From bfbb596977ca122359b2dd4b6593b3abb301bb83 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Thu, 22 Feb 2024 21:52:54 +0530 Subject: [PATCH 01/15] Initial Setup of Markdown+Mermaid Signed-off-by: nikhilkalburgi --- package-lock.json | 279 ++++++++++++------------------- package.json | 28 +++- src/PreviewMarkdown.ts | 121 ++++++++++++++ src/components/Info.ts | 61 +++++++ src/components/MermaidDiagram.ts | 7 + src/extension.ts | 8 +- webpack.config.js | 4 + 7 files changed, 338 insertions(+), 170 deletions(-) create mode 100644 src/PreviewMarkdown.ts create mode 100644 src/components/Info.ts create mode 100644 src/components/MermaidDiagram.ts diff --git a/package-lock.json b/package-lock.json index 8e42811..14e6d59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,11 @@ "name": "asyncapi-preview", "version": "0.6.2", "license": "Apache-2.0", + "dependencies": { + "@asyncapi/parser": "^3.0.7", + "@types/markdown-it": "^13.0.7", + "markdown-it": "^14.0.0" + }, "devDependencies": { "@asyncapi/react-component": "^1.2.7", "@types/glob": "^7.2.0", @@ -58,12 +63,11 @@ } }, "node_modules/@asyncapi/parser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-3.0.1.tgz", - "integrity": "sha512-LtRVjbswpqW7TlSqnGVdFm1da3DV1sqQz07ZG6xqzpR2A2pkn16+5Fk+OhuAggZ0atXNLSYfYSuKp8t3iKvrKA==", - "dev": true, + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-3.0.7.tgz", + "integrity": "sha512-CKdkZbhs+2Mw7M2UZPypKEhKuaF+o5qZB2TQc0pDf+Wr09uEnm6WTdyqzmMGVb5fkQYApu8psQeDyVMbhfoWXQ==", "dependencies": { - "@asyncapi/specs": "^6.1.0", + "@asyncapi/specs": "^6.5.0", "@openapi-contrib/openapi-schema-to-json-schema": "~3.2.0", "@stoplight/json": "^3.20.2", "@stoplight/json-ref-readers": "^1.2.2", @@ -117,10 +121,9 @@ } }, "node_modules/@asyncapi/specs": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.2.0.tgz", - "integrity": "sha512-5uf/Rg6pavZHx7rVIkP0TP/icIahJCuHgmY1rdtkrWxHZMXbASDDV3DlTUaonbsUeemwchoqljmrTd1O1xqvxg==", - "dev": true, + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.5.0.tgz", + "integrity": "sha512-84QUcfMT05+vvHO5EnSI0I5OZKzMgF/i3vgw92ghk1l52VM/lb3qNnuARzyo+uHJ9kmIb5+naK9wTuliVOdzmg==", "dependencies": { "@types/json-schema": "^7.0.11" } @@ -274,7 +277,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.3.tgz", "integrity": "sha512-XfZgry4DwEZvSFtS/6Y+R48D7qJYJK6R9/yJFyUFHCIUMEEHuJ4X95TDgJp5QkmzfLYvapMPzskV5HpIDrREug==", - "dev": true, "engines": { "node": ">= 10.16.0" }, @@ -286,7 +288,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@jsep-plugin/ternary/-/ternary-1.1.3.tgz", "integrity": "sha512-qtLGzCNzPVJ3kdH6/zoLWDPjauHIKiLSBAR71Wa0+PWvGA8wODUQvRgxtpUA5YqAYL3CQ8S4qXhd/9WuWTZirg==", - "dev": true, "engines": { "node": ">= 10.16.0" }, @@ -339,7 +340,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@openapi-contrib/openapi-schema-to-json-schema/-/openapi-schema-to-json-schema-3.2.0.tgz", "integrity": "sha512-Gj6C0JwCr8arj0sYuslWXUBSP/KnUlEGnPW4qxlXvAl543oaNQgMgIgkQUA6vs5BCCvwTEiL8m/wdWzfl4UvSw==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3" } @@ -348,7 +348,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@stoplight/better-ajv-errors/-/better-ajv-errors-1.0.3.tgz", "integrity": "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==", - "dev": true, "dependencies": { "jsonpointer": "^5.0.0", "leven": "^3.1.0" @@ -364,7 +363,6 @@ "version": "3.21.0", "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.21.0.tgz", "integrity": "sha512-5O0apqJ/t4sIevXCO3SBN9AHCEKKR/Zb4gaj7wYe5863jme9g02Q0n/GhM7ZCALkL+vGPTe4ZzTETP8TFtsw3g==", - "dev": true, "dependencies": { "@stoplight/ordered-object-literal": "^1.0.3", "@stoplight/path": "^1.3.2", @@ -381,7 +379,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/@stoplight/json-ref-readers/-/json-ref-readers-1.2.2.tgz", "integrity": "sha512-nty0tHUq2f1IKuFYsLM4CXLZGHdMn+X/IwEUIpeSOXt0QjMUbL0Em57iJUDzz+2MkWG83smIigNZ3fauGjqgdQ==", - "dev": true, "dependencies": { "node-fetch": "^2.6.0", "tslib": "^1.14.1" @@ -394,7 +391,6 @@ "version": "3.1.6", "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.6.tgz", "integrity": "sha512-YNcWv3R3n3U6iQYBsFOiWSuRGE5su1tJSiX6pAPRVk7dP0L7lqCteXGzuVRQ0gMZqUl8v1P0+fAKxF6PLo9B5A==", - "dev": true, "dependencies": { "@stoplight/json": "^3.21.0", "@stoplight/path": "^1.3.2", @@ -414,14 +410,12 @@ "node_modules/@stoplight/json-ref-resolver/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@stoplight/ordered-object-literal": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.5.tgz", "integrity": "sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg==", - "dev": true, "engines": { "node": ">=8" } @@ -430,7 +424,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/@stoplight/path/-/path-1.3.2.tgz", "integrity": "sha512-lyIc6JUlUA8Ve5ELywPC8I2Sdnh1zc1zmbYgVarhXIp9YeAB0ReeqmGEOWNtlHkbP2DAA1AL65Wfn2ncjK/jtQ==", - "dev": true, "engines": { "node": ">=8" } @@ -439,7 +432,6 @@ "version": "1.18.3", "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.18.3.tgz", "integrity": "sha512-YY8x7X2SWJIhGTLPol+eFiQpWPz0D0mJdkK2i4A0QJG68KkNhypP6+JBC7/Kz3XWjqr0L/RqAd+N5cQLPOKZGQ==", - "dev": true, "dependencies": { "@stoplight/better-ajv-errors": "1.0.3", "@stoplight/json": "~3.21.0", @@ -471,7 +463,6 @@ "version": "13.6.0", "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.6.0.tgz", "integrity": "sha512-dzyuzvUjv3m1wmhPfq82lCVYGcXG0xUYgqnWfCq3PCVR4BKFhjdkHrnJ+jIDoMKvXb05AZP/ObQF6+NpDo29IQ==", - "dev": true, "dependencies": { "@types/json-schema": "^7.0.4", "utility-types": "^3.10.0" @@ -484,7 +475,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-7.1.0.tgz", "integrity": "sha512-gTaNRsPWO/K2KY6MrqaUFClF9kmuM6MFH5Dhg1VYDODgFbByw1yb7xu3hrViE/sz+dGOeMWgCzwUwQtAnCTE9g==", - "dev": true, "engines": { "node": ">=12.0.0" } @@ -492,14 +482,12 @@ "node_modules/@stoplight/spectral-core/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@stoplight/spectral-formats": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@stoplight/spectral-formats/-/spectral-formats-1.6.0.tgz", "integrity": "sha512-X27qhUfNluiduH0u/QwJqhOd8Wk5YKdxVmKM03Aijlx0AH1H5mYt3l9r7t2L4iyJrsBaFPnMGt7UYJDGxszbNA==", - "dev": true, "dependencies": { "@stoplight/json": "^3.17.0", "@stoplight/spectral-core": "^1.8.0", @@ -513,14 +501,12 @@ "node_modules/@stoplight/spectral-formats/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@stoplight/spectral-functions": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.7.2.tgz", "integrity": "sha512-f+61/FtIkQeIo+a269CeaeqjpyRsgDyIk6DGr7iS4hyuk1PPk7Uf6MNRDs9FEIBh7CpdEJ+HSHbMLwgpymWTIw==", - "dev": true, "dependencies": { "@stoplight/better-ajv-errors": "1.0.3", "@stoplight/json": "^3.17.1", @@ -541,14 +527,12 @@ "node_modules/@stoplight/spectral-functions/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@stoplight/spectral-parsers": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.3.tgz", "integrity": "sha512-J0KW5Rh5cHWnJQ3yN+cr/ijNFVirPSR0pkQbdrNX30VboEl083UEDrQ3yov9kjLVIWEk9t9kKE7Eo3QT/k4JLA==", - "dev": true, "dependencies": { "@stoplight/json": "~3.21.0", "@stoplight/types": "^13.6.0", @@ -562,14 +546,12 @@ "node_modules/@stoplight/spectral-parsers/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@stoplight/spectral-ref-resolver": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.4.tgz", "integrity": "sha512-5baQIYL0NJTSVy8v6RxOR4U51xOUYM8wJri1YvlAT6bPN8m0EIxMwfVYi0xUZEMVeHcWx869nIkoqyWmOutF2A==", - "dev": true, "dependencies": { "@stoplight/json-ref-readers": "1.2.2", "@stoplight/json-ref-resolver": "~3.1.6", @@ -584,14 +566,12 @@ "node_modules/@stoplight/spectral-ref-resolver/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@stoplight/spectral-runtime": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@stoplight/spectral-runtime/-/spectral-runtime-1.1.2.tgz", "integrity": "sha512-fr5zRceXI+hrl82yAVoME+4GvJie8v3wmOe9tU+ZLRRNonizthy8qDi0Z/z4olE+vGreSDcuDOZ7JjRxFW5kTw==", - "dev": true, "dependencies": { "@stoplight/json": "^3.17.0", "@stoplight/path": "^1.3.2", @@ -609,7 +589,6 @@ "version": "12.5.0", "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-12.5.0.tgz", "integrity": "sha512-dwqYcDrGmEyUv5TWrDam5TGOxU72ufyQ7hnOIIDdmW5ezOwZaBFoR5XQ9AsH49w7wgvOqB2Bmo799pJPWnpCbg==", - "dev": true, "dependencies": { "@types/json-schema": "^7.0.4", "utility-types": "^3.10.0" @@ -621,14 +600,12 @@ "node_modules/@stoplight/spectral-runtime/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@stoplight/types": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.20.0.tgz", "integrity": "sha512-2FNTv05If7ib79VPDA/r9eUet76jewXFH2y2K5vuge6SXbRHtWBhcaRmu+6QpF4/WRNoJj5XYRSwLGXDxysBGA==", - "dev": true, "dependencies": { "@types/json-schema": "^7.0.4", "utility-types": "^3.10.0" @@ -641,7 +618,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.2.3.tgz", "integrity": "sha512-Mx01wjRAR9C7yLMUyYFTfbUf5DimEpHMkRDQ1PKLe9dfNILbgdxyrncsOXM3vCpsQ1Hfj4bPiGl+u4u6e9Akqw==", - "dev": true, "dependencies": { "@stoplight/ordered-object-literal": "^1.0.1", "@stoplight/types": "^13.0.0", @@ -655,14 +631,12 @@ "node_modules/@stoplight/yaml-ast-parser": { "version": "0.0.48", "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.48.tgz", - "integrity": "sha512-sV+51I7WYnLJnKPn2EMWgS4EUfoP4iWEbrWwbXsj0MZCB/xOK8j6+C9fntIdOM50kpx45ZLC3s6kwKivWuqvyg==", - "dev": true + "integrity": "sha512-sV+51I7WYnLJnKPn2EMWgS4EUfoP4iWEbrWwbXsj0MZCB/xOK8j6+C9fntIdOM50kpx45ZLC3s6kwKivWuqvyg==" }, "node_modules/@stoplight/yaml/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/@types/dompurify": { "version": "2.3.4", @@ -677,7 +651,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/es-aggregate-error/-/es-aggregate-error-1.0.6.tgz", "integrity": "sha512-qJ7LIFp06h1QE1aVxbVd+zJP2wdaugYXYfd6JxsyRMrYHaxb6itXPogW2tz+ylUJ1n1b+JF1PHyYCfYHm0dvUg==", - "dev": true, "dependencies": { "@types/node": "*" } @@ -727,8 +700,26 @@ "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "node_modules/@types/linkify-it": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==" + }, + "node_modules/@types/markdown-it": { + "version": "13.0.7", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.7.tgz", + "integrity": "sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==", + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==" }, "node_modules/@types/minimatch": { "version": "5.1.2", @@ -745,8 +736,7 @@ "node_modules/@types/node": { "version": "14.18.32", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.32.tgz", - "integrity": "sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow==", - "dev": true + "integrity": "sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow==" }, "node_modules/@types/protocol-buffers-schema": { "version": "3.4.3", @@ -766,8 +756,7 @@ "node_modules/@types/urijs": { "version": "1.19.25", "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", - "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==", - "dev": true + "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==" }, "node_modules/@types/vscode": { "version": "1.72.0", @@ -1208,7 +1197,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -1293,7 +1281,6 @@ "version": "8.11.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -1309,7 +1296,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "dev": true, "peerDependencies": { "ajv": "^8.5.0" }, @@ -1323,7 +1309,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", - "dev": true, "peerDependencies": { "ajv": "^8.0.1" } @@ -1332,7 +1317,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, "dependencies": { "ajv": "^8.0.0" }, @@ -1406,14 +1390,12 @@ "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 + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -1435,7 +1417,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", @@ -1456,7 +1437,6 @@ "version": "1.8.6", "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", - "dev": true, "bin": { "astring": "bin/astring" } @@ -1471,7 +1451,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -1483,7 +1462,6 @@ "version": "5.7.7", "resolved": "https://registry.npmjs.org/avsc/-/avsc-5.7.7.tgz", "integrity": "sha512-9cYNccliXZDByFsFliVwk5GvTq058Fj513CiR4E60ndDwmuXzTJEp/Bp8FyuRmGyYupLjHLs+JA9/CBoVS4/NQ==", - "dev": true, "engines": { "node": ">=0.11" } @@ -1491,8 +1469,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/big-integer": { "version": "1.6.51", @@ -1535,7 +1512,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1621,7 +1597,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2", "get-intrinsic": "^1.2.1", @@ -1823,8 +1798,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/copy-webpack-plugin": { "version": "10.2.4", @@ -1985,7 +1959,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.1", "gopd": "^1.0.1", @@ -1999,7 +1972,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -2025,7 +1997,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "dev": true, "engines": { "node": ">= 0.6.0" } @@ -2124,6 +2095,17 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", @@ -2140,7 +2122,6 @@ "version": "1.22.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "arraybuffer.prototype.slice": "^1.0.2", @@ -2193,7 +2174,6 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.11.tgz", "integrity": "sha512-DCiZiNlMlbvofET/cE55My387NiLvuGToBEZDdK9U2G3svDCjL8WOgO5Il6lO83nQ8qmag/R9nArdpaFQ/m3lA==", - "dev": true, "dependencies": { "define-data-property": "^1.1.0", "define-properties": "^1.2.1", @@ -2221,7 +2201,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.2", "has-tostringtag": "^1.0.0", @@ -2235,7 +2214,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -2593,7 +2571,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, "engines": { "node": ">=6" } @@ -2610,8 +2587,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { "version": "3.2.12", @@ -2656,8 +2632,7 @@ "node_modules/fast-memoize": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", - "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", - "dev": true + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", @@ -2749,7 +2724,6 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, "dependencies": { "is-callable": "^1.1.3" } @@ -2845,7 +2819,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2854,7 +2827,6 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -2872,7 +2844,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2896,7 +2867,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, "dependencies": { "function-bind": "^1.1.2", "has-proto": "^1.0.1", @@ -2911,7 +2881,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -3000,7 +2969,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, "dependencies": { "define-properties": "^1.1.3" }, @@ -3035,7 +3003,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -3080,7 +3047,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3098,7 +3064,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.2" }, @@ -3110,7 +3075,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3122,7 +3086,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3134,7 +3097,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -3149,7 +3111,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -3225,7 +3186,6 @@ "version": "9.0.21", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", - "dev": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -3295,7 +3255,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.2", "hasown": "^2.0.0", @@ -3318,7 +3277,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.0", @@ -3332,7 +3290,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -3356,7 +3313,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -3372,7 +3328,6 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3396,7 +3351,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -3441,7 +3395,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3462,7 +3415,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -3483,7 +3435,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -3499,7 +3450,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -3511,7 +3461,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -3526,7 +3475,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -3541,7 +3489,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, "dependencies": { "which-typed-array": "^1.1.11" }, @@ -3568,7 +3515,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -3654,7 +3600,6 @@ "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" }, @@ -3735,7 +3680,6 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.8.tgz", "integrity": "sha512-qofGylTGgYj9gZFsHuyWAN4jr35eJ66qJCK4eKDnldohuUoQFbU3iZn2zjvEbd9wOAhP9Wx5DsAAduTyE1PSWQ==", - "dev": true, "engines": { "node": ">= 10.16.0" } @@ -3758,8 +3702,7 @@ "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -3770,14 +3713,12 @@ "node_modules/jsonc-parser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.2.1.tgz", - "integrity": "sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==", - "dev": true + "integrity": "sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==" }, "node_modules/jsonpath-plus": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-7.2.0.tgz", "integrity": "sha512-zBfiUPM5nD0YZSBT/o/fbCUlCcepMIdP0CJZxM1+KgA4f2T206f6VAg9e7mX35+KlMaIc5qXW34f3BnwJ3w+RA==", - "dev": true, "engines": { "node": ">=12.0.0" } @@ -3786,7 +3727,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3804,7 +3744,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, "engines": { "node": ">=6" } @@ -3822,6 +3761,14 @@ "node": ">= 0.8.0" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -3855,8 +3802,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -3867,8 +3813,7 @@ "node_modules/lodash.topath": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", - "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==", - "dev": true + "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==" }, "node_modules/log-symbols": { "version": "4.1.0", @@ -3911,6 +3856,22 @@ "node": ">=10" } }, + "node_modules/markdown-it": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.0.0.tgz", + "integrity": "sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.0.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/marked": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", @@ -3923,6 +3884,11 @@ "node": ">= 12" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3976,7 +3942,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4179,7 +4144,6 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/nimma/-/nimma-0.2.2.tgz", "integrity": "sha512-V52MLl7BU+tH2Np9tDrIXK8bql3MVUadnMIl/0/oZSGC9keuro0O9UUv9QKp0aMvtN8HRew4G7byY7H4eWsxaQ==", - "dev": true, "dependencies": { "@jsep-plugin/regex": "^1.0.1", "@jsep-plugin/ternary": "^1.0.2", @@ -4198,7 +4162,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz", "integrity": "sha512-EvGovdvau6FyLexFH2OeXfIITlgIbgZoAZe3usiySeaIDm5QS+A10DKNpaPBBqqRSZr2HN6HVNXxtwUAr2apEw==", - "dev": true, "optional": true, "engines": { "node": ">=10.0.0" @@ -4208,7 +4171,6 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -4227,20 +4189,17 @@ "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -4271,7 +4230,6 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4280,7 +4238,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -4289,7 +4246,6 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -4524,7 +4480,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-1.1.1.tgz", "integrity": "sha512-PxkIc/2ZpLiEzQXu5YRDOUgBlfGYBY8156HY5ZcRAwwonMk5W/MrJP2LLkG/hF7GEQzaHo2aS7ho6ZLCOvf+6g==", - "dev": true, "engines": { "node": ">=12.0.0" } @@ -4560,7 +4515,14 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "engines": { "node": ">=6" } @@ -4670,7 +4632,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -4708,7 +4669,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4838,7 +4798,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1", @@ -4855,8 +4814,7 @@ "node_modules/safe-array-concat/node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, "node_modules/safe-buffer": { "version": "5.1.2", @@ -4868,7 +4826,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -4881,8 +4838,7 @@ "node_modules/safe-stable-stringify": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", - "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==", - "dev": true + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -4959,7 +4915,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, "dependencies": { "define-data-property": "^1.1.1", "get-intrinsic": "^1.2.1", @@ -4974,7 +4929,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, "dependencies": { "define-data-property": "^1.0.1", "functions-have-names": "^1.2.3", @@ -5027,7 +4981,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -5041,7 +4994,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/simple-eval/-/simple-eval-1.0.0.tgz", "integrity": "sha512-kpKJR+bqTscgC0xuAl2xHN6bB12lHjC2DCUfqjAx19bQyO3R2EVLOurm3H9AUltv/uFVcSCVNc6faegR+8NYLw==", - "dev": true, "dependencies": { "jsep": "^1.1.2" }, @@ -5104,7 +5056,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5121,7 +5072,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5135,7 +5085,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5385,8 +5334,7 @@ "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -5431,7 +5379,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1", @@ -5445,7 +5392,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "for-each": "^0.3.3", @@ -5463,7 +5409,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -5482,7 +5427,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "for-each": "^0.3.3", @@ -5505,11 +5449,15 @@ "node": ">=4.2.0" } }, + "node_modules/uc.micro": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.0.0.tgz", + "integrity": "sha512-DffL94LsNOccVn4hyfRe5rdKa273swqeA5DJpMOeFmEn1wCDc7nAbbB0gXlgBCL7TNzeTv6G7XVWzan7iJtfig==" + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -5568,7 +5516,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -5576,8 +5523,7 @@ "node_modules/urijs": { "version": "1.19.11", "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", - "dev": true + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" }, "node_modules/url-parse": { "version": "1.5.10", @@ -5612,7 +5558,6 @@ "version": "3.10.0", "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", - "dev": true, "engines": { "node": ">= 4" } @@ -5883,7 +5828,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -5899,7 +5843,6 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.4", diff --git a/package.json b/package.json index 59f9b57..722d016 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "onLanguage:yml", "onLanguage:yaml", "onLanguage:json", - "onCommand:asyncapi.preview" + "onCommand:asyncapi.preview", + "onCommand:asyncapi.markdown" ], "main": "./dist/extension.js", "contributes": { @@ -49,6 +50,14 @@ { "command": "asyncapi.paste", "title": "AsyncAPI: Paste as Schema" + }, + { + "command": "asyncapi.markdown", + "title": "Preview Asyncapi Markdown", + "icon": { + "light": "resources/icons/open-preview_black.svg", + "dark": "resources/icons/open-preview_white.svg" + } } ], "snippets": [ @@ -67,11 +76,23 @@ { "when": "(resourceLangId == json || resourceLangId == yaml) && asyncapi.isAsyncAPI", "command": "asyncapi.preview" + }, + { + "when": "(resourceLangId == json || resourceLangId == yaml) && asyncapi.isAsyncAPI", + "command": "asyncapi.markdown", + "group": "navigation" + }, + { + "when": "(resourceLangId == json || resourceLangId == yaml) && asyncapi.isAsyncAPI", + "command": "asyncapi.markdown" } ], "commandPalette": [ { "command": "asyncapi.preview" + }, + { + "command": "asyncapi.markdown" } ], "editor/context": [ @@ -122,5 +143,10 @@ "typescript": "^4.6.4", "webpack": "^5.70.0", "webpack-cli": "^4.9.2" + }, + "dependencies": { + "@asyncapi/parser": "^3.0.7", + "@types/markdown-it": "^13.0.7", + "markdown-it": "^14.0.0" } } diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts new file mode 100644 index 0000000..0d002f7 --- /dev/null +++ b/src/PreviewMarkdown.ts @@ -0,0 +1,121 @@ +import * as vscode from 'vscode'; +import * as path from 'path'; +import { isAsyncAPIFile } from './PreviewWebPanel'; +import * as Markdownit from 'markdown-it'; +import { Parser, fromFile, AsyncAPIDocumentInterface } from '@asyncapi/parser'; +import Info from './components/Info'; +import MermaidDiagram from './components/MermaidDiagram'; + +const md = Markdownit('commonmark'); +const parser = new Parser(); + +function buildMarkdown(document:AsyncAPIDocumentInterface | undefined){ + + let content = ''; + + if(document !== undefined){ + + content = ` + ${Info(document)} + ${MermaidDiagram(document)} + `; + } + + return md.render(content); +} + +export function previewMarkdown(context: vscode.ExtensionContext) { + return async (uri: vscode.Uri) => { + uri = uri || (await promptForAsyncapiFile()) as vscode.Uri; + if (uri) { + console.log('Opening asyncapi markdown', uri.fsPath); + openAsyncAPIMarkdown(context, uri); + } + }; + } + +export const openAsyncapiMdFiles: { [id: string]: vscode.WebviewPanel } = {}; // vscode.Uri.fsPath => vscode.WebviewPanel + + +export async function openAsyncAPIMarkdown(context: vscode.ExtensionContext, uri: vscode.Uri) { + const localResourceRoots = [ + vscode.Uri.file(path.dirname(uri.fsPath)), + vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/mermaid/dist/mermaid.min.js') + ]; + if (vscode.workspace.workspaceFolders) { + vscode.workspace.workspaceFolders.forEach(folder => { + localResourceRoots.push(folder.uri); + }); + } + const panel: vscode.WebviewPanel = + openAsyncapiMdFiles[uri.fsPath] || + vscode.window.createWebviewPanel('markdown-preview', '', vscode.ViewColumn.Two, { + enableScripts: true, + retainContextWhenHidden: true, + localResourceRoots, + }); + + const { document } = await fromFile(parser, uri.fsPath).parse(); + let result = buildMarkdown(document); + + panel.title = path.basename(uri.fsPath); + panel.webview.html = getWebviewContent(context, panel.webview, uri, result); + + panel.onDidDispose(() => { + delete openAsyncapiMdFiles[uri.fsPath]; + }); + openAsyncapiMdFiles[uri.fsPath] = panel; +} + +async function promptForAsyncapiFile() { + if (isAsyncAPIFile(vscode.window.activeTextEditor?.document)) { + return vscode.window.activeTextEditor?.document.uri; + } + const uris = await vscode.window.showOpenDialog({ + canSelectFiles: true, + canSelectFolders: false, + canSelectMany: false, + openLabel: 'Open AsyncAPI file', + filters: { + asyncAPI: ['yml', 'yaml', 'json'], + }, + }); + return uris?.[0]; +} + +function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Webview, asyncapiFile: vscode.Uri, result:any) { + const mermaidJs = webview.asWebviewUri( + vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/mermaid/dist/mermaid.min.js') + ); + + const html = ` + + + + + + + + ${result} + + + + + + `; + return html; +} diff --git a/src/components/Info.ts b/src/components/Info.ts new file mode 100644 index 0000000..87a6c72 --- /dev/null +++ b/src/components/Info.ts @@ -0,0 +1,61 @@ +import {AsyncAPIDocumentInterface } from '@asyncapi/parser'; + +export default function info(asyncapi:AsyncAPIDocumentInterface) { + + const info = asyncapi.info(); + const defaultContentType = asyncapi.defaultContentType(); + const specId = info.id(); + const termsOfService = info.termsOfService(); + const license = info.license(); + const contact = info.contact(); + const externalDocs = info.externalDocs(); + const extensions: any = info.extensions(); + + const infoList = []; + if (specId) { + infoList.push(`Specification ID: \`${specId}\``); + } + if (license) { + infoList.push(license.url() ? ( + `License: [${license.name()}](${license.url()})` + ) : `License: ${license.name()}`); + } + if (termsOfService) { + infoList.push( + `[${termsOfService}](${termsOfService})` + ); + } + if (defaultContentType) { + infoList.push( + `Default content type: [${defaultContentType}](https://www.iana.org/assignments/media-types/${defaultContentType})` + ); + } + if (contact) { + if (contact.url()) { + infoList.push( + `Support: [${contact.url()}](${contact.name() || 'Link'})` + ); + } + if (contact.email()) { + infoList.push( + `Email support: [${`mailto:${contact.email()}`}](${contact.email()})` + ); + } + } + + return ( + ` +# ${info.title()} ${info.version()} documentation + +${ + infoList.map((value)=>{ + return '\n* '+ value; + }) +} + +![${info.title()}](${(extensions.get('x-logo'))?extensions.get('x-logo').value():null}) + + +#### ${info.description()} + `); +} \ No newline at end of file diff --git a/src/components/MermaidDiagram.ts b/src/components/MermaidDiagram.ts new file mode 100644 index 0000000..179d866 --- /dev/null +++ b/src/components/MermaidDiagram.ts @@ -0,0 +1,7 @@ +import {AsyncAPIDocumentInterface } from '@asyncapi/parser'; + +export default function mermaidDiagram(asyncapi:AsyncAPIDocumentInterface){ + + + return ``; +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 55cfbfb..92bf9b6 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; -import { isAsyncAPIFile, openAsyncAPI, openAsyncapiFiles, previewAsyncAPI } from './PreviewWebPanel'; +import { isAsyncAPIFile, openAsyncAPI, openAsyncapiFiles, previewAsyncAPI} from './PreviewWebPanel'; +import { openAsyncAPIMarkdown, openAsyncapiMdFiles, previewMarkdown} from './PreviewMarkdown'; import { asyncapiSmartPaste } from './SmartPasteCommand'; @@ -28,6 +29,9 @@ export function activate(context: vscode.ExtensionContext) { console.log('Reloading asyncapi file', document.uri.fsPath); openAsyncAPI(context, document.uri); } + if(openAsyncapiMdFiles[document.uri.fsPath]){ + openAsyncAPIMarkdown(context, document.uri); + } if (vscode.window.activeTextEditor?.document) { setAsyncAPIPreviewContext(vscode.window.activeTextEditor.document); } @@ -37,6 +41,8 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.commands.registerCommand('asyncapi.preview', previewAsyncAPI(context))); context.subscriptions.push(vscode.commands.registerCommand("asyncapi.paste", asyncapiSmartPaste)); + + context.subscriptions.push(vscode.commands.registerCommand("asyncapi.markdown", previewMarkdown(context))); } export function deactivate() {} diff --git a/webpack.config.js b/webpack.config.js index 664fc7a..6f182cc 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -56,6 +56,10 @@ const extensionConfig = { from: 'node_modules/@asyncapi/react-component/styles/default.min.css', to: 'node_modules/@asyncapi/react-component/styles/default.min.css', }, + { + from: '/node_modules/mermaid/dist/mermaid.min.js', + to: '/node_modules/mermaid/dist/mermaid.min.js', + }, ], }), ], From be4795e85fc6ebb9c46836ba2389a3ede9eaf441 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Thu, 29 Feb 2024 20:42:37 +0530 Subject: [PATCH 02/15] integrate ejs and partially develop markdown Signed-off-by: nikhilkalburgi --- package-lock.json | 1278 +++++++++++++++++++++++++++++- package.json | 5 +- src/Asyncapi.ts | 143 ++++ src/PreviewMarkdown.ts | 18 +- src/components/Asyncapi.ejs | 2 + src/components/Bindings.ejs | 5 + src/components/Extensions.ejs | 5 + src/components/Info.ejs | 55 ++ src/components/Info.ts | 61 -- src/components/MermaidDiagram.ts | 7 - src/components/Message.ejs | 0 src/components/Operations.ejs | 0 src/components/Schema.ejs | 0 src/components/Security.ejs | 0 src/components/Servers.ejs | 55 ++ src/components/Tags.ejs | 27 + src/components/classDiagram.ejs | 0 src/components/flowchart.ejs | 0 webpack.config.js | 16 +- 19 files changed, 1578 insertions(+), 99 deletions(-) create mode 100644 src/Asyncapi.ts create mode 100644 src/components/Asyncapi.ejs create mode 100644 src/components/Bindings.ejs create mode 100644 src/components/Extensions.ejs create mode 100644 src/components/Info.ejs delete mode 100644 src/components/Info.ts delete mode 100644 src/components/MermaidDiagram.ts create mode 100644 src/components/Message.ejs create mode 100644 src/components/Operations.ejs create mode 100644 src/components/Schema.ejs create mode 100644 src/components/Security.ejs create mode 100644 src/components/Servers.ejs create mode 100644 src/components/Tags.ejs create mode 100644 src/components/classDiagram.ejs create mode 100644 src/components/flowchart.ejs diff --git a/package-lock.json b/package-lock.json index 14e6d59..8f54d12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,10 +11,14 @@ "dependencies": { "@asyncapi/parser": "^3.0.7", "@types/markdown-it": "^13.0.7", - "markdown-it": "^14.0.0" + "ejs": "^3.1.9", + "eta": "^3.2.0", + "markdown-it": "^14.0.0", + "mermaid": "^10.8.0" }, "devDependencies": { "@asyncapi/react-component": "^1.2.7", + "@types/ejs": "^3.1.5", "@types/glob": "^7.2.0", "@types/js-yaml": "^4.0.5", "@types/mocha": "^9.1.1", @@ -128,6 +132,11 @@ "@types/json-schema": "^7.0.11" } }, + "node_modules/@braintree/sanitize-url": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", + "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==" + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -638,6 +647,32 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz", + "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==" + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/dompurify": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.3.4.tgz", @@ -647,6 +682,12 @@ "@types/trusted-types": "*" } }, + "node_modules/@types/ejs": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz", + "integrity": "sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==", + "dev": true + }, "node_modules/@types/es-aggregate-error": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/es-aggregate-error/-/es-aggregate-error-1.0.6.tgz", @@ -716,6 +757,14 @@ "@types/mdurl": "*" } }, + "node_modules/@types/mdast": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "dependencies": { + "@types/unist": "^2" + } + }, "node_modules/@types/mdurl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", @@ -733,6 +782,11 @@ "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", "dev": true }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, "node_modules/@types/node": { "version": "14.18.32", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.32.tgz", @@ -753,6 +807,11 @@ "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", "dev": true }, + "node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + }, "node_modules/@types/urijs": { "version": "1.19.25", "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", @@ -1363,7 +1422,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1441,6 +1499,11 @@ "astring": "bin/astring" } }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1656,7 +1719,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1668,6 +1730,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1757,7 +1828,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1768,8 +1838,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/colorette": { "version": "2.0.19", @@ -1874,6 +1943,14 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1912,6 +1989,462 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, + "node_modules/cytoscape": { + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.28.1.tgz", + "integrity": "sha512-xyItz4O/4zp9/239wCcH8ZcFuuZooEeF8KHRmzjDfGdXsj3OG9MFSMA0pJE0uX3uCN/ygof6hHf4L7lst+JaDg==", + "dependencies": { + "heap": "^0.2.6", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz", + "integrity": "sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==", + "dependencies": { + "d3": "^7.8.2", + "lodash-es": "^4.17.21" + } + }, "node_modules/data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -1926,11 +2459,15 @@ "node": ">=10" } }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1949,6 +2486,18 @@ "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==", "dev": true }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1984,6 +2533,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2001,11 +2558,18 @@ "node": ">= 0.6.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, "engines": { "node": ">=0.3.1" } @@ -2070,12 +2634,31 @@ "readable-stream": "^2.0.2" } }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.283", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.283.tgz", "integrity": "sha512-g6RQ9zCOV+U5QVHW9OpFR7rdk/V7xfopNXnyAamdpFgCHgZ1sjI8VuR1+zG2YG/TZk+tQ8mpNkug4P8FU0fuOA==", "dev": true }, + "node_modules/elkjs": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.2.tgz", + "integrity": "sha512-2Y/RaA1pdgSHpY0YG4TYuYCD2wh97CRvu22eLG3Kz0pgQ/6KbIFTxsTnDc4MH/6hFlg2L/9qXrDMG0nMjP63iw==" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2567,6 +3150,17 @@ "node": ">=0.10.0" } }, + "node_modules/eta": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-3.2.0.tgz", + "integrity": "sha512-Qzc3it7nLn49dbOb9+oHV9rwtt9qN8oShRztqkZ3gXPqQflF0VLin5qhWk0g/2ioibBwT4DU6OIMVft7tg/rVg==", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -2664,6 +3258,33 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3055,7 +3676,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -3127,6 +3747,11 @@ "he": "bin/he" } }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==" + }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -3264,6 +3889,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -3554,6 +4187,23 @@ "jsdom": "^16.5.2" } }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -3731,6 +4381,11 @@ "node": ">=0.10.0" } }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -3740,6 +4395,19 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -3804,6 +4472,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -3884,6 +4557,41 @@ "node": ">= 12" } }, + "node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "dependencies": { + "@types/mdast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", @@ -3904,6 +4612,458 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.8.0.tgz", + "integrity": "sha512-9CzfSreRjdDJxX796+jW4zjEq0DVw5xVF0nWsqff8OTbrt+ml0TZ5PyYUjjUZJa2NYxYJZZXewEquxGiM8qZEA==", + "dependencies": { + "@braintree/sanitize-url": "^6.0.1", + "@types/d3-scale": "^4.0.3", + "@types/d3-scale-chromatic": "^3.0.0", + "cytoscape": "^3.28.1", + "cytoscape-cose-bilkent": "^4.1.0", + "d3": "^7.4.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.10", + "dayjs": "^1.11.7", + "dompurify": "^3.0.5", + "elkjs": "^0.9.0", + "khroma": "^2.0.0", + "lodash-es": "^4.17.21", + "mdast-util-from-markdown": "^1.3.0", + "non-layered-tidy-tree-layout": "^2.0.2", + "stylis": "^4.1.3", + "ts-dedent": "^2.2.0", + "uuid": "^9.0.0", + "web-worker": "^1.2.0" + } + }, + "node_modules/mermaid/node_modules/dompurify": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.9.tgz", + "integrity": "sha512-uyb4NDIvQ3hRn6NiC+SIFaP4mJ/MdXlvtunaqK9Bn6dD3RuB/1S/gasEjDHD8eiaqdSael2vBv+hOs7Y+jhYOQ==" + }, + "node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", + "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", + "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -4110,11 +5270,18 @@ "node": ">=10" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "engines": { + "node": ">=4" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { "version": "3.3.1", @@ -4211,6 +5378,11 @@ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, + "node_modules/non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4771,6 +5943,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4794,6 +5971,22 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safe-array-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", @@ -4843,8 +6036,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/saxes": { "version": "5.0.1", @@ -5118,11 +6310,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -5312,6 +6508,14 @@ "node": ">=8" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "engines": { + "node": ">=6.10" + } + }, "node_modules/ts-loader": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", @@ -5468,6 +6672,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unzipper": { "version": "0.10.11", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", @@ -5562,6 +6778,35 @@ "node": ">= 4" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -5597,6 +6842,11 @@ "node": ">=10.13.0" } }, + "node_modules/web-worker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.3.0.tgz", + "integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==" + }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", diff --git a/package.json b/package.json index 722d016..3c65ef1 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ }, "devDependencies": { "@asyncapi/react-component": "^1.2.7", + "@types/ejs": "^3.1.5", "@types/glob": "^7.2.0", "@types/js-yaml": "^4.0.5", "@types/mocha": "^9.1.1", @@ -146,7 +147,7 @@ }, "dependencies": { "@asyncapi/parser": "^3.0.7", - "@types/markdown-it": "^13.0.7", - "markdown-it": "^14.0.0" + "ejs": "^3.1.9", + "mermaid": "^10.8.0" } } diff --git a/src/Asyncapi.ts b/src/Asyncapi.ts new file mode 100644 index 0000000..ba39f72 --- /dev/null +++ b/src/Asyncapi.ts @@ -0,0 +1,143 @@ +import {AsyncAPIDocumentInterface, SchemaV2 as SchemaModel } from '@asyncapi/parser'; +import * as vscode from 'vscode'; +import * as ejs from 'ejs'; +import * as path from 'path'; +import * as Markdownit from 'markdown-it'; + +const md = Markdownit('commonmark'); + + +const extRenderType = 'x-schema-private-render-type'; +const extRenderAdditionalInfo = 'x-schema-private-render-additional-info'; +const extRawValue = 'x-schema-private-raw-value'; +const jsonSchemaTypes: string[] = [ + 'string', + 'number', + 'integer', + 'boolean', + 'array', + 'object', + 'null', +]; + +class SchemaHelper { + static jsonFieldToSchema(value: any): object { + if (value === undefined || value === null) { + return { + type: 'string', + const: value === undefined ? '' : 'NULL', + [extRawValue]: true, + [extRenderType]: false, + }; + } + if (typeof value !== 'object') { + const str = + typeof value.toString === 'function' ? value.toString() : value; + return { + type: 'string', + const: str, + [extRawValue]: true, + [extRenderType]: false, + }; + } + if (this.isJSONSchema(value)) { + return value; + } + if (Array.isArray(value)) { + return { + type: 'array', + items: value.map(v => this.jsonFieldToSchema(v)), + [extRenderType]: false, + [extRenderAdditionalInfo]: false, + }; + } + return { + type: 'object', + properties: Object.entries(value).reduce((obj:any, [k, v]) => { + obj[String(k)] = this.jsonFieldToSchema(v); + return obj; + }, {}), + [extRenderType]: false, + [extRenderAdditionalInfo]: false, + }; + } + + static jsonToSchema(value: any): SchemaModel { + if (value && typeof value.json === 'function') { + value = value.json(); + } + const json = this.jsonFieldToSchema(value) as object; + return new SchemaModel(json); + } + + private static isJSONSchema(value: any): boolean { + if ( + value && + typeof value === 'object' && + (jsonSchemaTypes.includes(value.type) || + (Array.isArray(value.type) && + value.type.some((t: string) => !jsonSchemaTypes.includes(t)))) + ) { + return true; + } + return false; + } + + static getCustomExtensions(item: any): Record { + try { + const extensions = item.extensions().all(); + return extensions.reduce((acc: { [x: string]: any; }, ext: { id: () => any; value: () => any; }) => { + const extName = ext.id(); + if ( + !extName.startsWith('x-parser-') && + !extName.startsWith('x-schema-private-') + ) { + acc[String(extName)] = ext.value(); + } + return acc; + }, {}); + } catch (err) { + return {}; + } + } +} + + + +export default async function info(asyncapi:AsyncAPIDocumentInterface, context: vscode.ExtensionContext) { + + + const info = asyncapi.info(); + const templatePath = path.join(context.extensionPath,'dist', 'components','Asyncapi.ejs'); + + return await ejs.renderFile(templatePath, { + info: { + title: info.title(), + version: info.version(), + defaultContentType: asyncapi.defaultContentType(), + specId: info.id(), + termsOfService: info.termsOfService(), + license: info.license(), + contact: info.contact(), + externalDocs: info.externalDocs(), + extensions: info.extensions(), + hasDescription: info.hasDescription(), + description: md.render(info.description() || ""), + tags: info.tags(), + + }, + servers:{ + servers: asyncapi.servers(), + schemaHelper: SchemaHelper + }, + path:{ + infoPath: path.join(context.extensionPath,'dist', 'components','Info.ejs'), + tagsPath: path.join(context.extensionPath,'dist', 'components','Tags.ejs'), + serversPath: path.join(context.extensionPath,'dist', 'components','Servers.ejs'), + securityPath: path.join(context.extensionPath,'dist', 'components','Security.ejs'), + bindingsPath: path.join(context.extensionPath,'dist', 'components','Bindings.ejs'), + extensionsPath: path.join(context.extensionPath,'dist', 'components','Extensions.ejs'), + schemaPath: path.join(context.extensionPath,'dist', 'components','Schema.ejs') + } + }); +} \ No newline at end of file diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts index 0d002f7..2e99628 100644 --- a/src/PreviewMarkdown.ts +++ b/src/PreviewMarkdown.ts @@ -1,27 +1,23 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { isAsyncAPIFile } from './PreviewWebPanel'; -import * as Markdownit from 'markdown-it'; import { Parser, fromFile, AsyncAPIDocumentInterface } from '@asyncapi/parser'; -import Info from './components/Info'; -import MermaidDiagram from './components/MermaidDiagram'; +import Asyncapi from './Asyncapi'; + -const md = Markdownit('commonmark'); const parser = new Parser(); -function buildMarkdown(document:AsyncAPIDocumentInterface | undefined){ + +async function buildMarkdown(document:AsyncAPIDocumentInterface | undefined, context: vscode.ExtensionContext){ let content = ''; if(document !== undefined){ - content = ` - ${Info(document)} - ${MermaidDiagram(document)} - `; + content = await Asyncapi(document, context); } - return md.render(content); + return content; } export function previewMarkdown(context: vscode.ExtensionContext) { @@ -56,7 +52,7 @@ export async function openAsyncAPIMarkdown(context: vscode.ExtensionContext, uri }); const { document } = await fromFile(parser, uri.fsPath).parse(); - let result = buildMarkdown(document); + let result = await buildMarkdown(document, context); panel.title = path.basename(uri.fsPath); panel.webview.html = getWebviewContent(context, panel.webview, uri, result); diff --git a/src/components/Asyncapi.ejs b/src/components/Asyncapi.ejs new file mode 100644 index 0000000..43f3214 --- /dev/null +++ b/src/components/Asyncapi.ejs @@ -0,0 +1,2 @@ +<%- include(path.infoPath,{...info,tagsPath: path.tagsPath}) %> +<%- include(path.serversPath,{...servers, ...path}) %> \ No newline at end of file diff --git a/src/components/Bindings.ejs b/src/components/Bindings.ejs new file mode 100644 index 0000000..12df28e --- /dev/null +++ b/src/components/Bindings.ejs @@ -0,0 +1,5 @@ +<% if (!bindings.isEmpty()) { %> + <% for(let binding of bindings.all()){ %> + <%- include(SchemaPath,{ schemaName:`${binding.protocol().charAt(0).toUpperCase() + binding.protocol().slice(1)} ${name}`, schema: schemaHelper.jsonToSchema(binding), key: binding.protocol() }) %> + <% } %> +<% } %> \ No newline at end of file diff --git a/src/components/Extensions.ejs b/src/components/Extensions.ejs new file mode 100644 index 0000000..41c29fe --- /dev/null +++ b/src/components/Extensions.ejs @@ -0,0 +1,5 @@ + + +<% if (Object.keys(schemaHelper.getCustomExtensions(extensions) || {}).length !== 0) { %> + <%- include(SchemaPath,{ schemaName:name, schema: schemaHelper.jsonToSchema(extensions) }) %> +<% } %> \ No newline at end of file diff --git a/src/components/Info.ejs b/src/components/Info.ejs new file mode 100644 index 0000000..a4d499c --- /dev/null +++ b/src/components/Info.ejs @@ -0,0 +1,55 @@ +

<%= title %> <%= version %> documentation

+<% if(extensions && extensions.has('x-logo')) { %> +  logo +<% } %> + + +<% if(externalDocs) { %> + <%= externalDocs.description() || 'Find more info here.' %> +<% } %> + +<% if(hasDescription) { %> + <%- description %> +<% } %> + +<%- include(tagsPath,{ name:"Specification Tags", tags }) %> \ No newline at end of file diff --git a/src/components/Info.ts b/src/components/Info.ts deleted file mode 100644 index 87a6c72..0000000 --- a/src/components/Info.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {AsyncAPIDocumentInterface } from '@asyncapi/parser'; - -export default function info(asyncapi:AsyncAPIDocumentInterface) { - - const info = asyncapi.info(); - const defaultContentType = asyncapi.defaultContentType(); - const specId = info.id(); - const termsOfService = info.termsOfService(); - const license = info.license(); - const contact = info.contact(); - const externalDocs = info.externalDocs(); - const extensions: any = info.extensions(); - - const infoList = []; - if (specId) { - infoList.push(`Specification ID: \`${specId}\``); - } - if (license) { - infoList.push(license.url() ? ( - `License: [${license.name()}](${license.url()})` - ) : `License: ${license.name()}`); - } - if (termsOfService) { - infoList.push( - `[${termsOfService}](${termsOfService})` - ); - } - if (defaultContentType) { - infoList.push( - `Default content type: [${defaultContentType}](https://www.iana.org/assignments/media-types/${defaultContentType})` - ); - } - if (contact) { - if (contact.url()) { - infoList.push( - `Support: [${contact.url()}](${contact.name() || 'Link'})` - ); - } - if (contact.email()) { - infoList.push( - `Email support: [${`mailto:${contact.email()}`}](${contact.email()})` - ); - } - } - - return ( - ` -# ${info.title()} ${info.version()} documentation - -${ - infoList.map((value)=>{ - return '\n* '+ value; - }) -} - -![${info.title()}](${(extensions.get('x-logo'))?extensions.get('x-logo').value():null}) - - -#### ${info.description()} - `); -} \ No newline at end of file diff --git a/src/components/MermaidDiagram.ts b/src/components/MermaidDiagram.ts deleted file mode 100644 index 179d866..0000000 --- a/src/components/MermaidDiagram.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {AsyncAPIDocumentInterface } from '@asyncapi/parser'; - -export default function mermaidDiagram(asyncapi:AsyncAPIDocumentInterface){ - - - return ``; -} \ No newline at end of file diff --git a/src/components/Message.ejs b/src/components/Message.ejs new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Operations.ejs b/src/components/Operations.ejs new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Schema.ejs b/src/components/Schema.ejs new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Security.ejs b/src/components/Security.ejs new file mode 100644 index 0000000..e69de29 diff --git a/src/components/Servers.ejs b/src/components/Servers.ejs new file mode 100644 index 0000000..01d9c87 --- /dev/null +++ b/src/components/Servers.ejs @@ -0,0 +1,55 @@ +<% if (!servers.isEmpty()) { %> +

Servers

+ <% for(let server of servers.all()){ %> +
+

<%= server.id().charAt(0).toUpperCase() + server.id().slice(1) %> Server

+

+

    +
  • URL: <%= server.url() %>
  • +
  • Protocol: <%= server.protocol() %> <%= server.protocolVersion() ? server.protocolVersion() : '' %>
  • +
+ <% if(server.hasDescription()) { %> +

+ Description: <%= server.description() %> +

+ <% } %> +

+

URL Variables

+ + + + + + + + + + + <% for(let entry of server.variables().all()){ %> + + + + <% if(entry.hasDefaultValue()){ %> + + <% }else { %> + + <% } %> + <% if(entry.hasAllowedValues()){ %> + + <% }else { %> + + <% } %> + + <% } %> + +
NameDescriptionDefault valueAllowed values
<%= entry.id() %><%= entry.description() %><%= entry.defaultValue() %>_None_<%= entry.allowedValues().map(value => value).join(', ') %>_Any_
+ + <%- include(securityPath,{ prototcol: server.protocol(), security: server.security() }) %> + <%- include(tagsPath,{ name:"Tags", tags: server.tags() }) %> + + <%- include(bindingsPath,{ name:"Server specific information", bindings: server.bindings(), schemaHelper }) %> + <%- include(extensionsPath,{ name:"Server extensions", extensions: server.extensions(), schemaHelper }) %> + +
+ <% } %> +<% } %> \ No newline at end of file diff --git a/src/components/Tags.ejs b/src/components/Tags.ejs new file mode 100644 index 0000000..7b44372 --- /dev/null +++ b/src/components/Tags.ejs @@ -0,0 +1,27 @@ +<% if(tags && !tags.isEmpty()) { %> +
<%= name %>
+ + + + + + + + + + <% for(let entry of tags.all()){ %> + + + + <% if(entry.externalDocs()){ %> + + <% }else { %> + + <% } %> + + <% } %> + +
NameDescriptionDocumentation
<%= entry.name() %><%= entry.description() %><%= entry.externalDocs() && entry.externalDocs().hasDescription() ? entry.externalDocs().description() : 'Find more info here' %>-
+ +<% } %> + diff --git a/src/components/classDiagram.ejs b/src/components/classDiagram.ejs new file mode 100644 index 0000000..e69de29 diff --git a/src/components/flowchart.ejs b/src/components/flowchart.ejs new file mode 100644 index 0000000..e69de29 diff --git a/webpack.config.js b/webpack.config.js index 6f182cc..c1ca2b3 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,7 +3,7 @@ 'use strict'; const path = require('path'); -const CopyPlugin = require('copy-webpack-plugin'); +const copyPlugin = require('copy-webpack-plugin'); //@ts-check /** @typedef {import('webpack').Configuration} WebpackConfig **/ @@ -39,6 +39,10 @@ const extensionConfig = { }, ], }, + { + test: /\.ejs$/, + loader: 'ejs-loader' + } ], }, devtool: 'nosources-source-map', @@ -46,7 +50,7 @@ const extensionConfig = { level: 'log', // enables logging required for problem matchers }, plugins: [ - new CopyPlugin({ + new copyPlugin({ patterns: [ { from: 'node_modules/@asyncapi/react-component/browser/standalone/index.js', @@ -57,9 +61,13 @@ const extensionConfig = { to: 'node_modules/@asyncapi/react-component/styles/default.min.css', }, { - from: '/node_modules/mermaid/dist/mermaid.min.js', - to: '/node_modules/mermaid/dist/mermaid.min.js', + from: 'node_modules/mermaid/dist/mermaid.min.js', + to: 'node_modules/mermaid/dist/mermaid.min.js', }, + { + from: 'src/components', + to: 'components' + } ], }), ], From 2d648594ccbf0d654c45d1820d98c6f14e803def Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Wed, 6 Mar 2024 23:47:14 +0530 Subject: [PATCH 03/15] add components except Message and schema Signed-off-by: nikhilkalburgi --- src/Asyncapi.ts | 132 +++++++++++++++++++++++++++++++++- src/components/Asyncapi.ejs | 3 +- src/components/Bindings.ejs | 2 +- src/components/Extensions.ejs | 4 +- src/components/Operations.ejs | 125 ++++++++++++++++++++++++++++++++ src/components/Security.ejs | 117 ++++++++++++++++++++++++++++++ src/components/Servers.ejs | 10 ++- 7 files changed, 380 insertions(+), 13 deletions(-) diff --git a/src/Asyncapi.ts b/src/Asyncapi.ts index ba39f72..2f8cf37 100644 --- a/src/Asyncapi.ts +++ b/src/Asyncapi.ts @@ -3,6 +3,7 @@ import * as vscode from 'vscode'; import * as ejs from 'ejs'; import * as path from 'path'; import * as Markdownit from 'markdown-it'; +import { Server } from 'http'; const md = Markdownit('commonmark'); @@ -10,6 +11,7 @@ const md = Markdownit('commonmark'); const extRenderType = 'x-schema-private-render-type'; const extRenderAdditionalInfo = 'x-schema-private-render-additional-info'; const extRawValue = 'x-schema-private-raw-value'; +const extParameterLocation = 'x-schema-private-parameter-location'; const jsonSchemaTypes: string[] = [ 'string', 'number', @@ -21,6 +23,30 @@ const jsonSchemaTypes: string[] = [ ]; class SchemaHelper { + static parametersToSchema(parameters: any[]) { + if (parameters.length === 0) { + return; + } + + const json:object = { + type: 'object', + properties: parameters.reduce( + (obj, parameter) => { + const parameterName = parameter.id(); + obj[String(parameterName)] = Object.assign({}, parameter.schema() === undefined ? {type: 'string'} : parameter.schema().json()); + obj[String(parameterName)].description = + parameter.description() || obj[String(parameterName)].description; + obj[String(parameterName)][extParameterLocation] = parameter.location(); + return obj; + }, + {}, + ), + required: parameters.map(parameter => parameter.id()), + [extRenderType]: false, + [extRenderAdditionalInfo]: false, + }; + return new SchemaModel(json); + } static jsonFieldToSchema(value: any): object { if (value === undefined || value === null) { return { @@ -102,6 +128,96 @@ class SchemaHelper { } } +class ServerHelper { + static securityType(value: string) { + switch (value) { + case 'apiKey': + return 'API key'; + case 'oauth2': + return 'OAuth2'; + case 'openIdConnect': + return 'Open ID'; + case 'http': + return 'HTTP'; + case 'userPassword': + return 'User/Password'; + case 'X509': + return 'X509'; + case 'symmetricEncryption': + return 'Symmetric Encription'; + case 'asymmetricEncryption': + return 'Asymmetric Encription'; + case 'httpApiKey': + return 'HTTP API key'; + case 'scramSha256': + return 'ScramSha256'; + case 'scramSha512': + return 'ScramSha512'; + case 'gssapi': + return 'GSSAPI'; + case 'plain': + return 'PLAIN'; + default: + return 'API key'; + } + } + + static flowName(value: string) { + switch (value) { + case 'implicit': + return 'Implicit'; + case 'password': + return 'Password'; + case 'clientCredentials': + return 'Client credentials'; + case 'authorizationCode': + return 'Authorization Code'; + default: + return 'Implicit'; + } + } + + static getKafkaSecurity(protocol: string, securitySchema: { type: () => any; }) { + let securityProtocol; + let saslMechanism; + if (protocol === 'kafka') { + if (securitySchema) { + securityProtocol = 'SASL_PLAINTEXT'; + } else { + securityProtocol = 'PLAINTEXT'; + } + } else if (securitySchema) { + securityProtocol = 'SASL_SSL'; + } else { + securityProtocol = 'SSL'; + } + if (securitySchema) { + switch (securitySchema.type()) { + case 'plain': + saslMechanism = 'PLAIN'; + break; + case 'scramSha256': + saslMechanism = 'SCRAM-SHA-256'; + break; + case 'scramSha512': + saslMechanism = 'SCRAM-SHA-512'; + break; + case 'oauth2': + saslMechanism = 'OAUTHBEARER'; + break; + case 'gssapi': + saslMechanism = 'GSSAPI'; + break; + case 'X509': + securityProtocol = 'SSL'; + break; + } + } + + return { securityProtocol, saslMechanism }; + } +} + export default async function info(asyncapi:AsyncAPIDocumentInterface, context: vscode.ExtensionContext) { @@ -128,7 +244,17 @@ export default async function info(asyncapi:AsyncAPIDocumentInterface, context: }, servers:{ servers: asyncapi.servers(), - schemaHelper: SchemaHelper + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + md + }, + operations:{ + channels: asyncapi.channels(), + isV3: asyncapi.version().split('.')[0] === '3', + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + allServersLength: asyncapi.servers().all().length, + md }, path:{ infoPath: path.join(context.extensionPath,'dist', 'components','Info.ejs'), @@ -137,7 +263,9 @@ export default async function info(asyncapi:AsyncAPIDocumentInterface, context: securityPath: path.join(context.extensionPath,'dist', 'components','Security.ejs'), bindingsPath: path.join(context.extensionPath,'dist', 'components','Bindings.ejs'), extensionsPath: path.join(context.extensionPath,'dist', 'components','Extensions.ejs'), - schemaPath: path.join(context.extensionPath,'dist', 'components','Schema.ejs') + schemaPath: path.join(context.extensionPath,'dist', 'components','Schema.ejs'), + operationsPath: path.join(context.extensionPath,'dist', 'components','Operations.ejs'), + messagePath: path.join(context.extensionPath,'dist', 'components','Message.ejs') } }); } \ No newline at end of file diff --git a/src/components/Asyncapi.ejs b/src/components/Asyncapi.ejs index 43f3214..983bdf1 100644 --- a/src/components/Asyncapi.ejs +++ b/src/components/Asyncapi.ejs @@ -1,2 +1,3 @@ <%- include(path.infoPath,{...info,tagsPath: path.tagsPath}) %> -<%- include(path.serversPath,{...servers, ...path}) %> \ No newline at end of file +<%- include(path.serversPath,{...servers, ...path}) %> +<%- include(path.operationsPath,{...operations, ...path}) %> \ No newline at end of file diff --git a/src/components/Bindings.ejs b/src/components/Bindings.ejs index 12df28e..c927f9c 100644 --- a/src/components/Bindings.ejs +++ b/src/components/Bindings.ejs @@ -1,5 +1,5 @@ <% if (!bindings.isEmpty()) { %> <% for(let binding of bindings.all()){ %> - <%- include(SchemaPath,{ schemaName:`${binding.protocol().charAt(0).toUpperCase() + binding.protocol().slice(1)} ${name}`, schema: schemaHelper.jsonToSchema(binding), key: binding.protocol() }) %> + <%- include(schemaPath,{ schemaName:`${binding.protocol().charAt(0).toUpperCase() + binding.protocol().slice(1)} ${name}`, schema: schemaHelper.jsonToSchema(binding), key: binding.protocol() }) %> <% } %> <% } %> \ No newline at end of file diff --git a/src/components/Extensions.ejs b/src/components/Extensions.ejs index 41c29fe..9a25262 100644 --- a/src/components/Extensions.ejs +++ b/src/components/Extensions.ejs @@ -1,5 +1,3 @@ - - <% if (Object.keys(schemaHelper.getCustomExtensions(extensions) || {}).length !== 0) { %> - <%- include(SchemaPath,{ schemaName:name, schema: schemaHelper.jsonToSchema(extensions) }) %> + <%- include(schemaPath,{ schemaName:name, schema: schemaHelper.jsonToSchema(extensions) }) %> <% } %> \ No newline at end of file diff --git a/src/components/Operations.ejs b/src/components/Operations.ejs index e69de29..98fca70 100644 --- a/src/components/Operations.ejs +++ b/src/components/Operations.ejs @@ -0,0 +1,125 @@ +<% if(!channels.isEmpty()) { %> +

Operations

+ <% for(let channel of channels.all()) { %> + <% for(let operation of channel.operations().all()) { %> + <% if(operation && channel) { %> + <% let type; + const applyToAllServers = allServersLength === channel.servers().all().length; + const servers = applyToAllServers ? [] : channel.servers().all(); + const showInfoList = operation.operationId() || (servers && servers.length); + if (operation.isSend()) { + if (operation.reply() !== undefined) { + type = 'request'; + } else { + type = 'send'; + } + } else if (operation.isReceive()) { + if (operation.reply() !== undefined) { + type = 'reply'; + } else { + type = 'receive'; + } + } %> + <%- md.render(`${getRenderedTypeForOperation({type})} \`${channel.address()}\` Operation`) %> + <% if(operation.summary()) { %> + <%- md.render(`*${operation.summary().trim()}*`) %> + <% } %> + <% if(showInfoList) { %> +
    + <% if(operation.operationId()) { %> +
  • Operation ID: <%= operation.operationId() %>
  • + <% if(servers && servers.length) { %> +
  • Available Only on Server: + <%= servers.map(s => { + const serverId = s.id(); + const slug = FormatHelpers.slugify(serverId); + return `[${serverId}](#${slug}-server)`; + }).join(', ') %> +
  • + <% } %> + <% } %> +
+ <% } %> + <% if(channel.hasDescription()) { %> + <%- md.render(channel.description()) %> + <% } %> + <% if(operation.hasDescription()) { %> + <%- md.render(operation.description()) %> + <% } %> + <% if(operation.externalDocs()) { %> + <%= (operation.externalDocs().description() || 'Find more info here.') %> + <% } %> + + <%- include(tagsPath,{ name:"Operation tags", tags: operation.tags() }) %> + + <% const parameters = schemaHelper.parametersToSchema(channel.parameters().all()); %> + <% if(parameters) { %> +

Parameters

+ <%- include(schemaPath,{}) %> + <% } %> + + <%- include(securityPath,{ header:'Additional security requirements', protocol: null, security: operation.security(), serverHelper, md }) %> + + + <%- include(bindingsPath,{ name:"Channel specific information", bindings: channel.bindings(), schemaHelper, schemaPath }) %> + <%- include(bindingsPath,{ name:"Operation specific information", bindings: operation.bindings(), schemaHelper, schemaPath }) %> + <%- include(extensionsPath,{ name:"Channel extensions", extensions: channel.extensions(), schemaHelper, schemaPath }) %> + <%- include(extensionsPath,{ name:"Operation extensions", extensions: operation.extensions(), schemaHelper, schemaPath }) %> + + + <% const messages = operation.messages().all(); %> + <% if (messages.length !== 0) { %> + <% const messageText = getOperationMessageText({type}); %> + <% if(messages.length > 1) { %> +

<%= messageText %>

+ <% } %> + <% for(let message of messages) { %> + <%- include(messagePath,{message}) %> + <% } %> + <% } %> + + <% } %> + <% } %> + <% } %> +<% } %> + + + +<% function getRenderedTypeForOperation({type}) { + if (isV3) { + switch (type) { + case 'request': + return 'REQUEST'; + case 'send': + return 'SEND'; + case 'reply': + return 'REPLY'; + case 'receive': + return 'RECEIVE'; + } + } + switch (type) { + case 'send': + return 'SUB'; + case 'receive': + return 'PUB'; + } + + return 'UNKNOWN'; + } + + function getOperationMessageText({type}) { + let messagesText = 'Accepts **one of** the following messages:'; + if (isV3) { + if (type === 'send') { + messagesText = 'Sending **one of** the following messages:'; + } else if (type === 'request') { + messagesText = 'Request contains **one of** the following messages:'; + } else if (type === 'receive') { + messagesText = 'Receive **one of** the following messages:'; + } else if (type === 'reply') { + messagesText = 'Request contains **one of** the following messages:'; + } + } + return messagesText; + } %> \ No newline at end of file diff --git a/src/components/Security.ejs b/src/components/Security.ejs index e69de29..79ba76f 100644 --- a/src/components/Security.ejs +++ b/src/components/Security.ejs @@ -0,0 +1,117 @@ +<% let renderedRequirements; %> +<% if(security?.length) { %> + <% renderedRequirements = security.map((requirement, idx) => {return { requirement, idx }}).filter(Boolean); %> +<% }else if(protocol == 'kafka' || protocol == 'kafka-secure') { %> + <% renderedRequirements = {requirement: null}; %> +<% } %> +<% if(renderedRequirements) { %> + <% if(security?.length && renderedRequirements.length !== 0) { %> +
+

<%= (header || "Security") %>

+ <% for(let { requirement, idx } of renderedRequirements) { %> + <% let renderedServerSecurities; %> + <% if(!requirement && (protocol == 'kafka' || protocol == 'kafka-secure')) { %> + <% renderedServerSecurities = {securitySchema: null}; %> + <% }else if(requirement) { %> + <% renderedServerSecurities = requirement.all().map(requirementItem =>{return {securitySchema: requirementItem.scheme(), requiredScopes: requirementItem.scopes(), key: requirementItem.scheme().type()}} ).filter(Boolean); %> + <% } %> + <% if(renderedServerSecurities) { %> + <% if(requirement && renderedServerSecurities.length !== 0) { %> +
Security Requirement
+ <% for(let {securitySchema, requiredScopes, key} of renderedServerSecurities) { + let schemas = []; + renderSecuritySchemasBasic({ securitySchema, schemas }); + renderSecuritySchemasKafka({ protocol, securitySchema, schemas }); + renderSecuritySchemasFlows({ securitySchema, requiredScopes, schemas }); + schemas.filter(Boolean); + const type = securitySchema?.type() && serverHelper.securityType(securitySchema.type()); %> +
    + <% if(type) { %> +
  • Type: <%= type %>
  • + <% } %> + <% if(schemas.length > 0) { %> + <% for(let schema of schemas) { %> + <% if(schema.split('_')[0] == 'OpenID') { %> +
  • OpenID Connect URL: <%= schema.split('_')[2] %>
  • + <% }else if(schema.split('_')[0] == 'RequiredScopes'){ %> +
  • Required Scopes: <%= schema.split('_')[1]? schema.split('_')[1]: 'Nil' %>
  • + + + + + + + + + + + + <% for(let entry of JSON.parse(schema.split('_')[2])){ %> + + + + + + + + <% } %> + +
    FlowAuth URLToken URLRefresh URLScopes
    <%= entry[0] %><%= entry[1] %><%= entry[2] %><%= entry[3] %><%= entry[4] %>
    + <% }else { %> +
  • <%= schema %>
  • + <% } %> + <% } %> + <% } %> +
+ <% if(securitySchema?.hasDescription()) { %> + <%- md.render(securitySchema.description()) %> + <% } %> + <% } %> + <% } %> + <% } %> + <% } %> +
+ <% } %> +<% } %> + +<% function renderSecuritySchemasBasic({ securitySchema, schemas }) { + if (securitySchema) { + if (securitySchema.name()) { + schemas.push(`Name: ${securitySchema.name()}`); + } + if (securitySchema.in()) { + schemas.push(`In: ${securitySchema.in()}`); + } + if (securitySchema.scheme()) { + schemas.push(`Scheme: ${securitySchema.scheme()}`); + } + if (securitySchema.bearerFormat()) { + schemas.push(`Bearer format: ${securitySchema.bearerFormat()}`); + } + if (securitySchema.openIdConnectUrl()) { + schemas.push(`OpenID_${securitySchema.openIdConnectUrl()}_${securitySchema.openIdConnectUrl()}`); + } + } + } + + function renderSecuritySchemasKafka({ protocol, securitySchema, schemas }) { + const isKafkaProtocol = protocol === 'kafka' || protocol === 'kafka-secure'; + if (!isKafkaProtocol) { return; } + + const { securityProtocol, saslMechanism } = serverHelper.getKafkaSecurity(protocol,securitySchema); + + if (securityProtocol) { schemas.push(`security.protocol: ${securityProtocol}`); } + if (saslMechanism) { schemas.push(`sasl.mechanism: ${saslMechanism}`); } + } + + + function flowsRenderer([flowName, flow]) { + return [serverHelper.flowName(flowName) || '-', (flow?.authorizationUrl() ? flow.authorizationUrl() : '-'), (flow?.tokenUrl() ? flow.tokenUrl() : '-'), (flow?.refreshUrl() ? flow.refreshUrl() : '-'), Object.keys(flow?.scopes() || {}).length ? Object.keys(flow.scopes()).map(v => `\`${v}\``).join(', ') : '-' ]; + } + function renderSecuritySchemasFlows({ securitySchema, requiredScopes, schemas }) { + const flows = securitySchema?.flows(); + if (!flows) { return; } + + const flowsData = Object.entries({authorizationCode: flows.authorizationCode(),clientCredentials: flows.clientCredentials(),implicit: flows.implicit(),password: flows.password()}); + schemas.push( `RequiredScopes_${ requiredScopes.map(v => `\`${v}\``).join(', ')}_${JSON.stringify(flowsData.map(entry => flowsRenderer(entry)))}` ); + } %> diff --git a/src/components/Servers.ejs b/src/components/Servers.ejs index 01d9c87..ed729bc 100644 --- a/src/components/Servers.ejs +++ b/src/components/Servers.ejs @@ -9,9 +9,7 @@
  • Protocol: <%= server.protocol() %> <%= server.protocolVersion() ? server.protocolVersion() : '' %>
  • <% if(server.hasDescription()) { %> -

    - Description: <%= server.description() %> -

    + <%- md.render(`Description: ${server.description()}`) %> <% } %>

    URL Variables

    @@ -44,11 +42,11 @@ - <%- include(securityPath,{ prototcol: server.protocol(), security: server.security() }) %> + <%- include(securityPath,{ header:null, protocol: server.protocol(), security: server.security(), serverHelper, md }) %> <%- include(tagsPath,{ name:"Tags", tags: server.tags() }) %> - <%- include(bindingsPath,{ name:"Server specific information", bindings: server.bindings(), schemaHelper }) %> - <%- include(extensionsPath,{ name:"Server extensions", extensions: server.extensions(), schemaHelper }) %> + <%- include(bindingsPath,{ name:"Server specific information", bindings: server.bindings(), schemaHelper, schemaPath }) %> + <%- include(extensionsPath,{ name:"Server extensions", extensions: server.extensions(), schemaHelper, schemaPath }) %> <% } %> From ea543eb9e441ba4c3c18874d9805dfbe92f72c55 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Fri, 8 Mar 2024 23:50:58 +0530 Subject: [PATCH 04/15] complete markdown building Signed-off-by: nikhilkalburgi --- src/Asyncapi.ts | 390 +++++++++++++++++++++++++++++++ src/components/Bindings.ejs | 2 +- src/components/Extensions.ejs | 2 +- src/components/Message.ejs | 109 +++++++++ src/components/Operations.ejs | 14 +- src/components/Schema.ejs | 420 ++++++++++++++++++++++++++++++++++ 6 files changed, 928 insertions(+), 9 deletions(-) diff --git a/src/Asyncapi.ts b/src/Asyncapi.ts index 2f8cf37..bacef3b 100644 --- a/src/Asyncapi.ts +++ b/src/Asyncapi.ts @@ -4,6 +4,7 @@ import * as ejs from 'ejs'; import * as path from 'path'; import * as Markdownit from 'markdown-it'; import { Server } from 'http'; +import { sample } from 'openapi-sampler'; const md = Markdownit('commonmark'); @@ -22,7 +23,341 @@ const jsonSchemaTypes: string[] = [ 'null', ]; +const RESTRICTED_ANY = 'restricted any'; +const NEVER = 'never'; +const UNKNOWN = 'unknown'; +const ANY = 'any'; +const jsonSchemaKeywordTypes = { + maxLength: 'string', + minLength: 'string', + pattern: 'string', + contentMediaType: 'string', + contentEncoding: 'string', + multipleOf: 'number', + maximum: 'number', + exclusiveMaximum: 'number', + minimum: 'number', + exclusiveMinimum: 'number', + items: 'array', + maxItems: 'array', + minItems: 'array', + uniqueItems: 'array', + contains: 'array', + additionalItems: 'array', + maxProperties: 'object', + minProperties: 'object', + required: 'object', + properties: 'object', + patternProperties: 'object', + propertyNames: 'object', + dependencies: 'object', + additionalProperties: 'object', +}; + class SchemaHelper { + + static toSchemaType(schema: { json: () => boolean; isBooleanSchema: () => any; not: () => any; }):any { + if (!schema || typeof schema.json !== 'function') { + return UNKNOWN; + } + if (schema.isBooleanSchema()) { + if (schema.json() === true) { + return ANY; + } + return NEVER; + } + // handle case with `{}` schemas + if (Object.keys(schema.json()).length === 0) { + return ANY; + } + // handle case with `{ not: {}, ... }` schemas + const not = schema.not(); + if (not && this.inferType(not) === ANY) { + return NEVER; + } + + let type = this.inferType(schema); + if (Array.isArray(type)) { + return type.map(t => this.toType(t, schema)).join(' | '); + } + type = this.toType(type, schema); + const combinedType = this.toCombinedType(schema); + + if (type && combinedType) { + return `${type} ${combinedType}`; + } + if (combinedType) { + return combinedType; + } + return type; + } + + static toType(type: string, schema: { json?: () => boolean; isBooleanSchema?: () => any; not?: () => any; items?: any; additionalItems?: any; }) { + if (type === 'array') { + const items = schema.items(); + if (Array.isArray(items)) { + const types = items.map(item => this.toSchemaType(item)).join(', '); + const additionalItems = schema.additionalItems(); + if (additionalItems === true) { + return `tuple<${types || UNKNOWN}, ...optional<${ANY}>>`; + } + if (additionalItems === false) { + return `tuple<${types}>`; + } + const additionalType = this.toSchemaType(additionalItems); + return `tuple<${types || UNKNOWN}, ...optional<${additionalType}>>`; + } + if (!items) { + return `array<${ANY}>`; + } + return `array<${this.toSchemaType(items) || UNKNOWN}>`; + } + return type; + } + + static toCombinedType(schema: { json?: () => boolean; isBooleanSchema?: () => any; not?: () => any; oneOf?: any; anyOf?: any; allOf?: any; }) { + const t = []; + if (schema.oneOf()) { + t.push('oneOf'); + } + if (schema.anyOf()) { + t.push('anyOf'); + } + if (schema.allOf()) { + t.push('allOf'); + } + if (t.length === 0 || t.length > 1) { + return undefined; + } + return t[0]; + } + + static inferType(schema: { json: any; isBooleanSchema?: (() => any) | (() => any) | undefined; not?: (() => any) | (() => any) | undefined; type?: any; const?: any; enum?: any; oneOf?: any; anyOf?: any; allOf?: any; }) { + let types = schema.type(); + + if (types !== undefined) { + if (Array.isArray(types)) { + // if types have `integer` and `number` types, `integer` is unnecessary + if (types.includes('integer') && types.includes('number')) { + types = types.filter(t => t !== 'integer'); + } + return types.length === 1 ? types[0] : types; + } + return types; + } + + const constValue = schema.const(); + if (constValue !== undefined) { + const typeOf = typeof constValue; + if (typeOf === 'number' && Number.isInteger(constValue)) { + return 'integer'; + } + return typeOf; + } + const enumValue = schema.enum(); + if (Array.isArray(enumValue) && enumValue.length) { + const inferredType = Array.from(new Set(enumValue.map(e => { + const typeOf = typeof e; + if (typeOf === 'number' && Number.isInteger(e)) { + return 'integer'; + } + return typeOf; + }))); + return inferredType.length === 1 ? inferredType[0] : inferredType; + } + + const schemaKeys = Object.keys(schema.json() || {}) || []; + const hasInferredTypes = Object.keys(jsonSchemaKeywordTypes).some(key => + schemaKeys.includes(key), + ); + if (hasInferredTypes === true) { + return ''; + } + if (this.toCombinedType(schema)) { + return ''; + } + return ANY; + } + + static prettifyValue(value: { toString: () => any; }) { + const typeOf = typeof value; + if (typeOf === 'string') { + return `"${value}"`; + } + if (typeOf === 'number' || typeOf === 'bigint' || typeOf === 'boolean') { + return value; + } + if (Array.isArray(value)) { + return `[${value.toString()}]`; + } + return JSON.stringify(value); + } + + static humanizeConstraints(schema: { minimum: () => undefined; exclusiveMinimum: () => undefined; maximum: () => undefined; exclusiveMaximum: () => undefined; multipleOf: () => { toString: (arg0: number) => any; } | undefined; minLength: () => number | undefined; maxLength: () => undefined; uniqueItems: () => any; minItems: () => number | undefined; maxItems: () => undefined; minProperties: () => number | undefined; maxProperties: () => undefined; }) { + const constraints = []; + + // related to number/integer + const numberRange = this.humanizeNumberRangeConstraint( + schema.minimum(), + schema.exclusiveMinimum(), + schema.maximum(), + schema.exclusiveMaximum(), + ); + if (numberRange !== undefined) { + constraints.push(numberRange); + } + const multipleOfConstraint = this.humanizeMultipleOfConstraint( + schema.multipleOf(), + ); + if (multipleOfConstraint !== undefined) { + constraints.push(multipleOfConstraint); + } + + // related to string + const stringRange = this.humanizeRangeConstraint( + 'characters', + schema.minLength(), + schema.maxLength(), + ); + if (stringRange !== undefined) { + constraints.push(stringRange); + } + + // related to array + const hasUniqueItems = schema.uniqueItems(); + const arrayRange = this.humanizeRangeConstraint( + hasUniqueItems ? 'unique items' : 'items', + schema.minItems(), + schema.maxItems(), + ); + if (arrayRange !== undefined) { + constraints.push(arrayRange); + } + + // related to object + const objectRange = this.humanizeRangeConstraint( + 'properties', + schema.minProperties(), + schema.maxProperties(), + ); + if (objectRange !== undefined) { + constraints.push(objectRange); + } + + return constraints; + } + + static humanizeNumberRangeConstraint( + min: undefined, + exclusiveMin: undefined, + max: undefined, + exclusiveMax: undefined, + ) { + const hasExclusiveMin = exclusiveMin !== undefined; + const hasMin = min !== undefined || hasExclusiveMin; + const hasExclusiveMax = exclusiveMax !== undefined; + const hasMax = max !== undefined || hasExclusiveMax; + + let numberRange; + if (hasMin && hasMax) { + numberRange = hasExclusiveMin ? '( ' : '[ '; + numberRange += hasExclusiveMin ? exclusiveMin : min; + numberRange += ' .. '; + numberRange += hasExclusiveMax ? exclusiveMax : max; + numberRange += hasExclusiveMax ? ' )' : ' ]'; + } else if (hasMin) { + numberRange = hasExclusiveMin ? '> ' : '>= '; + numberRange += hasExclusiveMin ? exclusiveMin : min; + } else if (hasMax) { + numberRange = hasExclusiveMax ? '< ' : '<= '; + numberRange += hasExclusiveMax ? exclusiveMax : max; + } + return numberRange; + } + + static humanizeMultipleOfConstraint( + multipleOf: { toString: (arg0: number) => any; } | undefined, + ) { + if (multipleOf === undefined) { + return; + } + const strigifiedMultipleOf = multipleOf.toString(10); + if (!(/^0\.0*1$/).test(strigifiedMultipleOf)) { + return `multiple of ${strigifiedMultipleOf}`; + } + return `decimal places <= ${strigifiedMultipleOf.split('.')[1].length}`; + } + + static humanizeRangeConstraint( + description: any, + min: number | undefined, + max: undefined, + ) { + let stringRange; + if (min !== undefined && max !== undefined) { + if (min === max) { + stringRange = `${min} ${description}`; + } else { + stringRange = `[ ${min} .. ${max} ] ${description}`; + } + } else if (max !== undefined) { + stringRange = `<= ${max} ${description}`; + } else if (min !== undefined) { + if (min === 1) { + stringRange = 'non-empty'; + } else { + stringRange = `>= ${min} ${description}`; + } + } + return stringRange; + } + + static getDependentRequired(propertyName: string, schema: { dependencies: () => any; }) { + const dependentRequired = []; + const dependencies = schema.dependencies(); + if (!dependencies) { + return; + } + + for (const [prop, array] of Object.entries(dependencies)) { + if (Array.isArray(array) && array.includes(propertyName)) { + dependentRequired.push(prop); + } + } + return dependentRequired.length ? dependentRequired : undefined; + } + + static getDependentSchemas(schema: { dependencies: () => any; }) { + const dependencies = schema.dependencies(); + if (!dependencies) { + return; + } + + const records:any = {}; + for (const [prop, propSchema] of Object.entries(dependencies)) { + if (typeof propSchema === 'object' && !Array.isArray(propSchema)) { + records[String(prop)] = propSchema; + } + } + if (!Object.keys(records).length) { + return undefined; + } + + const json:object = { + type: 'object', + properties: Object.entries(records).reduce( + (obj:any, [propertyName, propertySchema]:any[]) => { + obj[String(propertyName)] = Object.assign({}, propertySchema.json()); + return obj; + }, + {}, + ), + [extRenderType]: false, + [extRenderAdditionalInfo]: false, + }; + return new SchemaModel(json); + } + static parametersToSchema(parameters: any[]) { if (parameters.length === 0) { return; @@ -218,7 +553,61 @@ class ServerHelper { } } +class MessageHelper { + static getPayloadExamples(message: { examples: () => { (): any; new(): any; all: { (): any; new(): any; }; }; payload: () => any; }) { + const examples = message.examples().all(); + if (Array.isArray(examples) && examples.some(e => e.payload())) { + const messageExamples = examples + .map(e => { + if (!e.payload()) {return;} + return { + name: e.name(), + summary: e.summary(), + example: e.payload(), + }; + }) + .filter(Boolean); + + if (messageExamples.length > 0) { + return messageExamples; + } + } + + const payload = message.payload(); + if (payload?.examples()) { + return payload.examples().map((example: any) => ({ example })); + } + } + + static getHeadersExamples(message: { examples: () => { (): any; new(): any; all: { (): any; new(): any; }; }; headers: () => any; }) { + const examples = message.examples().all(); + if (Array.isArray(examples) && examples.some(e => e.headers())) { + const messageExamples = examples + .map(e => { + if (!e.headers()) {return;} + return { + name: e.name(), + summary: e.summary(), + example: e.headers(), + }; + }) + .filter(Boolean); + + if (messageExamples.length > 0) { + return messageExamples; + } + } + + const headers = message.headers(); + if (headers?.examples()) { + return headers.examples().map((example: any) => ({ example })); + } + } + static generateExample(value: any, options: any) { + return JSON.stringify(sample(value, options || {}) || '', null, 2); + } +} export default async function info(asyncapi:AsyncAPIDocumentInterface, context: vscode.ExtensionContext) { @@ -253,6 +642,7 @@ export default async function info(asyncapi:AsyncAPIDocumentInterface, context: isV3: asyncapi.version().split('.')[0] === '3', schemaHelper: SchemaHelper, serverHelper: ServerHelper, + messageHelper: MessageHelper, allServersLength: asyncapi.servers().all().length, md }, diff --git a/src/components/Bindings.ejs b/src/components/Bindings.ejs index c927f9c..419eb2a 100644 --- a/src/components/Bindings.ejs +++ b/src/components/Bindings.ejs @@ -1,5 +1,5 @@ <% if (!bindings.isEmpty()) { %> <% for(let binding of bindings.all()){ %> - <%- include(schemaPath,{ schemaName:`${binding.protocol().charAt(0).toUpperCase() + binding.protocol().slice(1)} ${name}`, schema: schemaHelper.jsonToSchema(binding), key: binding.protocol() }) %> + <%- include(schemaPath,{ schemaName:`${binding.protocol().charAt(0).toUpperCase() + binding.protocol().slice(1)} ${name}`, schema: schemaHelper.jsonToSchema(binding), hideTitle: false, schemaHelper, md, path:"" }) %> <% } %> <% } %> \ No newline at end of file diff --git a/src/components/Extensions.ejs b/src/components/Extensions.ejs index 9a25262..b678539 100644 --- a/src/components/Extensions.ejs +++ b/src/components/Extensions.ejs @@ -1,3 +1,3 @@ <% if (Object.keys(schemaHelper.getCustomExtensions(extensions) || {}).length !== 0) { %> - <%- include(schemaPath,{ schemaName:name, schema: schemaHelper.jsonToSchema(extensions) }) %> + <%- include(schemaPath,{ schemaName:name, schema: schemaHelper.jsonToSchema(extensions), hideTitle: false, schemaHelper, md, path:"" }) %> <% } %> \ No newline at end of file diff --git a/src/components/Message.ejs b/src/components/Message.ejs index e69de29..78b56ba 100644 --- a/src/components/Message.ejs +++ b/src/components/Message.ejs @@ -0,0 +1,109 @@ +<% if (message) { + const messageId = message.id(); + const headers = message.headers(); + const payload = message.payload(); + const correlationId = message.correlationId(); + const contentType = message.contentType(); + const externalDocs = message.externalDocs(); + const showInfoList = contentType || externalDocs; + + let header = 'Message'; + if (message.title()) { + header += ` ${message.title()}`; + } + const id = message.name() || messageId; + if (id) { + header += ` ${id}`; + } %> + +

    <%- header %>

    + + <% if(message.summary()) { %> + <%- md.render(`*${message.summary()}*`) %> + <% } %> + + <% if(showInfoList) { %> +
    + <% if(messageId) { %> +
  • Message ID: <%= messageId %>
  • + <% } %> + <% if(contentType) { %> +
  • + Content type: <%- `${contentType}` %> +
  • + <% } %> + <% if(correlationId) { %> +
      +
    • + Correlation ID: <%= correlationId.location() %> +
    • + <% if(correlationId.hasDescription()) { %> +
      + <%- md.render(correlationId.description()) %> + <% } %> +
    + <% } %> +
    + <% } %> + <% if(message.hasDescription()) { %> + <%- md.render(message.description()) %> + <% } %> + + <% if(externalDocs) { %> + + <%- md.render(externalDocs.description() || 'Find more info here.') %> + + <% } %> + + <% if(headers) { %> +
    Headers
    + <%- include(schemaPath,{schema:headers,schemaName:"", hideTitle:true, schemaHelper, md, path:""}) %> + <% const ex = messageHelper.getHeadersExamples(message); + if (ex) { %> +
    Examples of headers
    + <% if (ex.length !== 0) { + examples.map((e, idx) => { %> +

    <%= e.name && e.name %>

    + <%- e.summary && md.render(e.summary) %> + <%= JSON.stringify(e.example, null, 2) %> + <% }); %> + <% } %> + <% }else { + const headers = message.headers(); + if (headers) { %> +
    Examples of headers _generated_
    + <%- md.render(messageHelper.generateExample(headers.json())) %> + <% } %> + <% } %> + + <% } %> + + <% if(payload) { %> +
    Payload
    + <%- include(schemaPath,{schema:payload, schemaName:"", hideTitle:true, schemaHelper, md, path:""}) %> + <% const examples = messageHelper.getPayloadExamples(message); + if (examples) { %> +
    Examples of payload
    + <% if (examples.length !== 0) { + examples.map((ex, idx) => { %> +

    <%= ex.name && ex.name %>

    + <%- ex.summary && md.render(ex.summary) %> + <%= md.render(JSON.stringify(ex.example, null, 2)) %> + <% }); %> + <% } %> + <% }else { + const payload = message.payload(); + if (payload) { %> +
    Examples of payload _generated_
    + <%- md.render(messageHelper.generateExample(payload.json())) %> + <% } %> + + <% } %> + + <% } %> + + <%- include(bindingsPath,{name:"Message specific information", bindings:message.bindings(), schemaHelper, schemaPath}) %> + <%- include(extensionsPath,{name:"Message extensions", extensions:message.extensions(), schemaHelper, schemaPath}) %> + <%- include(tagsPath,{name:"Message tags", tags:message.tags()}) %> +<% } %> + diff --git a/src/components/Operations.ejs b/src/components/Operations.ejs index 98fca70..fc7c6b7 100644 --- a/src/components/Operations.ejs +++ b/src/components/Operations.ejs @@ -55,26 +55,26 @@ <% const parameters = schemaHelper.parametersToSchema(channel.parameters().all()); %> <% if(parameters) { %>

    Parameters

    - <%- include(schemaPath,{}) %> + <%- include(schemaPath,{ schema: parameters, schemaName: "Parameters", hideTitle: true, schemaHelper, md, path:"" }) %> <% } %> <%- include(securityPath,{ header:'Additional security requirements', protocol: null, security: operation.security(), serverHelper, md }) %> - <%- include(bindingsPath,{ name:"Channel specific information", bindings: channel.bindings(), schemaHelper, schemaPath }) %> - <%- include(bindingsPath,{ name:"Operation specific information", bindings: operation.bindings(), schemaHelper, schemaPath }) %> - <%- include(extensionsPath,{ name:"Channel extensions", extensions: channel.extensions(), schemaHelper, schemaPath }) %> - <%- include(extensionsPath,{ name:"Operation extensions", extensions: operation.extensions(), schemaHelper, schemaPath }) %> + <%- include(bindingsPath,{ name:"Channel specific information", bindings: channel.bindings(), schemaHelper, schemaPath, md }) %> + <%- include(bindingsPath,{ name:"Operation specific information", bindings: operation.bindings(), schemaHelper, schemaPath, md }) %> + <%- include(extensionsPath,{ name:"Channel extensions", extensions: channel.extensions(), schemaHelper, schemaPath, md }) %> + <%- include(extensionsPath,{ name:"Operation extensions", extensions: operation.extensions(), schemaHelper, schemaPath, md }) %> <% const messages = operation.messages().all(); %> <% if (messages.length !== 0) { %> <% const messageText = getOperationMessageText({type}); %> <% if(messages.length > 1) { %> -

    <%= messageText %>

    +

    <%- md.render(messageText) %>

    <% } %> <% for(let message of messages) { %> - <%- include(messagePath,{message}) %> + <%- include(messagePath,{message, bindingsPath, extensionsPath, schemaHelper, schemaPath, md, messageHelper}) %> <% } %> <% } %> diff --git a/src/components/Schema.ejs b/src/components/Schema.ejs index e69de29..6e2925a 100644 --- a/src/components/Schema.ejs +++ b/src/components/Schema.ejs @@ -0,0 +1,420 @@ +<% if(schemaName && hideTitle === false ) { %> +

    <%= schemaName %>

    +<% } %> + + + + + + + + + + + + + <% if ( schema && !(schemaName.indexOf('x-parser-')> -1 || schemaName.indexOf('x-schema-private-') > -1) ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema, schemaName, 'root'); %> + + + + + + + + + <% const dependentSchemas = schemaHelper.getDependentSchemas(schema); + const extensions = schemaHelper.getCustomExtensions(schema); + const extensionsSchema = (extensions || Object.keys(extensions).length)? schemaHelper.jsonToSchema(extensions) : null; + const properties = schema.properties() || {}; + if (Object.keys(properties)) { + const required = schema.required() || []; + const patternProperties = schema.patternProperties() || {}; + for(let [propertyName, property] of Object.entries(properties) ) { %> + <% if ( property && !(propertyName.indexOf('x-parser-')> -1 || propertyName.indexOf('x-schema-private-') > -1) ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(property, propertyName, required.includes(propertyName), schemaHelper.getDependentRequired(propertyName,schema), buildPath((path || schemaName), propertyName)); %> + + + + + + + + + <% } %> + <% } %> + <% for(let [propertyName, property] of Object.entries(patternProperties) ) { %> + <% if ( property && !(propertyName.indexOf('x-parser-')> -1 || propertyName.indexOf('x-schema-private-') > -1) ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(property, propertyName, false, [], buildPath((path || schemaName), propertyName), 'pattern property'); %> + + + + + + + + + <% } %> + <% } %> + + <% const type = schema.type(); + const types = Array.isArray(type) ? type : [type]; + if (!(type !== undefined && !types.includes('array'))) { + const items = schema.items(); + if (items && !Array.isArray(items) && Object.keys(items.properties() || {}).length) { + const properties = items.properties() || {}; + if (Object.keys(properties)) { + const required = items.required() || []; + const patternProperties = items.patternProperties() || {}; + for(let [propertyName, property] of Object.entries(properties) ) { %> + <% if ( property && !(propertyName.indexOf('x-parser-')> -1 || propertyName.indexOf('x-schema-private-') > -1) ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(property, propertyName, required.includes(propertyName), schemaHelper.getDependentRequired(propertyName,items), buildPath((path || ""), propertyName)); %> + + + + + + + + + <% } %> + <% } %> + <% for(let [propertyName, property] of Object.entries(patternProperties) ) { %> + <% if ( property && !(propertyName.indexOf('x-parser-')> -1 || propertyName.indexOf('x-schema-private-') > -1) ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(property, propertyName, false, [], path, 'Single Item'); %> + + + + + + + + + <% } %> + <% } %> + <% } %> + <% } else if (Array.isArray(items)) { %> + + <% items.map((item, idx) => { + if ( item ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(item, "", false, [], buildPath(path || "", idx), 'index'); %> + + + + + + + + + <% } %> + <% }) %> + + <% }else { %> + <% if ( items ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(items, "", false, [], path, 'Single Item'); %> + + + + + + + + + <% } %> + <% } %> + + <% } %> + + <% } %> + <% schema.oneOf() && schema.oneOf().map((s, idx) => { + if ( s && !(idx.indexOf('x-parser-')> -1 || idx.indexOf('x-schema-private-') > -1) ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(s, idx, false, [], buildPath(path || schemaName, idx), 'oneOf item'); %> + + + + + + + + + <% } %> + <% }) %> + <% schema.anyOf() && schema.anyOf().map((s, idx) => { + if ( s && !(idx.indexOf('x-parser-')> -1 || idx.indexOf('x-schema-private-') > -1) ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(s, idx, false, [], buildPath(path || schemaName, idx), 'anyOf item'); %> + + + + + + + + + <% } %> + <% }) %> + <% schema.allOf() && schema.allOf().map((s, idx) => { + if ( s && !(idx.indexOf('x-parser-')> -1 || idx.indexOf('x-schema-private-') > -1) ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(s, idx, false, [], buildPath(path || schemaName, idx), 'allOf item'); %> + + + + + + + + + <% } %> + <% }) %> + <% if ( schema.not() ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.not(), "", false, [], path,'not', false); %> + + + + + + + + + <% } %> + <% if ( schema.propertyNames() ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.propertyNames(), "", false, [], path,'property names', false); %> + + + + + + + + + <% } %> + <% if ( schema.contains() ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.contains(), "", false, [], path,'contains', false); %> + + + + + + + + + <% } %> + <% if ( schema.if() ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.if(), "", false, [], path,'if', false); %> + + + + + + + + + <% } %> + <% if ( schema.then() ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.then(), "", false, [], path,'then', false); %> + + + + + + + + + <% } %> + <% if ( schema.else() ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.else(), "", false, [], path,'else', false); %> + + + + + + + + + <% } %> + <% if ( dependentSchemas ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(dependentSchemas, "", false, [], path,'dependant schemas'); %> + + + + + + + + + <% } %> + <% if ( extensionsSchema ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(extensionsSchema, "", false, [], path); %> + + + + + + + + + <% } %> + <% const ext = schema.extensions(); + if (ext.get('x-schema-private-render-additional-info')?.value() === true) { + const type = schema.type(); + const types = Array.isArray(type) ? type : [type]; + if (!(type !== undefined && !types.includes('object'))) { + const additionalProperties = schema.additionalProperties(); + if (!(additionalProperties === true || additionalProperties === undefined || additionalProperties === false)) { + if ( additionalProperties ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(additionalProperties, "", false, [], path,'additional properties', false); %> + + + + + + + + + <% } %> + <% } %> + <% } %> + <% } %> + <% if (ext.get('x-schema-private-render-additional-info')?.value() === true) { + const type = schema.type(); + const types = Array.isArray(type) ? type : [type]; + if (!(type !== undefined && !types.includes('array'))) { + if (Array.isArray(schema.items())) { + const additionalItems = schema.additionalItems(); + if (!(additionalItems === true || additionalItems === undefined || additionalItems === false)) { + if ( additionalItems ) { + const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(additionalItems, "", false, [], path,'additional items', false); %> + + + + + + + + + <% } %> + <% } %> + <% } %> + <% } %> + <% } %> + +<% } %> + +
    NameTypeDescriptionValueConstraintsNotes
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    + +<% function schemaPropRow( schema, schemaName, required = false, dependentRequired = [], path = '', nameNote = '',tryRenderAdditionalNotes = true) { + const isCircular = schema.isCircular() || false; + const extensions = schema.extensions(); + const renderType = extensions.get('x-schema-private-render-type')?.value() !== false; + const rawValue = extensions.get('x-schema-private-raw-value')?.value() === true; + const name = tree(path) || schemaName; + const schemaType = renderType && schemaHelper.toSchemaType(schema); + let description = (schema.description() || '').replace(new RegExp('\S*\r?\n','g'), ' '); + const externalDocs = schema.externalDocs(); + description = externalDocs ? `${!description.endsWith('.') ? `${description}.` : description} [${externalDocs.description() || 'Documentation'}](${externalDocs.url()})` : description; + description = description.trim(); + const values = rawValue ? `\`${schemaHelper.prettifyValue(schema.const())}\`` : schemaValues(schema); + const constraints = schemaConstraints(schema); + const notes = schemaNotes({ schema, required, dependentRequired, isCircular, tryRenderAdditionalNotes }); + + let renderedName = ''; + if (nameNote) { + renderedName = name ? `${name} (${nameNote})` : `(${nameNote})`; + } else { + renderedName = name; + } + return [renderedName, schemaType, description, values, constraints, notes]; +} + +function tree(path = '') { + path = String(path); + const filteredPaths = path.split('.').filter(Boolean); + return filteredPaths.join('.'); +} + +function buildPath(path = '', field = '') { + console.log(path,field); + if (!path) return field; + return `${path}.${field}`; +} + +function schemaValues(schema) { + if (!schema) return null; + const values = []; + + if (schema.default()) values.push(`default (\`${schemaHelper.prettifyValue(schema.default())}\`)`); + if (schema.const()) values.push(`const (\`${schemaHelper.prettifyValue(schema.const())}\`)`); + if (schema.enum()) { + const allowed = schema.enum().map(v => `\`${schemaHelper.prettifyValue(v)}\``).join(', '); + values.push(`allowed (${allowed})`); + } + if (schema.examples()) { + const examples = schema.examples().map(v => `\`${schemaHelper.prettifyValue(v)}\``).join(', '); + values.push(`examples (${examples})`); + } + + return values.join(', '); +} + +function schemaConstraints(schema) { + if (!schema) return null; + const constraints = []; + + if (schema.format()) constraints.push(`format (\`${schema.format()}\`)`); + if (schema.pattern()) constraints.push(`pattern (\`${schema.pattern()}\`)`); + if (schema.contentMediaType()) constraints.push(`media type (\`${schema.contentMediaType()}\`)`); + if (schema.contentEncoding()) constraints.push(`encoding (\`${schema.contentEncoding()}\`)`); + + return constraints.concat(schemaHelper.humanizeConstraints(schema)).join(', '); +} + +function schemaNotes({ schema, required = false, dependentRequired = [], isCircular = false, tryRenderAdditionalNotes }) { + if (!schema) return null; + const notes = []; + + if (schema.deprecated()) notes.push('deprecated'); + + if (required) notes.push('required'); + if (dependentRequired.length) { + const deps = dependentRequired.map(v => `\`${v}\``).join(', '); + notes.push(`required when defined (${deps})`); + } + const extensions = schema.extensions(); + const parameterLocation = extensions.get('x-schema-private-parameter-location'); + if (parameterLocation?.value()) { + notes.push(`parameter location (${parameterLocation.value()})`); + } + + if (isCircular) notes.push('circular'); + if (schema.writeOnly()) notes.push('write-only'); + if (schema.readOnly()) notes.push('read-only'); + if (extensions.get('x-schema-private-render-additional-info')?.value() !== false) { + const type = schema.type(); + const types = Array.isArray(type) ? type : [type]; + if ( + (type === undefined && tryRenderAdditionalNotes) || + types.includes('object') + ) { + const additionalProperties = schema.additionalProperties(); + if (additionalProperties === true || additionalProperties === undefined) { + notes.push('additional properties are allowed'); + } else if (additionalProperties === false) { + notes.push('additional properties are NOT allowed'); + } + } + if ( + ( + (type === undefined && tryRenderAdditionalNotes) || + types.includes('array') + ) && + Array.isArray(schema.items()) + ) { + const additionalItems = schema.additionalItems(); + if (additionalItems === true || additionalItems === undefined) { + notes.push('additional items are allowed'); + } else if (additionalItems === false) { + notes.push('additional items are NOT allowed'); + } + } + } + return notes.join(', '); +} %> \ No newline at end of file From 4e8e9c701f6dfcd37ecf186c3bbb6753db467478 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Sun, 10 Mar 2024 13:08:45 +0530 Subject: [PATCH 05/15] feat: build the markdown preview Signed-off-by: nikhilkalburgi --- src/PreviewMarkdown.ts | 180 +++++++++++++++++++++++++-- src/components/Message.ejs | 2 +- src/components/Schema.ejs | 241 ++++++++++++++++++------------------ src/components/Security.ejs | 12 +- src/components/Servers.ejs | 15 +-- src/components/Tags.ejs | 11 +- 6 files changed, 311 insertions(+), 150 deletions(-) diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts index 2e99628..98cf2bb 100644 --- a/src/PreviewMarkdown.ts +++ b/src/PreviewMarkdown.ts @@ -89,25 +89,181 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web + +
    +
    ${result}
    +
    Section 2
    +
    Section 3
    +
    + +
    + + + +
    + - ${result} diff --git a/src/components/Message.ejs b/src/components/Message.ejs index 78b56ba..7986a83 100644 --- a/src/components/Message.ejs +++ b/src/components/Message.ejs @@ -88,7 +88,7 @@ examples.map((ex, idx) => { %>

    <%= ex.name && ex.name %>

    <%- ex.summary && md.render(ex.summary) %> - <%= md.render(JSON.stringify(ex.example, null, 2)) %> + <%- md.render(JSON.stringify(ex.example, null, 2)) %> <% }); %> <% } %> <% }else { diff --git a/src/components/Schema.ejs b/src/components/Schema.ejs index 6e2925a..8b9f2a0 100644 --- a/src/components/Schema.ejs +++ b/src/components/Schema.ejs @@ -1,6 +1,7 @@ <% if(schemaName && hideTitle === false ) { %>

    <%= schemaName %>

    <% } %> +
    @@ -16,12 +17,12 @@ <% if ( schema && !(schemaName.indexOf('x-parser-')> -1 || schemaName.indexOf('x-schema-private-') > -1) ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema, schemaName, 'root'); %> - - - - - - + + + + + + <% const dependentSchemas = schemaHelper.getDependentSchemas(schema); const extensions = schemaHelper.getCustomExtensions(schema); @@ -34,12 +35,12 @@ <% if ( property && !(propertyName.indexOf('x-parser-')> -1 || propertyName.indexOf('x-schema-private-') > -1) ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(property, propertyName, required.includes(propertyName), schemaHelper.getDependentRequired(propertyName,schema), buildPath((path || schemaName), propertyName)); %> - - - - - - + + + + + + <% } %> <% } %> @@ -47,11 +48,11 @@ <% if ( property && !(propertyName.indexOf('x-parser-')> -1 || propertyName.indexOf('x-schema-private-') > -1) ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(property, propertyName, false, [], buildPath((path || schemaName), propertyName), 'pattern property'); %> - - - - - + + + + + <% } %> @@ -70,12 +71,12 @@ <% if ( property && !(propertyName.indexOf('x-parser-')> -1 || propertyName.indexOf('x-schema-private-') > -1) ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(property, propertyName, required.includes(propertyName), schemaHelper.getDependentRequired(propertyName,items), buildPath((path || ""), propertyName)); %> - - - - - - + + + + + + <% } %> <% } %> @@ -83,12 +84,12 @@ <% if ( property && !(propertyName.indexOf('x-parser-')> -1 || propertyName.indexOf('x-schema-private-') > -1) ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(property, propertyName, false, [], path, 'Single Item'); %> - - - - - - + + + + + + <% } %> <% } %> @@ -99,12 +100,12 @@ if ( item ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(item, "", false, [], buildPath(path || "", idx), 'index'); %> - - - - - - + + + + + + <% } %> <% }) %> @@ -113,12 +114,12 @@ <% if ( items ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(items, "", false, [], path, 'Single Item'); %> - - - - - - + + + + + + <% } %> <% } %> @@ -130,12 +131,12 @@ if ( s && !(idx.indexOf('x-parser-')> -1 || idx.indexOf('x-schema-private-') > -1) ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(s, idx, false, [], buildPath(path || schemaName, idx), 'oneOf item'); %> - - - - - - + + + + + + <% } %> <% }) %> @@ -143,12 +144,12 @@ if ( s && !(idx.indexOf('x-parser-')> -1 || idx.indexOf('x-schema-private-') > -1) ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(s, idx, false, [], buildPath(path || schemaName, idx), 'anyOf item'); %> - - - - - - + + + + + + <% } %> <% }) %> @@ -156,101 +157,101 @@ if ( s && !(idx.indexOf('x-parser-')> -1 || idx.indexOf('x-schema-private-') > -1) ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(s, idx, false, [], buildPath(path || schemaName, idx), 'allOf item'); %> - - - - - - + + + + + + <% } %> <% }) %> <% if ( schema.not() ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.not(), "", false, [], path,'not', false); %> - - - - - - + + + + + + <% } %> <% if ( schema.propertyNames() ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.propertyNames(), "", false, [], path,'property names', false); %> - - - - - - + + + + + + <% } %> <% if ( schema.contains() ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.contains(), "", false, [], path,'contains', false); %> - - - - - - + + + + + + <% } %> <% if ( schema.if() ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.if(), "", false, [], path,'if', false); %> - - - - - - + + + + + + <% } %> <% if ( schema.then() ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.then(), "", false, [], path,'then', false); %> - - - - - - + + + + + + <% } %> <% if ( schema.else() ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(schema.else(), "", false, [], path,'else', false); %> - - - - - - + + + + + + <% } %> <% if ( dependentSchemas ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(dependentSchemas, "", false, [], path,'dependant schemas'); %> - - - - - - + + + + + + <% } %> <% if ( extensionsSchema ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(extensionsSchema, "", false, [], path); %> - - - - - - + + + + + + <% } %> <% const ext = schema.extensions(); @@ -263,12 +264,12 @@ if ( additionalProperties ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(additionalProperties, "", false, [], path,'additional properties', false); %> - - - - - - + + + + + + <% } %> <% } %> @@ -284,12 +285,12 @@ if ( additionalItems ) { const [renderedName, schemaType, description, values, constraints, notes] = schemaPropRow(additionalItems, "", false, [], path,'additional items', false); %> - - - - - - + + + + + + <% } %> <% } %> @@ -300,7 +301,7 @@ <% } %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %> <%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %><%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    <%- (renderedName || '-') %> <%- (schemaType || '-') %> <%- (md.render(description) || '-') %> <%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %> <%- (renderedName || '-') %> <%- (schemaType || '-') %><%- (md.render(description) || '-') %><%- (values || '-') %><%- (constraints || '-') %><%- (notes || '-') %>
    - +
    <% function schemaPropRow( schema, schemaName, required = false, dependentRequired = [], path = '', nameNote = '',tryRenderAdditionalNotes = true) { const isCircular = schema.isCircular() || false; const extensions = schema.extensions(); diff --git a/src/components/Security.ejs b/src/components/Security.ejs index 79ba76f..53eeb15 100644 --- a/src/components/Security.ejs +++ b/src/components/Security.ejs @@ -35,6 +35,7 @@
  • OpenID Connect URL: <%= schema.split('_')[2] %>
  • <% }else if(schema.split('_')[0] == 'RequiredScopes'){ %>
  • Required Scopes: <%= schema.split('_')[1]? schema.split('_')[1]: 'Nil' %>
  • +
    @@ -48,15 +49,16 @@ <% for(let entry of JSON.parse(schema.split('_')[2])){ %> - - - - - + + + + + <% } %>
    <%= entry[0] %><%= entry[1] %><%= entry[2] %><%= entry[3] %><%= entry[4] %><%= entry[0] %><%= entry[1] %><%= entry[2] %><%= entry[3] %><%= entry[4] %>
    +
    <% }else { %>
  • <%= schema %>
  • <% } %> diff --git a/src/components/Servers.ejs b/src/components/Servers.ejs index ed729bc..286481b 100644 --- a/src/components/Servers.ejs +++ b/src/components/Servers.ejs @@ -13,6 +13,7 @@ <% } %>

    URL Variables

    +
    @@ -25,23 +26,23 @@ <% for(let entry of server.variables().all()){ %> - - + + <% if(entry.hasDefaultValue()){ %> - + <% }else { %> - + <% } %> <% if(entry.hasAllowedValues()){ %> - + <% }else { %> - + <% } %> <% } %>
    <%= entry.id() %><%= entry.description() %><%= entry.id() %><%= entry.description() %><%= entry.defaultValue() %><%= entry.defaultValue() %>_None__None_<%= entry.allowedValues().map(value => value).join(', ') %><%= entry.allowedValues().map(value => value).join(', ') %>_Any__Any_
    - +
    <%- include(securityPath,{ header:null, protocol: server.protocol(), security: server.security(), serverHelper, md }) %> <%- include(tagsPath,{ name:"Tags", tags: server.tags() }) %> diff --git a/src/components/Tags.ejs b/src/components/Tags.ejs index 7b44372..47e077c 100644 --- a/src/components/Tags.ejs +++ b/src/components/Tags.ejs @@ -1,5 +1,6 @@ <% if(tags && !tags.isEmpty()) { %>
    <%= name %>
    +
    @@ -11,17 +12,17 @@ <% for(let entry of tags.all()){ %> - - + + <% if(entry.externalDocs()){ %> - + <% }else { %> - + <% } %> <% } %>
    <%= entry.name() %><%= entry.description() %><%= entry.name() %><%= entry.description() %><%= entry.externalDocs() && entry.externalDocs().hasDescription() ? entry.externalDocs().description() : 'Find more info here' %><%= entry.externalDocs() && entry.externalDocs().hasDescription() ? entry.externalDocs().description() : 'Find more info here' %>--
    - +
    <% } %> From e29110f934dfd8d4ee13d91dca6dfdb162d97f81 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Sun, 10 Mar 2024 13:15:22 +0530 Subject: [PATCH 06/15] add markdown-it Signed-off-by: nikhilkalburgi --- package-lock.json | 32 -------------------------------- package.json | 1 + 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8f54d12..7cf26d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,7 @@ "license": "Apache-2.0", "dependencies": { "@asyncapi/parser": "^3.0.7", - "@types/markdown-it": "^13.0.7", "ejs": "^3.1.9", - "eta": "^3.2.0", "markdown-it": "^14.0.0", "mermaid": "^10.8.0" }, @@ -743,20 +741,6 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, - "node_modules/@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==" - }, - "node_modules/@types/markdown-it": { - "version": "13.0.7", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.7.tgz", - "integrity": "sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==", - "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, "node_modules/@types/mdast": { "version": "3.0.15", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", @@ -765,11 +749,6 @@ "@types/unist": "^2" } }, - "node_modules/@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==" - }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -3150,17 +3129,6 @@ "node": ">=0.10.0" } }, - "node_modules/eta": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eta/-/eta-3.2.0.tgz", - "integrity": "sha512-Qzc3it7nLn49dbOb9+oHV9rwtt9qN8oShRztqkZ3gXPqQflF0VLin5qhWk0g/2ioibBwT4DU6OIMVft7tg/rVg==", - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "url": "https://github.com/eta-dev/eta?sponsor=1" - } - }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", diff --git a/package.json b/package.json index 3c65ef1..d5211a7 100644 --- a/package.json +++ b/package.json @@ -148,6 +148,7 @@ "dependencies": { "@asyncapi/parser": "^3.0.7", "ejs": "^3.1.9", + "markdown-it": "^14.0.0", "mermaid": "^10.8.0" } } From c3adf7c9cad5c0a74ed75650ae3f053301ede075 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Fri, 10 May 2024 20:32:17 +0530 Subject: [PATCH 07/15] add diagnostics for incorrect spec --- package-lock.json | 23 ++++ package.json | 1 + src/Asyncapi.ts | 3 +- src/Diagnostics.ts | 35 +++++ src/PreviewMarkdown.ts | 171 ++----------------------- src/components/Diagnostics.ejs | 21 +++ src/globals.css | 227 +++++++++++++++++++++++++++++++++ webpack.config.js | 4 + 8 files changed, 326 insertions(+), 159 deletions(-) create mode 100644 src/Diagnostics.ts create mode 100644 src/components/Diagnostics.ejs create mode 100644 src/globals.css diff --git a/package-lock.json b/package-lock.json index 7cf26d6..6a826bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@types/ejs": "^3.1.5", "@types/glob": "^7.2.0", "@types/js-yaml": "^4.0.5", + "@types/markdown-it": "^13.0.7", "@types/mocha": "^9.1.1", "@types/node": "14.x", "@types/vscode": "^1.66.0", @@ -741,6 +742,22 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, + "node_modules/@types/linkify-it": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "13.0.7", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.7.tgz", + "integrity": "sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==", + "dev": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, "node_modules/@types/mdast": { "version": "3.0.15", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", @@ -749,6 +766,12 @@ "@types/unist": "^2" } }, + "node_modules/@types/mdurl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "dev": true + }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", diff --git a/package.json b/package.json index d5211a7..6312be9 100644 --- a/package.json +++ b/package.json @@ -128,6 +128,7 @@ "@types/ejs": "^3.1.5", "@types/glob": "^7.2.0", "@types/js-yaml": "^4.0.5", + "@types/markdown-it": "^13.0.7", "@types/mocha": "^9.1.1", "@types/node": "14.x", "@types/vscode": "^1.66.0", diff --git a/src/Asyncapi.ts b/src/Asyncapi.ts index bacef3b..dd654a1 100644 --- a/src/Asyncapi.ts +++ b/src/Asyncapi.ts @@ -3,7 +3,6 @@ import * as vscode from 'vscode'; import * as ejs from 'ejs'; import * as path from 'path'; import * as Markdownit from 'markdown-it'; -import { Server } from 'http'; import { sample } from 'openapi-sampler'; const md = Markdownit('commonmark'); @@ -609,7 +608,7 @@ class MessageHelper { } } -export default async function info(asyncapi:AsyncAPIDocumentInterface, context: vscode.ExtensionContext) { +export default async function asyncapiMarkdown(asyncapi:AsyncAPIDocumentInterface, context: vscode.ExtensionContext) { const info = asyncapi.info(); diff --git a/src/Diagnostics.ts b/src/Diagnostics.ts new file mode 100644 index 0000000..5d24ec1 --- /dev/null +++ b/src/Diagnostics.ts @@ -0,0 +1,35 @@ +import { ISpectralDiagnostic } from '@stoplight/spectral-core'; +import * as vscode from 'vscode'; +import * as ejs from 'ejs'; +import * as path from 'path'; + +export default async function diagnosticsMarkdown(diagnostics: ISpectralDiagnostic[], context: vscode.ExtensionContext){ + const templatePath = path.join(context.extensionPath,'dist', 'components','Diagnostics.ejs'); + let data: object[] = []; + let recentErrorPath: string = ""; + let joinedPath: string = ""; + diagnostics.forEach(diagnostic =>{ + joinedPath = diagnostic.path.join(' / '); + console.log(joinedPath, recentErrorPath, data.length); + if(joinedPath.indexOf(recentErrorPath) === -1 || !recentErrorPath){ + recentErrorPath = joinedPath; + data.push({ + code: diagnostic.code, + message: diagnostic.message, + path: recentErrorPath, + severity: diagnostic.severity, + source: diagnostic.source + }); + }else{ + recentErrorPath = joinedPath; + data[data.length - 1] = { + code: diagnostic.code, + message: diagnostic.message, + path: recentErrorPath, + severity: diagnostic.severity, + source: diagnostic.source + }; + } + }); + return await ejs.renderFile(templatePath, {data}); +} \ No newline at end of file diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts index 98cf2bb..9ea5908 100644 --- a/src/PreviewMarkdown.ts +++ b/src/PreviewMarkdown.ts @@ -3,18 +3,22 @@ import * as path from 'path'; import { isAsyncAPIFile } from './PreviewWebPanel'; import { Parser, fromFile, AsyncAPIDocumentInterface } from '@asyncapi/parser'; import Asyncapi from './Asyncapi'; +import { ISpectralDiagnostic } from '@stoplight/spectral-core'; +import Diagnostics from './Diagnostics'; const parser = new Parser(); -async function buildMarkdown(document:AsyncAPIDocumentInterface | undefined, context: vscode.ExtensionContext){ +async function buildMarkdown(document:AsyncAPIDocumentInterface | undefined, diagnostics: ISpectralDiagnostic[], context: vscode.ExtensionContext){ let content = ''; if(document !== undefined){ content = await Asyncapi(document, context); + }else{ + content = await Diagnostics(diagnostics, context); } return content; @@ -36,7 +40,8 @@ export const openAsyncapiMdFiles: { [id: string]: vscode.WebviewPanel } = {}; // export async function openAsyncAPIMarkdown(context: vscode.ExtensionContext, uri: vscode.Uri) { const localResourceRoots = [ vscode.Uri.file(path.dirname(uri.fsPath)), - vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/mermaid/dist/mermaid.min.js') + vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/mermaid/dist/mermaid.min.js'), + vscode.Uri.joinPath(context.extensionUri, 'dist/globals.css') ]; if (vscode.workspace.workspaceFolders) { vscode.workspace.workspaceFolders.forEach(folder => { @@ -51,8 +56,9 @@ export async function openAsyncAPIMarkdown(context: vscode.ExtensionContext, uri localResourceRoots, }); - const { document } = await fromFile(parser, uri.fsPath).parse(); - let result = await buildMarkdown(document, context); + const { document, diagnostics } = await fromFile(parser, uri.fsPath).parse(); + console.log(diagnostics); + let result = await buildMarkdown(document, diagnostics, context); panel.title = path.basename(uri.fsPath); panel.webview.html = getWebviewContent(context, panel.webview, uri, result); @@ -83,164 +89,15 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web const mermaidJs = webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/mermaid/dist/mermaid.min.js') ); + const globalsCss = webview.asWebviewUri( + vscode.Uri.joinPath(context.extensionUri, 'dist/globals.css') + ); const html = ` - + diff --git a/src/components/Diagnostics.ejs b/src/components/Diagnostics.ejs new file mode 100644 index 0000000..8f47733 --- /dev/null +++ b/src/components/Diagnostics.ejs @@ -0,0 +1,21 @@ +

    Error Loading Preview

    +<% data.forEach(diagnostic => { %> +
    + <% if(diagnostic.severity == 0) { %> +
    + <% } else if(diagnostic.severity == 1) { %> +
    + <% }else if(diagnostic.severity == 2) { %> +
    + <% }else if(diagnostic.severity == 3) { %> +
    + <% } %> +
    +

    ⚠️<%= diagnostic.message %>

    +

    <%= diagnostic.path %>

    +
    <%= diagnostic.code %>
    +

    Source: <%= diagnostic.source %>

    +

    Severity: <%= diagnostic.severity %>

    +
    +
    +<% }) %> \ No newline at end of file diff --git a/src/globals.css b/src/globals.css new file mode 100644 index 0000000..564602a --- /dev/null +++ b/src/globals.css @@ -0,0 +1,227 @@ +html{ + scroll-behavior: smooth; +} +body { + color: #121212; + background-color: #efefef; + word-wrap: break-word; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + height: 100vh; +} +h1 { + color: #121212; +} +.container { + display: flex; + overflow-x: hidden; +} +.section { + flex: 0 0 100%; + box-sizing: border-box; + padding: 20px; + aspect-ratio: 1; + overflow-y: auto; + height:calc(100vh - 60px);; +} +.button-container { + display: flex; + justify-content: center; + margin: 10px; +} +.button { + padding: 10px 20px; + margin: 0px 10px; + border-radius: .5rem; + color: #444; + font-size: 1rem; + font-weight: 700; + letter-spacing: .1rem; + cursor: pointer; + flex:1; + border: none; + outline: none; + transition: .2s ease-in-out; + box-shadow: -6px -6px 14px rgba(255, 255, 255, .7), + -6px -6px 10px rgba(255, 255, 255, .5), + 6px 6px 8px rgba(255, 255, 255, .075), + 6px 6px 10px rgba(0, 0, 0, .15); +} +button:hover { + box-shadow: -2px -2px 6px rgba(255, 255, 255, .6), + -2px -2px 4px rgba(255, 255, 255, .4), + 2px 2px 2px rgba(255, 255, 255, .05), + 2px 2px 4px rgba(0, 0, 0, .1); +} +button:active { + box-shadow: inset -2px -2px 6px rgba(255, 255, 255, .7), + inset -2px -2px 4px rgba(255, 255, 255, .5), + inset 2px 2px 2px rgba(255, 255, 255, .075), + inset 2px 2px 4px rgba(0, 0, 0, .15); +} +.table-container{ + overflow-x:auto; +} +table { + width: 100%; + border-collapse: collapse; + margin-top: 20px; +} +th, td { + padding: 12px; + text-align: left; + border-bottom: 1px solid #ddd; +} +th { + background-color: black; + color: white; +} +tr:nth-child(even) { + background-color: #fefefe; +} +code { + display: block; + padding: 10px; + background-color: #282c34; + color: #abb2bf; + border-radius: 5px; + margin-bottom: 20px; + margin-top: 20px; + white-space: pre-wrap; +} +blockquote { + border-left: 4px solid #61dafb; + margin: 0; + margin-top: 20px; + padding: 10px 20px; + background-color: #fff; + color: #333; +} +a { + text-decoration: none; + color: #3498db; + font-weight: bold; + transition: color 0.3s ease-in-out; +} +a:hover { + color: #1abc9c; +} + +@media screen and (max-width: 600px) { + table { + display: block; + } + + thead, tbody, th, td, tr { + display: block; + } + + th { + position: absolute; + top: -9999px; + left: -9999px; + } + + td { + border: none; + position: relative; + padding-left: 50%; + white-space: nowrap; + } + + td:before { + position: absolute; + top: 12px; + left: 6px; + width: 45%; + padding-right: 10px; + white-space: nowrap; + content: attr(data-th) ": "; + font-weight: bold; + } + code { + font-size: 14px; + } + + blockquote { + font-size: 16px; + } +} + +.diagnostic { + display: flex; + border: 1px solid #ccc; + border-radius: 10px; + padding: 20px; + margin-bottom: 20px; + background-color: #fff; + box-shadow: 5px 5px 15px #bcbcbc, -5px -5px 15px #ffffff; + transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; + overflow: hidden; +} + +.diagnostic:hover { + transform: translate(2px, 2px); + box-shadow: 7px 7px 20px #bcbcbc, -7px -7px 20px #ffffff; +} + +.left-bar { + width: 10px; + border-radius: 10px 0 0 10px; + display: inline-block; + vertical-align: top; + margin-right: 20px; +} + +.high { + background-color: #e74c3c; +} +.medium { + background-color: #d9720b; +} +.low { + background-color: #ebe80a; +} +.hint{ + background-color: #119adf; +} + +.content-box { + flex-grow: 1; +} + +.message { + font-size: 18px; + font-weight: bold; + margin-bottom: 10px; +} + +.secondary-text { + color: #666; + font-size: 14px; + margin-bottom: 10px; +} + +.icon { + font-size: 24px; + color: #e74c3c; + margin-right: 10px; + vertical-align: middle; +} + +.code { + font-family: monospace; + white-space: pre-wrap; + background-color: #f9f9f9; + padding: 10px; + border-radius: 5px; + margin-top: 10px; +} + +.source { + font-style: italic; + color: #999; + margin-top: 10px; +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index c1ca2b3..28e6bc2 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -67,6 +67,10 @@ const extensionConfig = { { from: 'src/components', to: 'components' + }, + { + from:'src/globals.css', + to:'globals.css' } ], }), From 154c78096939653b2cb132bcedc7cbea3aeb3533 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Mon, 20 May 2024 21:42:09 +0530 Subject: [PATCH 08/15] fix: add the incorrect specs preview enhancement --- .gitignore | 1 + package-lock.json | 89 ++---- package.json | 7 +- src/Asyncapi.ts | 454 ++++++++++++++++++++++++++++++- src/PreviewMarkdown.ts | 57 +++- src/components/Diagnostics.ejs | 3 +- src/components/Info.ejs | 4 +- src/components/Info.ts | 61 ----- src/components/MermaidDiagram.ts | 7 - src/components/Message.ejs | 79 +++++- src/components/Security.ejs | 1 + src/components/Servers.ejs | 2 +- src/components/Tags.ejs | 6 +- src/globals.css | 27 +- webpack.config.js | 4 - 15 files changed, 619 insertions(+), 183 deletions(-) delete mode 100644 src/components/Info.ts delete mode 100644 src/components/MermaidDiagram.ts diff --git a/.gitignore b/.gitignore index 5f8d342..fa47056 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules .vscode-test/ *.vsix .DS_Store +package-lock.json \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index aae7fcf..cb75292 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,17 +10,18 @@ "license": "Apache-2.0", "dependencies": { "@asyncapi/parser": "^3.0.7", + "@types/markdown-it": "^13.0.7", "ejs": "^3.1.9", + "js-yaml": "^4.1.0", "markdown-it": "^14.0.0", "mermaid": "^10.8.0", - "@types/markdown-it": "^13.0.7" + "yaml": "^2.4.2" }, "devDependencies": { "@asyncapi/react-component": "^1.2.7", "@types/ejs": "^3.1.5", "@types/glob": "^7.2.0", - "@types/js-yaml": "^4.0.5", - "@types/markdown-it": "^13.0.7", + "@types/js-yaml": "^4.0.9", "@types/mocha": "^9.1.1", "@types/node": "14.x", "@types/vscode": "^1.66.0", @@ -733,9 +734,9 @@ } }, "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==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "dev": true }, "node_modules/@types/json-schema": { @@ -743,18 +744,15 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, - "node_modules/@types/linkify-it": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", - "dev": true + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==" }, "node_modules/@types/markdown-it": { "version": "13.0.7", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-13.0.7.tgz", "integrity": "sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==", - "dev": true, "dependencies": { "@types/linkify-it": "*", "@types/mdurl": "*" @@ -771,8 +769,7 @@ "node_modules/@types/mdurl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", - "dev": true + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==" }, "node_modules/@types/minimatch": { "version": "5.1.2", @@ -2075,7 +2072,6 @@ "node": ">=12" } }, - "node_modules/d3-brush": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", @@ -2091,7 +2087,6 @@ "node": ">=12" } }, - "node_modules/d3-chord": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", @@ -2111,7 +2106,6 @@ "node": ">=12" } }, - "node_modules/d3-contour": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", @@ -2119,7 +2113,6 @@ "dependencies": { "d3-array": "^3.2.0" }, - "engines": { "node": ">=12" } @@ -2549,14 +2542,6 @@ "robust-predicates": "^3.0.2" } }, - "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", - "dependencies": { - "robust-predicates": "^3.0.2" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2582,14 +2567,6 @@ "node": ">=6" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "engines": { - "node": ">=6" - } - }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -2672,20 +2649,6 @@ "node": ">=0.10.0" } }, - "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/electron-to-chromium": { "version": "1.4.283", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.283.tgz", @@ -2697,11 +2660,6 @@ "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.2.tgz", "integrity": "sha512-2Y/RaA1pdgSHpY0YG4TYuYCD2wh97CRvu22eLG3Kz0pgQ/6KbIFTxsTnDc4MH/6hFlg2L/9qXrDMG0nMjP63iw==" }, - "node_modules/elkjs": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.2.tgz", - "integrity": "sha512-2Y/RaA1pdgSHpY0YG4TYuYCD2wh97CRvu22eLG3Kz0pgQ/6KbIFTxsTnDc4MH/6hFlg2L/9qXrDMG0nMjP63iw==" - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -3407,20 +3365,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/fstream": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", @@ -4938,7 +4882,6 @@ "micromark-util-symbol": "^1.0.0" } }, - "node_modules/micromark-util-decode-string": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", @@ -4959,7 +4902,6 @@ "micromark-util-decode-numeric-character-reference": "^1.0.0", "micromark-util-symbol": "^1.0.0" } - }, "node_modules/micromark-util-encode": { "version": "1.1.0", @@ -4990,7 +4932,6 @@ "url": "https://opencollective.com/unified" } ] - }, "node_modules/micromark-util-normalize-identifier": { "version": "1.1.0", @@ -5083,7 +5024,6 @@ "url": "https://opencollective.com/unified" } ] - }, "node_modules/micromark-util-types": { "version": "1.1.0", @@ -7235,6 +7175,17 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index b19a03d..964f24c 100644 --- a/package.json +++ b/package.json @@ -127,8 +127,6 @@ "@asyncapi/react-component": "^1.2.7", "@types/ejs": "^3.1.5", "@types/glob": "^7.2.0", - "@types/js-yaml": "^4.0.5", - "@types/markdown-it": "^13.0.7", "@types/mocha": "^9.1.1", "@types/node": "14.x", "@types/vscode": "^1.66.0", @@ -148,9 +146,10 @@ }, "dependencies": { "@asyncapi/parser": "^3.0.7", + "@types/markdown-it": "^13.0.7", "ejs": "^3.1.9", "markdown-it": "^14.0.0", - "mermaid": "^10.8.0" - "@types/markdown-it": "^13.0.7", + "mermaid": "^10.8.0", + "yaml": "^2.4.2" } } diff --git a/src/Asyncapi.ts b/src/Asyncapi.ts index dd654a1..8252eed 100644 --- a/src/Asyncapi.ts +++ b/src/Asyncapi.ts @@ -4,6 +4,8 @@ import * as ejs from 'ejs'; import * as path from 'path'; import * as Markdownit from 'markdown-it'; import { sample } from 'openapi-sampler'; +import { description, hasDescription } from '@asyncapi/parser/esm/old-api/mixins'; +import { bindings } from '@asyncapi/parser/esm/models/v3/mixins'; const md = Markdownit('commonmark'); @@ -22,7 +24,6 @@ const jsonSchemaTypes: string[] = [ 'null', ]; -const RESTRICTED_ANY = 'restricted any'; const NEVER = 'never'; const UNKNOWN = 'unknown'; const ANY = 'any'; @@ -318,7 +319,7 @@ class SchemaHelper { return; } - for (const [prop, array] of Object.entries(dependencies)) { + for (const [prop, array] of Object.entries(dependencies || {})) { if (Array.isArray(array) && array.includes(propertyName)) { dependentRequired.push(prop); } @@ -333,7 +334,7 @@ class SchemaHelper { } const records:any = {}; - for (const [prop, propSchema] of Object.entries(dependencies)) { + for (const [prop, propSchema] of Object.entries(dependencies || {})) { if (typeof propSchema === 'object' && !Array.isArray(propSchema)) { records[String(prop)] = propSchema; } @@ -344,7 +345,7 @@ class SchemaHelper { const json:object = { type: 'object', - properties: Object.entries(records).reduce( + properties: Object.entries(records || {}).reduce( (obj:any, [propertyName, propertySchema]:any[]) => { obj[String(propertyName)] = Object.assign({}, propertySchema.json()); return obj; @@ -413,7 +414,7 @@ class SchemaHelper { } return { type: 'object', - properties: Object.entries(value).reduce((obj:any, [k, v]) => { + properties: Object.entries(value || {}).reduce((obj:any, [k, v]) => { obj[String(k)] = this.jsonFieldToSchema(v); return obj; }, {}), @@ -608,12 +609,446 @@ class MessageHelper { } } -export default async function asyncapiMarkdown(asyncapi:AsyncAPIDocumentInterface, context: vscode.ExtensionContext) { +function addServers(asyncapi: any){ + return { + isEmpty: ()=> (asyncapi.servers)? false : true, + all: ()=>{ + return Object.entries(asyncapi.servers || {}).map((server: any)=>{ + return{ + id: ()=> server[0], + url: ()=> (server[1] && server[1].host)? server[1].host : "", + protocol: ()=> (server[1] && server[1].protocol)? server[1].protocol : "", + protocolVersion: ()=> "", + hasDescription: ()=> (server[1] && server[1].description)? true : false, + description: ()=> (server[1])? server[1].description : "", + variables: ()=> (server[1] && server[1].variables)? {all: ()=> Object.entries(server[1].variables || {}).map((entry: any)=>{ + return { + id: ()=> (entry[0])? entry[0] : "", + description: ()=> (entry[1] && entry[1].description)? entry[1].description : "", + hasDefaultValue: ()=> (entry[1] && entry[1].default)? true : false, + defaultValue: ()=> (entry[1] && entry[1].default)? entry[1].default : "", + hasAllowedValues: ()=> (entry[1] && entry[1].enum)? true : false, + allowedValues: ()=> (entry[1] && entry[1].enum)? entry[1].enum : [] + + }; + }) }: "", + security: ()=> { + return server[1].security?.map( (sec: any)=>{ + return { + all: ()=> Object.entries(sec || {}).map((security: any)=>{ + return { + scheme: ()=>{ + return { + type: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()])? asyncapi.components.securitySchemes[security[1].split('/').pop()].type : "", + hasDescription: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()] && asyncapi.components.securitySchemes[security[1].split('/').pop()].description )? true : false, + description: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].description, + name: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].name, + in: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].in, + bearerFormat: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].bearerFormat, + openIdConnectUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].openIdConnectUrl, + scheme: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].scheme, + flows: ()=> { + if(!asyncapi.components.securitySchemes[security[1].split('/').pop()].flows) {return;} + return { + authorizationCode: ()=> { return { + authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode.authorizationUrl, + refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.refreshUrl, + tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.tokenUrl, + scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.availableScopes || [] + };}, + clientCredentials: ()=> { return { + authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.authorizationUrl, + refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.refreshUrl, + tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.tokenUrl, + scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.availableScopes || [] + };}, + implicit: ()=> { return { + authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.authorizationUrl, + refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.refreshUrl, + tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.tokenUrl, + scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.availableScopes || [] + };}, + password: ()=> { return { + authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.authorizationUrl, + refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.refreshUrl, + tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.tokenUrl, + scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.availableScopes || [] + };} + }; + } + }; + }, + scopes: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()])? asyncapi.components.securitySchemes[security[1].split('/').pop()].scopes || [] : "" + }; + }) + }; + }); + }, + extensions: ()=> { + return { + all: ()=> Object.entries(server[1].extensions || {}).map((extension: any)=>{ + return { + id: ()=> extension[1].id, + value: ()=> extension[1].value + }; + }) + }; + }, + bindings: ()=>{ + return { + isEmpty: ()=> (server[1].bindings)? false : true, + all: ()=> { + return Object.entries(server[1].bindings || {}).map((binding : any)=>{ + return { + protocol: ()=> (binding[1] && binding[1].protocol)? binding[1].protocol : "", + json: ()=> (binding[1] && binding[1].json)? binding[1].json : "", + type: ()=> (binding[1] && binding[1].type)? binding[1].type : "" + }; + }); + } + }; + }, + tags: ()=> { + return { + isEmpty: ()=> (server[1].tags)? false : true, + all: ()=> Object.entries(server[1].tags || {}).map((tag: any)=>{ + return { + name: ()=> (tag[1] && tag[1].name)? tag[1].name : "", + description: ()=> (tag[1] && tag[1].description)? tag[1].description : "", + externalDocs: ()=> (tag[1] && tag[1].externalDocs)? { + url: ()=> tag[1].externalDocs.url, + description: ()=> tag[1].externalDocs.description + } : "" + + }; + }) + }; + } + }; + }); + } + }; +} + +export default async function asyncapiMarkdown(asyncapi: any, context: vscode.ExtensionContext) { + const templatePath = path.join(context.extensionPath,'dist', 'components','Asyncapi.ejs'); + if(!asyncapi.isAsyncapiParser){ + return await ejs.renderFile(templatePath, { + info: { + title: (asyncapi.info && asyncapi.info.title)? asyncapi.info.title : "", + version: (asyncapi.info && asyncapi.info.version)? asyncapi.info.version : "", + defaultContentType: (asyncapi.defaultContentType)? asyncapi.defaultContentType : "", + specId: asyncapi.info && (asyncapi.info.specId)? asyncapi.info.specId : "", + termsOfService: (asyncapi.info && asyncapi.info.termsOfService)? asyncapi.info.termsOfService : "", + license: (asyncapi.info && asyncapi.info.license)? {url: ()=> asyncapi.info.license.url, name: ()=> asyncapi.info.license.name} : null, + contact: (asyncapi.info && asyncapi.info.contact)? {name: ()=> asyncapi.info.contact.name, url: ()=> asyncapi.info.contact.url, email: asyncapi.info.contact.email} : null, + externalDocs: (asyncapi.info && asyncapi.info.externalDocs)? {url: ()=> asyncapi.info.externalDocs.url(), description: ()=> asyncapi.info.externalDocs.description()} : null, + hasDescription: (asyncapi.info && asyncapi.info.description)? true: false, + description:(asyncapi.info)? md.render(asyncapi.info.description || "") : "", + tags: { + isEmpty: ()=> (asyncapi.info.tags)? false : true, + all: ()=> Object.entries(asyncapi.info.tags || {}).map((tag: any)=>{ + return { + name: ()=> (tag[1] && tag[1].name)? tag[1].name : "", + description: ()=> (tag[1] && tag[1].description)? tag[1].description : "", + externalDocs: ()=> (tag[1] && tag[1].externalDocs)? { + url: ()=> tag[1].externalDocs.url, + description: ()=> tag[1].externalDocs?.description, + hasDescription: ()=> tag[1].externalDocs?.description? true : false + } : "" + }; + }) + } + }, + servers:{ + servers: addServers(asyncapi), + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + md + }, + operations:{ + channels: { + isEmpty: ()=> (asyncapi.channels)? false : true, + all: ()=> Object.entries(asyncapi.channels || {}).map((channel: any)=>{ + return { + servers: ()=> addServers(asyncapi), + operations: ()=> { + return { + all: ()=> Object.entries(asyncapi.operations || {}).filter((operation: any)=> operation[1].channel?.$ref.split('channels/').pop().replaceAll('~1','/') === channel[0]).map((operation: any)=>{ + return { + operationId: ()=> (operation[0])? operation[0] : "", + isSend: ()=> (operation[1] && operation[1].action === 'send')? true : false, + isReceive: ()=> (operation[1] && operation[1].action === 'receive')? true : false, + reply: ()=> (operation[1] && operation[1].reply)? operation[1].reply : false, + summary: ()=> (operation[1] && operation[1].summary)? operation[1].summary : "", + hasDescription: ()=> (operation[1] && operation[1].description)? true : false, + description: ()=> (operation[1] && operation[1].description)? operation[1].description : "", + externalDocs: ()=> (operation[1] && operation[1].externalDocs)? { + url: ()=> operation[1].externalDocs.url, + description: ()=> operation[1].externalDocs.description, + hasDescription: ()=> operation[1].externalDocs.description? true : false + } : "", + tags: ()=> { + return { + isEmpty: ()=> (operation[1].tags)? false : true, + all: ()=> Object.entries(operation[1].tags || {}).map((tag: any)=>{ + return { + name: ()=> (tag[1] && tag[1].name)? tag[1].name : "", + description: ()=> (tag[1] && tag[1].description)? tag[1].description : "", + externalDocs: ()=> (tag[1] && tag[1].externalDocs)? { + url: ()=> tag[1].externalDocs?.url, + description: ()=> tag[1].externalDocs?.description, + hasDescription: ()=> tag[1].externalDocs?.description? true : false + } : "" + + }; + }) + }; + }, + extensions: ()=> { + return { + all: ()=> Object(operation[1].extensions).map((extension: any)=>{ + return { + id: ()=> extension[1].id, + value: ()=> extension[1].value + }; + }) + }; + }, + bindings: ()=>{ + return { + isEmpty: ()=> (operation[1].bindings)? false : true, + all: ()=> { + return Object.entries(operation[1].bindings || {}).map((binding : any)=>{ + return { + protocol: ()=> (binding[1] && binding[1].protocol)? binding[1].protocol : "", + json: ()=> (binding[1] && binding[1].json)? binding[1].json : "", + type: ()=> (binding[1] && binding[1].type)? binding[1].type : "" + }; + }); + } + }; + }, + security: ()=> { + return operation[1].security?.map( (sec: any)=>{ + return { + all: ()=> Object.entries(sec || {}).map((security: any)=>{ + return { + scheme: ()=>{ + return { + type: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()])? asyncapi.components.securitySchemes[security[1].split('/').pop()].type : "", + hasDescription: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()] && asyncapi.components.securitySchemes[security[1].split('/').pop()].description )? true : false, + description: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].description, + name: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].name, + in: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].in, + bearerFormat: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].bearerFormat, + openIdConnectUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].openIdConnectUrl, + scheme: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].scheme, + flows: ()=> { + if(!asyncapi.components.securitySchemes[security[1].split('/').pop()].flows) {return;} + return { + authorizationCode: ()=> { return { + authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode.authorizationUrl, + refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.refreshUrl, + tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.tokenUrl, + scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.availableScopes || [] + };}, + clientCredentials: ()=> { return { + authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.authorizationUrl, + refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.refreshUrl, + tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.tokenUrl, + scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.availableScopes || [] + };}, + implicit: ()=> { return { + authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.authorizationUrl, + refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.refreshUrl, + tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.tokenUrl, + scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.availableScopes || [] + };}, + password: ()=> { return { + authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.authorizationUrl, + refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.refreshUrl, + tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.tokenUrl, + scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.availableScopes || [] + };} + }; + } + }; + }, + scopes: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()])? asyncapi.components.securitySchemes[security[1].split('/').pop()].scopes || [] : "" + }; + }) + }; + }); + }, + messages: ()=>{ + return { + all: ()=>{ + let tmp: any = Object.values(operation[1].messages); + if(tmp[0]?.$ref) { + return [{incorrect: true, refs: Object.values(operation[1].messages)}]; + } + return Object.entries(operation[1].messages|| {}).map((message: any)=>{ + return { + id: ()=> message[0], + title: ()=> message[1].title, + name: ()=> message[1].name, + hasDescription: ()=> (message[1].description)? true : false, + description: ()=> message[1].description, + contentType: ()=> message[1].contentType, + summary: ()=> message[1].summary, + correlationId: ()=> { + return { + location: ()=> message[1].correlationId?.location, + hasDescription: ()=> message[1].correlationId? true : false, + description: ()=> message[1].correlationId?.description + }; + }, + externalDocs: ()=> { + return { + url: ()=> message[1].externalDocs?.url, + description: ()=> message[1].externalDocs?.description + }; + }, + headers: ()=> { + return { + incorrect: true, + ...message[1].headers + }; + }, + payload: ()=> { + return { + incorrect: true, + ...message[1].payload + }; + }, + tags: ()=> { + return { + isEmpty: ()=> (operation[1].tags)? false : true, + all: ()=> Object.entries(operation[1].tags || {}).map((tag: any)=>{ + return { + name: ()=> (tag[1] && tag[1].name)? tag[1].name : "", + description: ()=> (tag[1] && tag[1].description)? tag[1].description : "", + externalDocs: ()=> (tag[1] && tag[1].externalDocs)? { + url: ()=> tag[1].externalDocs.url, + description: ()=> tag[1].externalDocs?.description, + hasDescription: ()=> tag[1].externalDocs?.description? true : false + } : "" + + }; + }) + }; + }, + extensions: ()=> { + return { + all: ()=> Object.entries(message[1].extensions || {}).map((extension: any)=>{ + return { + id: ()=> extension[1].id, + value: ()=> extension[1].value + }; + }) + }; + }, + bindings: ()=>{ + return { + isEmpty: ()=> (message[1].bindings)? false : true, + all: ()=> { + return Object.entries(message[1].bindings || {}).map((binding : any)=>{ + return { + protocol: ()=> (binding[1] && binding[1].protocol)? binding[1].protocol : "", + json: ()=> (binding[1] && binding[1].json)? binding[1].json : "", + type: ()=> (binding[1] && binding[1].type)? binding[1].type : "" + }; + }); + } + }; + } + }; + }); + } + }; + } + }; + }), + + }; + }, + address: ()=> (channel[1])? channel[1].address : "", + hasDescription: ()=> (channel[1] && channel[1].description)? true : false, + description: ()=> (channel[1] && channel[1].description)? channel[1].description : "", + parameters: ()=> { + return { + all: ()=> Object.entries(channel[1].parameters || {}).map((parameter: any)=> { + return { + id: ()=> parameter[0], + schema: ()=> { + return { + json: ()=>{ + return{ + type: parameter[1].schema?.type, + title: parameter[1].schema?.title, + required: parameter[1].schema?.required + }; + } + }; + }, + description: ()=>parameter[1].description, + location: ()=>parameter[1].location + }; + }) + }; + }, + extensions: ()=> { + return { + all: ()=> Object.entries(channel[1].extensions || {}).map((extension: any)=>{ + return { + id: ()=> extension[1].id, + value: ()=> extension[1].value + }; + }) + }; + }, + bindings: ()=>{ + return { + isEmpty: ()=> (channel[1].bindings)? false : true, + all: ()=> { + return Object.entries(channel[1].bindings || {}).map((binding : any)=>{ + return { + protocol: ()=> (binding[1] && binding[1].protocol)? binding[1].protocol : "", + json: ()=> (binding[1] && binding[1].json)? binding[1].json : "", + type: ()=> (binding[1] && binding[1].type)? binding[1].type : "" + }; + }); + } + }; + } + + }; + }) + }, + isV3: (asyncapi.asyncapi)? asyncapi.asyncapi.split('.')[0] === '3' : true, + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + messageHelper: MessageHelper, + allServersLength: (asyncapi.servers)? Object.keys(asyncapi.servers).length : 0, + md + }, + path:{ + infoPath: path.join(context.extensionPath,'dist', 'components','Info.ejs'), + tagsPath: path.join(context.extensionPath,'dist', 'components','Tags.ejs'), + serversPath: path.join(context.extensionPath,'dist', 'components','Servers.ejs'), + securityPath: path.join(context.extensionPath,'dist', 'components','Security.ejs'), + bindingsPath: path.join(context.extensionPath,'dist', 'components','Bindings.ejs'), + extensionsPath: path.join(context.extensionPath,'dist', 'components','Extensions.ejs'), + schemaPath: path.join(context.extensionPath,'dist', 'components','Schema.ejs'), + operationsPath: path.join(context.extensionPath,'dist', 'components','Operations.ejs'), + messagePath: path.join(context.extensionPath,'dist', 'components','Message.ejs') + } + }); + }else{ const info = asyncapi.info(); - const templatePath = path.join(context.extensionPath,'dist', 'components','Asyncapi.ejs'); - return await ejs.renderFile(templatePath, { info: { title: info.title(), @@ -657,4 +1092,7 @@ export default async function asyncapiMarkdown(asyncapi:AsyncAPIDocumentInterfac messagePath: path.join(context.extensionPath,'dist', 'components','Message.ejs') } }); + } + + } \ No newline at end of file diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts index 9ea5908..3e819d5 100644 --- a/src/PreviewMarkdown.ts +++ b/src/PreviewMarkdown.ts @@ -1,27 +1,70 @@ import * as vscode from 'vscode'; import * as path from 'path'; +import * as fs from 'fs'; import { isAsyncAPIFile } from './PreviewWebPanel'; +import Diagnostics from './Diagnostics'; import { Parser, fromFile, AsyncAPIDocumentInterface } from '@asyncapi/parser'; import Asyncapi from './Asyncapi'; import { ISpectralDiagnostic } from '@stoplight/spectral-core'; -import Diagnostics from './Diagnostics'; +import { parse } from 'yaml'; + +function delay(ms: number | undefined) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + + function parsedAsyncapiPreview(){ + const editor: any = vscode.window.activeTextEditor; + if(!editor) {return;} + const document = editor.document; + const filePath: any = document?.fileName; + const fullPath = path.resolve(filePath); + const content = fs.readFileSync(fullPath, 'utf8'); + + let parsedData; + if (filePath.endsWith('.json')) { + parsedData = JSON.parse(content); + } else if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) { + parsedData = parse(content); + } else { + vscode.window.showInformationMessage('Unsupported file type.'); + return; + } + + return parsedData; +} const parser = new Parser(); -async function buildMarkdown(document:AsyncAPIDocumentInterface | undefined, diagnostics: ISpectralDiagnostic[], context: vscode.ExtensionContext){ +async function buildMarkdown(document: any, diagnostics: ISpectralDiagnostic[], context: vscode.ExtensionContext){ + let content = ''; if(document !== undefined){ - + vscode.window.onDidChangeActiveTextEditor(()=>null); + document.isAsyncapiParser = true; content = await Asyncapi(document, context); }else{ content = await Diagnostics(diagnostics, context); + vscode.window.onDidChangeActiveTextEditor(async()=>{ + + let parsedData: any = parsedAsyncapiPreview(); + if(parsedData){ + parsedData.isAsyncapiParser = false; + content += await Asyncapi(parsedData, context); + } + }); + let parsedData: any = parsedAsyncapiPreview(); + if(parsedData){ + parsedData.isAsyncapiParser = false; + content += await Asyncapi(parsedData, context); + } } return content; + } export function previewMarkdown(context: vscode.ExtensionContext) { @@ -56,10 +99,10 @@ export async function openAsyncAPIMarkdown(context: vscode.ExtensionContext, uri localResourceRoots, }); - const { document, diagnostics } = await fromFile(parser, uri.fsPath).parse(); - console.log(diagnostics); + const { document, diagnostics } = await fromFile(parser, uri.fsPath).parse(); let result = await buildMarkdown(document, diagnostics, context); + panel.title = path.basename(uri.fsPath); panel.webview.html = getWebviewContent(context, panel.webview, uri, result); @@ -89,7 +132,7 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web const mermaidJs = webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/mermaid/dist/mermaid.min.js') ); - const globalsCss = webview.asWebviewUri( + const globalsCSS = webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'dist/globals.css') ); @@ -97,7 +140,7 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web - + diff --git a/src/components/Diagnostics.ejs b/src/components/Diagnostics.ejs index 8f47733..4494827 100644 --- a/src/components/Diagnostics.ejs +++ b/src/components/Diagnostics.ejs @@ -9,7 +9,8 @@
    <% }else if(diagnostic.severity == 3) { %>
    - <% } %> + <% } %> +

    ⚠️<%= diagnostic.message %>

    <%= diagnostic.path %>

    diff --git a/src/components/Info.ejs b/src/components/Info.ejs index a4d499c..9ac28ce 100644 --- a/src/components/Info.ejs +++ b/src/components/Info.ejs @@ -1,7 +1,5 @@

    <%= title %> <%= version %> documentation

    -<% if(extensions && extensions.has('x-logo')) { %> -  logo -<% } %> +
      <% if (specId) { %>
    • diff --git a/src/components/Info.ts b/src/components/Info.ts deleted file mode 100644 index 87a6c72..0000000 --- a/src/components/Info.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {AsyncAPIDocumentInterface } from '@asyncapi/parser'; - -export default function info(asyncapi:AsyncAPIDocumentInterface) { - - const info = asyncapi.info(); - const defaultContentType = asyncapi.defaultContentType(); - const specId = info.id(); - const termsOfService = info.termsOfService(); - const license = info.license(); - const contact = info.contact(); - const externalDocs = info.externalDocs(); - const extensions: any = info.extensions(); - - const infoList = []; - if (specId) { - infoList.push(`Specification ID: \`${specId}\``); - } - if (license) { - infoList.push(license.url() ? ( - `License: [${license.name()}](${license.url()})` - ) : `License: ${license.name()}`); - } - if (termsOfService) { - infoList.push( - `[${termsOfService}](${termsOfService})` - ); - } - if (defaultContentType) { - infoList.push( - `Default content type: [${defaultContentType}](https://www.iana.org/assignments/media-types/${defaultContentType})` - ); - } - if (contact) { - if (contact.url()) { - infoList.push( - `Support: [${contact.url()}](${contact.name() || 'Link'})` - ); - } - if (contact.email()) { - infoList.push( - `Email support: [${`mailto:${contact.email()}`}](${contact.email()})` - ); - } - } - - return ( - ` -# ${info.title()} ${info.version()} documentation - -${ - infoList.map((value)=>{ - return '\n* '+ value; - }) -} - -![${info.title()}](${(extensions.get('x-logo'))?extensions.get('x-logo').value():null}) - - -#### ${info.description()} - `); -} \ No newline at end of file diff --git a/src/components/MermaidDiagram.ts b/src/components/MermaidDiagram.ts deleted file mode 100644 index 179d866..0000000 --- a/src/components/MermaidDiagram.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {AsyncAPIDocumentInterface } from '@asyncapi/parser'; - -export default function mermaidDiagram(asyncapi:AsyncAPIDocumentInterface){ - - - return ``; -} \ No newline at end of file diff --git a/src/components/Message.ejs b/src/components/Message.ejs index 7986a83..f03f183 100644 --- a/src/components/Message.ejs +++ b/src/components/Message.ejs @@ -1,4 +1,4 @@ -<% if (message) { +<% if (message && !message.incorrect) { const messageId = message.id(); const headers = message.headers(); const payload = message.payload(); @@ -35,11 +35,11 @@ <% if(correlationId) { %>
      • - Correlation ID: <%= correlationId.location() %> + Correlation ID: <%= correlationId?.location() %>
      • - <% if(correlationId.hasDescription()) { %> + <% if(correlationId?.hasDescription()) { %>
        - <%- md.render(correlationId.description()) %> + <%- md.render(correlationId?.description()) %> <% } %>
      <% } %> @@ -49,15 +49,15 @@ <%- md.render(message.description()) %> <% } %> - <% if(externalDocs) { %> - - <%- md.render(externalDocs.description() || 'Find more info here.') %> + <% if(externalDocs && externalDocs?.url()) { %> + + <%- md.render(externalDocs?.description() || 'Find more info here.') %> <% } %> - <% if(headers) { %> + <% if(headers && !headers.incorrect) { %>
      Headers
      - <%- include(schemaPath,{schema:headers,schemaName:"", hideTitle:true, schemaHelper, md, path:""}) %> + <%- include(schemaPath,{schema:headers.schema? headers.schema : headers,schemaName:"", hideTitle:true, schemaHelper, md, path:""}) %> <% const ex = messageHelper.getHeadersExamples(message); if (ex) { %>
      Examples of headers
      @@ -76,11 +76,34 @@ <% } %> <% } %> - <% } %> + <% }else if(headers && headers.incorrect) { %> + <% function renderHeaderObject(obj, indent) { %> + <% for (let key in obj) { %> + <% if (key != 'incorrect') { %> + <% if (typeof obj[key] === 'object' && obj[key] !== null) { %> +
      > + <%= key %>: +
      + <%= renderHeaderObject(obj[key], indent + 20) %> +
      +
      + <% } else { %> +
      > + <%= key %>: + <%= obj[key] %> +
      + <% } %> + <% } %> + <% } %> + <% } %> +
      + <%= renderHeaderObject(headers, 0) %> +
      + <% } %> - <% if(payload) { %> + <% if(payload && !payload.incorrect) { %>
      Payload
      - <%- include(schemaPath,{schema:payload, schemaName:"", hideTitle:true, schemaHelper, md, path:""}) %> + <%- include(schemaPath,{schema:payload.schema? payload.schema : payload, schemaName:"", hideTitle:true, schemaHelper, md, path:""}) %> <% const examples = messageHelper.getPayloadExamples(message); if (examples) { %>
      Examples of payload
      @@ -100,10 +123,40 @@ <% } %> - <% } %> + <% }else if(payload && payload.incorrect) { %> + <% function renderPayloadObject(obj, indent) { %> + <% for (let key in obj) { %> + <% if(key != 'incorrect') { %> + <% if (typeof obj[key] === 'object' && obj[key] !== null) { %> +
      > + <%= key %>: +
      + <%= renderPayloadObject(obj[key], indent + 20) %> +
      +
      + <% } else { %> +
      > + <%= key %>: + <%= obj[key] %> +
      + <% } %> + <% } %> + <% } %> + <% } %> +
      + <%= renderPayloadObject(payload, 0) %> +
      + <% } %> <%- include(bindingsPath,{name:"Message specific information", bindings:message.bindings(), schemaHelper, schemaPath}) %> <%- include(extensionsPath,{name:"Message extensions", extensions:message.extensions(), schemaHelper, schemaPath}) %> <%- include(tagsPath,{name:"Message tags", tags:message.tags()}) %> +<% }else if(message && message.incorrect) { %> +

      Message

      +
        + <% for (let ref of message.refs) { %> +
      • <%= `${Object.values(ref || {})[0].split('/')[2]?.replaceAll('~1',' / ')} / ${Object.values(ref || {})[0].split('/').pop()}` %>
      • + <% } %> +
      <% } %> diff --git a/src/components/Security.ejs b/src/components/Security.ejs index 53eeb15..c359b9f 100644 --- a/src/components/Security.ejs +++ b/src/components/Security.ejs @@ -108,6 +108,7 @@ function flowsRenderer([flowName, flow]) { + console.log(flow); return [serverHelper.flowName(flowName) || '-', (flow?.authorizationUrl() ? flow.authorizationUrl() : '-'), (flow?.tokenUrl() ? flow.tokenUrl() : '-'), (flow?.refreshUrl() ? flow.refreshUrl() : '-'), Object.keys(flow?.scopes() || {}).length ? Object.keys(flow.scopes()).map(v => `\`${v}\``).join(', ') : '-' ]; } function renderSecuritySchemasFlows({ securitySchema, requiredScopes, schemas }) { diff --git a/src/components/Servers.ejs b/src/components/Servers.ejs index 286481b..fe4709b 100644 --- a/src/components/Servers.ejs +++ b/src/components/Servers.ejs @@ -27,7 +27,7 @@ <% for(let entry of server.variables().all()){ %> <%= entry.id() %> - <%= entry.description() %> + <%= entry.description() %> <% if(entry.hasDefaultValue()){ %> <%= entry.defaultValue() %> <% }else { %> diff --git a/src/components/Tags.ejs b/src/components/Tags.ejs index 47e077c..56548e2 100644 --- a/src/components/Tags.ejs +++ b/src/components/Tags.ejs @@ -12,9 +12,9 @@ <% for(let entry of tags.all()){ %> - <%= entry.name() %> - <%= entry.description() %> - <% if(entry.externalDocs()){ %> + <%= entry.name() || '-' %> + <%= entry.description() || '-' %> + <% if(entry.externalDocs() && entry.externalDocs().url()){ %> <%= entry.externalDocs() && entry.externalDocs().hasDescription() ? entry.externalDocs().description() : 'Find more info here' %> <% }else { %> - diff --git a/src/globals.css b/src/globals.css index 564602a..0b6a2be 100644 --- a/src/globals.css +++ b/src/globals.css @@ -117,7 +117,9 @@ a:hover { thead, tbody, th, td, tr { display: block; } - + td { + background-color: #efefef; + } th { position: absolute; top: -9999px; @@ -151,6 +153,7 @@ a:hover { } .diagnostic { + position: relative; display: flex; border: 1px solid #ccc; border-radius: 10px; @@ -168,7 +171,7 @@ a:hover { } .left-bar { - width: 10px; + width: 7px; border-radius: 10px 0 0 10px; display: inline-block; vertical-align: top; @@ -224,4 +227,24 @@ a:hover { font-style: italic; color: #999; margin-top: 10px; +} + +.close-btn { + position: absolute; + top: 10px; + right: 10px; + background: none; + border: none; + font-size: 16px; + cursor: pointer; +} + +.nested-object { + margin-left: 20px; +} +.key { + font-weight: bold; +} +.value { + color: blue; } \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index f24ea73..efee6b9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -67,10 +67,6 @@ const extensionConfig = { { from: 'src/components', to: 'components' - }, - { - from:'src/globals.css', - to:'globals.css' } ], From e1072e0348050a2ed5fdfe2f0f8f6fdec9c93002 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Wed, 22 May 2024 19:18:42 +0530 Subject: [PATCH 09/15] fix in webpack config --- package-lock.json | 3 +-- package.json | 1 + webpack.config.js | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb75292..c43acdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,6 @@ "@asyncapi/parser": "^3.0.7", "@types/markdown-it": "^13.0.7", "ejs": "^3.1.9", - "js-yaml": "^4.1.0", "markdown-it": "^14.0.0", "mermaid": "^10.8.0", "yaml": "^2.4.2" @@ -21,7 +20,7 @@ "@asyncapi/react-component": "^1.2.7", "@types/ejs": "^3.1.5", "@types/glob": "^7.2.0", - "@types/js-yaml": "^4.0.9", + "@types/js-yaml": "^4.0.5", "@types/mocha": "^9.1.1", "@types/node": "14.x", "@types/vscode": "^1.66.0", diff --git a/package.json b/package.json index 964f24c..008ed83 100644 --- a/package.json +++ b/package.json @@ -127,6 +127,7 @@ "@asyncapi/react-component": "^1.2.7", "@types/ejs": "^3.1.5", "@types/glob": "^7.2.0", + "@types/js-yaml": "^4.0.5", "@types/mocha": "^9.1.1", "@types/node": "14.x", "@types/vscode": "^1.66.0", diff --git a/webpack.config.js b/webpack.config.js index efee6b9..e3a84da 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -67,6 +67,10 @@ const extensionConfig = { { from: 'src/components', to: 'components' + }, + { + from: 'src/globals.css', + to: 'globals.css' } ], From 6f7304ef268304da68a793c9d02e29ac4ff98110 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Sun, 2 Jun 2024 13:13:04 +0530 Subject: [PATCH 10/15] add support for AVRO --- src/PreviewMarkdown.ts | 13 +++++-------- src/components/Message.ejs | 6 ++---- src/globals.css | 2 +- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts index 3e819d5..112aaef 100644 --- a/src/PreviewMarkdown.ts +++ b/src/PreviewMarkdown.ts @@ -4,14 +4,11 @@ import * as fs from 'fs'; import { isAsyncAPIFile } from './PreviewWebPanel'; import Diagnostics from './Diagnostics'; import { Parser, fromFile, AsyncAPIDocumentInterface } from '@asyncapi/parser'; +import { AvroSchemaParser } from '@asyncapi/avro-schema-parser'; import Asyncapi from './Asyncapi'; import { ISpectralDiagnostic } from '@stoplight/spectral-core'; import { parse } from 'yaml'; -function delay(ms: number | undefined) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - function parsedAsyncapiPreview(){ const editor: any = vscode.window.activeTextEditor; if(!editor) {return;} @@ -35,7 +32,7 @@ function delay(ms: number | undefined) { const parser = new Parser(); - +parser.registerSchemaParser(AvroSchemaParser()); async function buildMarkdown(document: any, diagnostics: ISpectralDiagnostic[], context: vscode.ExtensionContext){ @@ -83,8 +80,7 @@ export const openAsyncapiMdFiles: { [id: string]: vscode.WebviewPanel } = {}; // export async function openAsyncAPIMarkdown(context: vscode.ExtensionContext, uri: vscode.Uri) { const localResourceRoots = [ vscode.Uri.file(path.dirname(uri.fsPath)), - vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/mermaid/dist/mermaid.min.js'), - vscode.Uri.joinPath(context.extensionUri, 'dist/globals.css') + vscode.Uri.joinPath(context.extensionUri, 'dist') ]; if (vscode.workspace.workspaceFolders) { vscode.workspace.workspaceFolders.forEach(folder => { @@ -99,7 +95,8 @@ export async function openAsyncAPIMarkdown(context: vscode.ExtensionContext, uri localResourceRoots, }); - const { document, diagnostics } = await fromFile(parser, uri.fsPath).parse(); + const { document, diagnostics } = await fromFile(parser, uri.fsPath).parse(); + let result = await buildMarkdown(document, diagnostics, context); diff --git a/src/components/Message.ejs b/src/components/Message.ejs index f03f183..59acb08 100644 --- a/src/components/Message.ejs +++ b/src/components/Message.ejs @@ -23,7 +23,7 @@ <% } %> <% if(showInfoList) { %> -
      +
        <% if(messageId) { %>
      • Message ID: <%= messageId %>
      • <% } %> @@ -33,7 +33,6 @@ <% } %> <% if(correlationId) { %> -
        • Correlation ID: <%= correlationId?.location() %>
        • @@ -41,9 +40,8 @@
          <%- md.render(correlationId?.description()) %> <% } %> -
        <% } %> -
      +
    <% } %> <% if(message.hasDescription()) { %> <%- md.render(message.description()) %> diff --git a/src/globals.css b/src/globals.css index 0b6a2be..9cbe607 100644 --- a/src/globals.css +++ b/src/globals.css @@ -16,7 +16,7 @@ h1 { } .container { display: flex; - overflow-x: hidden; + overflow: hidden; } .section { flex: 0 0 100%; From 04b756b1cc95dfb92e7c9a5aef2561a701931a23 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Tue, 11 Jun 2024 13:03:44 +0530 Subject: [PATCH 11/15] feat: add flowchart and classDiagram --- package-lock.json | 34 + package.json | 5 +- .../icons/open-markdown-preview_black.svg | 19 + .../icons/open-markdown-preview_white.svg | 19 + src/Asyncapi.ts | 1332 +++++++++-------- src/ClassDiagram.ts | 363 +++++ src/Flowchart.ts | 103 ++ src/PreviewMarkdown.ts | 192 ++- src/components/classDiagram.ejs | 59 + src/components/flowchart.ejs | 26 + src/globals.css | 104 +- webpack.config.js | 4 + 12 files changed, 1644 insertions(+), 616 deletions(-) create mode 100644 resources/icons/open-markdown-preview_black.svg create mode 100644 resources/icons/open-markdown-preview_white.svg create mode 100644 src/ClassDiagram.ts create mode 100644 src/Flowchart.ts diff --git a/package-lock.json b/package-lock.json index c43acdd..5c2f920 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "ejs": "^3.1.9", "markdown-it": "^14.0.0", "mermaid": "^10.8.0", + "panzoom": "^9.4.3", "yaml": "^2.4.2" }, "devDependencies": { @@ -1400,6 +1401,14 @@ "ajv": "^8.8.2" } }, + "node_modules/amator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/amator/-/amator-1.1.0.tgz", + "integrity": "sha512-V5+aH8pe+Z3u/UG3L3pG3BaFQGXAyXHVQDroRwjPHdh08bcUEchAVsU1MCuJSCaU5o60wTK6KaE6te5memzgYw==", + "dependencies": { + "bezier-easing": "^2.0.3" + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -1534,6 +1543,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bezier-easing": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", + "integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==" + }, "node_modules/big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", @@ -5282,6 +5296,11 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/ngraph.events": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.2.2.tgz", + "integrity": "sha512-JsUbEOzANskax+WSYiAPETemLWYXmixuPAlmZmhIbIj6FH/WDgEGCGnRwUQBK0GjOnVm8Ui+e5IJ+5VZ4e32eQ==" + }, "node_modules/nimma": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/nimma/-/nimma-0.2.2.tgz", @@ -5472,6 +5491,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/panzoom": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.3.tgz", + "integrity": "sha512-xaxCpElcRbQsUtIdwlrZA90P90+BHip4Vda2BC8MEb4tkI05PmR6cKECdqUCZ85ZvBHjpI9htJrZBxV5Gp/q/w==", + "dependencies": { + "amator": "^1.1.0", + "ngraph.events": "^1.2.2", + "wheel": "^1.0.0" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7034,6 +7063,11 @@ "node": ">=10" } }, + "node_modules/wheel": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wheel/-/wheel-1.0.0.tgz", + "integrity": "sha512-XiCMHibOiqalCQ+BaNSwRoZ9FDTAvOsXxGHXChBugewDj7HC8VBIER71dEOiRH1fSdLbRCQzngKTSiZ06ZQzeA==" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 008ed83..05d9394 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ "command": "asyncapi.markdown", "title": "Preview Asyncapi Markdown", "icon": { - "light": "resources/icons/open-preview_black.svg", - "dark": "resources/icons/open-preview_white.svg" + "light": "resources/icons/open-markdown-preview_black.svg", + "dark": "resources/icons/open-markdown-preview_white.svg" } } ], @@ -151,6 +151,7 @@ "ejs": "^3.1.9", "markdown-it": "^14.0.0", "mermaid": "^10.8.0", + "panzoom": "^9.4.3", "yaml": "^2.4.2" } } diff --git a/resources/icons/open-markdown-preview_black.svg b/resources/icons/open-markdown-preview_black.svg new file mode 100644 index 0000000..c18526d --- /dev/null +++ b/resources/icons/open-markdown-preview_black.svg @@ -0,0 +1,19 @@ + + + +Created with Fabric.js 3.6.6 + + + + + + + + + + + + + M + + \ No newline at end of file diff --git a/resources/icons/open-markdown-preview_white.svg b/resources/icons/open-markdown-preview_white.svg new file mode 100644 index 0000000..33ff8bd --- /dev/null +++ b/resources/icons/open-markdown-preview_white.svg @@ -0,0 +1,19 @@ + + + +Created with Fabric.js 3.6.6 + + + + + + + + + + + + + M + + \ No newline at end of file diff --git a/src/Asyncapi.ts b/src/Asyncapi.ts index 8252eed..97b619e 100644 --- a/src/Asyncapi.ts +++ b/src/Asyncapi.ts @@ -1,28 +1,17 @@ -import {AsyncAPIDocumentInterface, SchemaV2 as SchemaModel } from '@asyncapi/parser'; +import { AsyncAPIDocumentInterface, SchemaV2 as SchemaModel } from '@asyncapi/parser'; import * as vscode from 'vscode'; import * as ejs from 'ejs'; import * as path from 'path'; import * as Markdownit from 'markdown-it'; import { sample } from 'openapi-sampler'; -import { description, hasDescription } from '@asyncapi/parser/esm/old-api/mixins'; -import { bindings } from '@asyncapi/parser/esm/models/v3/mixins'; const md = Markdownit('commonmark'); - const extRenderType = 'x-schema-private-render-type'; const extRenderAdditionalInfo = 'x-schema-private-render-additional-info'; const extRawValue = 'x-schema-private-raw-value'; const extParameterLocation = 'x-schema-private-parameter-location'; -const jsonSchemaTypes: string[] = [ - 'string', - 'number', - 'integer', - 'boolean', - 'array', - 'object', - 'null', -]; +const jsonSchemaTypes: string[] = ['string', 'number', 'integer', 'boolean', 'array', 'object', 'null']; const NEVER = 'never'; const UNKNOWN = 'unknown'; @@ -55,15 +44,14 @@ const jsonSchemaKeywordTypes = { }; class SchemaHelper { - - static toSchemaType(schema: { json: () => boolean; isBooleanSchema: () => any; not: () => any; }):any { + static toSchemaType(schema: { json: () => boolean; isBooleanSchema: () => any; not: () => any }): any { if (!schema || typeof schema.json !== 'function') { return UNKNOWN; } if (schema.isBooleanSchema()) { if (schema.json() === true) { return ANY; - } + } return NEVER; } // handle case with `{}` schemas @@ -92,7 +80,10 @@ class SchemaHelper { return type; } - static toType(type: string, schema: { json?: () => boolean; isBooleanSchema?: () => any; not?: () => any; items?: any; additionalItems?: any; }) { + static toType( + type: string, + schema: { json?: () => boolean; isBooleanSchema?: () => any; not?: () => any; items?: any; additionalItems?: any } + ) { if (type === 'array') { const items = schema.items(); if (Array.isArray(items)) { @@ -115,7 +106,14 @@ class SchemaHelper { return type; } - static toCombinedType(schema: { json?: () => boolean; isBooleanSchema?: () => any; not?: () => any; oneOf?: any; anyOf?: any; allOf?: any; }) { + static toCombinedType(schema: { + json?: () => boolean; + isBooleanSchema?: () => any; + not?: () => any; + oneOf?: any; + anyOf?: any; + allOf?: any; + }) { const t = []; if (schema.oneOf()) { t.push('oneOf'); @@ -132,7 +130,17 @@ class SchemaHelper { return t[0]; } - static inferType(schema: { json: any; isBooleanSchema?: (() => any) | (() => any) | undefined; not?: (() => any) | (() => any) | undefined; type?: any; const?: any; enum?: any; oneOf?: any; anyOf?: any; allOf?: any; }) { + static inferType(schema: { + json: any; + isBooleanSchema?: (() => any) | (() => any) | undefined; + not?: (() => any) | (() => any) | undefined; + type?: any; + const?: any; + enum?: any; + oneOf?: any; + anyOf?: any; + allOf?: any; + }) { let types = schema.type(); if (types !== undefined) { @@ -156,20 +164,22 @@ class SchemaHelper { } const enumValue = schema.enum(); if (Array.isArray(enumValue) && enumValue.length) { - const inferredType = Array.from(new Set(enumValue.map(e => { - const typeOf = typeof e; - if (typeOf === 'number' && Number.isInteger(e)) { - return 'integer'; - } - return typeOf; - }))); + const inferredType = Array.from( + new Set( + enumValue.map(e => { + const typeOf = typeof e; + if (typeOf === 'number' && Number.isInteger(e)) { + return 'integer'; + } + return typeOf; + }) + ) + ); return inferredType.length === 1 ? inferredType[0] : inferredType; } const schemaKeys = Object.keys(schema.json() || {}) || []; - const hasInferredTypes = Object.keys(jsonSchemaKeywordTypes).some(key => - schemaKeys.includes(key), - ); + const hasInferredTypes = Object.keys(jsonSchemaKeywordTypes).some(key => schemaKeys.includes(key)); if (hasInferredTypes === true) { return ''; } @@ -179,7 +189,7 @@ class SchemaHelper { return ANY; } - static prettifyValue(value: { toString: () => any; }) { + static prettifyValue(value: { toString: () => any }) { const typeOf = typeof value; if (typeOf === 'string') { return `"${value}"`; @@ -193,7 +203,20 @@ class SchemaHelper { return JSON.stringify(value); } - static humanizeConstraints(schema: { minimum: () => undefined; exclusiveMinimum: () => undefined; maximum: () => undefined; exclusiveMaximum: () => undefined; multipleOf: () => { toString: (arg0: number) => any; } | undefined; minLength: () => number | undefined; maxLength: () => undefined; uniqueItems: () => any; minItems: () => number | undefined; maxItems: () => undefined; minProperties: () => number | undefined; maxProperties: () => undefined; }) { + static humanizeConstraints(schema: { + minimum: () => undefined; + exclusiveMinimum: () => undefined; + maximum: () => undefined; + exclusiveMaximum: () => undefined; + multipleOf: () => { toString: (arg0: number) => any } | undefined; + minLength: () => number | undefined; + maxLength: () => undefined; + uniqueItems: () => any; + minItems: () => number | undefined; + maxItems: () => undefined; + minProperties: () => number | undefined; + maxProperties: () => undefined; + }) { const constraints = []; // related to number/integer @@ -201,45 +224,31 @@ class SchemaHelper { schema.minimum(), schema.exclusiveMinimum(), schema.maximum(), - schema.exclusiveMaximum(), + schema.exclusiveMaximum() ); if (numberRange !== undefined) { constraints.push(numberRange); } - const multipleOfConstraint = this.humanizeMultipleOfConstraint( - schema.multipleOf(), - ); + const multipleOfConstraint = this.humanizeMultipleOfConstraint(schema.multipleOf()); if (multipleOfConstraint !== undefined) { constraints.push(multipleOfConstraint); } // related to string - const stringRange = this.humanizeRangeConstraint( - 'characters', - schema.minLength(), - schema.maxLength(), - ); + const stringRange = this.humanizeRangeConstraint('characters', schema.minLength(), schema.maxLength()); if (stringRange !== undefined) { constraints.push(stringRange); } // related to array const hasUniqueItems = schema.uniqueItems(); - const arrayRange = this.humanizeRangeConstraint( - hasUniqueItems ? 'unique items' : 'items', - schema.minItems(), - schema.maxItems(), - ); + const arrayRange = this.humanizeRangeConstraint(hasUniqueItems ? 'unique items' : 'items', schema.minItems(), schema.maxItems()); if (arrayRange !== undefined) { constraints.push(arrayRange); } // related to object - const objectRange = this.humanizeRangeConstraint( - 'properties', - schema.minProperties(), - schema.maxProperties(), - ); + const objectRange = this.humanizeRangeConstraint('properties', schema.minProperties(), schema.maxProperties()); if (objectRange !== undefined) { constraints.push(objectRange); } @@ -247,12 +256,7 @@ class SchemaHelper { return constraints; } - static humanizeNumberRangeConstraint( - min: undefined, - exclusiveMin: undefined, - max: undefined, - exclusiveMax: undefined, - ) { + static humanizeNumberRangeConstraint(min: undefined, exclusiveMin: undefined, max: undefined, exclusiveMax: undefined) { const hasExclusiveMin = exclusiveMin !== undefined; const hasMin = min !== undefined || hasExclusiveMin; const hasExclusiveMax = exclusiveMax !== undefined; @@ -275,24 +279,18 @@ class SchemaHelper { return numberRange; } - static humanizeMultipleOfConstraint( - multipleOf: { toString: (arg0: number) => any; } | undefined, - ) { + static humanizeMultipleOfConstraint(multipleOf: { toString: (arg0: number) => any } | undefined) { if (multipleOf === undefined) { return; } const strigifiedMultipleOf = multipleOf.toString(10); - if (!(/^0\.0*1$/).test(strigifiedMultipleOf)) { + if (!/^0\.0*1$/.test(strigifiedMultipleOf)) { return `multiple of ${strigifiedMultipleOf}`; } return `decimal places <= ${strigifiedMultipleOf.split('.')[1].length}`; } - static humanizeRangeConstraint( - description: any, - min: number | undefined, - max: undefined, - ) { + static humanizeRangeConstraint(description: any, min: number | undefined, max: undefined) { let stringRange; if (min !== undefined && max !== undefined) { if (min === max) { @@ -312,7 +310,7 @@ class SchemaHelper { return stringRange; } - static getDependentRequired(propertyName: string, schema: { dependencies: () => any; }) { + static getDependentRequired(propertyName: string, schema: { dependencies: () => any }) { const dependentRequired = []; const dependencies = schema.dependencies(); if (!dependencies) { @@ -327,13 +325,13 @@ class SchemaHelper { return dependentRequired.length ? dependentRequired : undefined; } - static getDependentSchemas(schema: { dependencies: () => any; }) { + static getDependentSchemas(schema: { dependencies: () => any }) { const dependencies = schema.dependencies(); if (!dependencies) { return; } - const records:any = {}; + const records: any = {}; for (const [prop, propSchema] of Object.entries(dependencies || {})) { if (typeof propSchema === 'object' && !Array.isArray(propSchema)) { records[String(prop)] = propSchema; @@ -343,39 +341,32 @@ class SchemaHelper { return undefined; } - const json:object = { + const json: object = { type: 'object', - properties: Object.entries(records || {}).reduce( - (obj:any, [propertyName, propertySchema]:any[]) => { - obj[String(propertyName)] = Object.assign({}, propertySchema.json()); - return obj; - }, - {}, - ), + properties: Object.entries(records || {}).reduce((obj: any, [propertyName, propertySchema]: any[]) => { + obj[String(propertyName)] = Object.assign({}, propertySchema.json()); + return obj; + }, {}), [extRenderType]: false, [extRenderAdditionalInfo]: false, }; return new SchemaModel(json); } - + static parametersToSchema(parameters: any[]) { if (parameters.length === 0) { return; } - const json:object = { + const json: object = { type: 'object', - properties: parameters.reduce( - (obj, parameter) => { - const parameterName = parameter.id(); - obj[String(parameterName)] = Object.assign({}, parameter.schema() === undefined ? {type: 'string'} : parameter.schema().json()); - obj[String(parameterName)].description = - parameter.description() || obj[String(parameterName)].description; - obj[String(parameterName)][extParameterLocation] = parameter.location(); - return obj; - }, - {}, - ), + properties: parameters.reduce((obj, parameter) => { + const parameterName = parameter.id(); + obj[String(parameterName)] = Object.assign({}, parameter.schema() === undefined ? { type: 'string' } : parameter.schema().json()); + obj[String(parameterName)].description = parameter.description() || obj[String(parameterName)].description; + obj[String(parameterName)][extParameterLocation] = parameter.location(); + return obj; + }, {}), required: parameters.map(parameter => parameter.id()), [extRenderType]: false, [extRenderAdditionalInfo]: false, @@ -392,8 +383,7 @@ class SchemaHelper { }; } if (typeof value !== 'object') { - const str = - typeof value.toString === 'function' ? value.toString() : value; + const str = typeof value.toString === 'function' ? value.toString() : value; return { type: 'string', const: str, @@ -414,7 +404,7 @@ class SchemaHelper { } return { type: 'object', - properties: Object.entries(value || {}).reduce((obj:any, [k, v]) => { + properties: Object.entries(value || {}).reduce((obj: any, [k, v]) => { obj[String(k)] = this.jsonFieldToSchema(v); return obj; }, {}), @@ -435,9 +425,7 @@ class SchemaHelper { if ( value && typeof value === 'object' && - (jsonSchemaTypes.includes(value.type) || - (Array.isArray(value.type) && - value.type.some((t: string) => !jsonSchemaTypes.includes(t)))) + (jsonSchemaTypes.includes(value.type) || (Array.isArray(value.type) && value.type.some((t: string) => !jsonSchemaTypes.includes(t)))) ) { return true; } @@ -447,12 +435,9 @@ class SchemaHelper { static getCustomExtensions(item: any): Record { try { const extensions = item.extensions().all(); - return extensions.reduce((acc: { [x: string]: any; }, ext: { id: () => any; value: () => any; }) => { + return extensions.reduce((acc: { [x: string]: any }, ext: { id: () => any; value: () => any }) => { const extName = ext.id(); - if ( - !extName.startsWith('x-parser-') && - !extName.startsWith('x-schema-private-') - ) { + if (!extName.startsWith('x-parser-') && !extName.startsWith('x-schema-private-')) { acc[String(extName)] = ext.value(); } return acc; @@ -466,53 +451,53 @@ class SchemaHelper { class ServerHelper { static securityType(value: string) { switch (value) { - case 'apiKey': - return 'API key'; - case 'oauth2': - return 'OAuth2'; - case 'openIdConnect': - return 'Open ID'; - case 'http': - return 'HTTP'; - case 'userPassword': - return 'User/Password'; - case 'X509': - return 'X509'; - case 'symmetricEncryption': - return 'Symmetric Encription'; - case 'asymmetricEncryption': - return 'Asymmetric Encription'; - case 'httpApiKey': - return 'HTTP API key'; - case 'scramSha256': - return 'ScramSha256'; - case 'scramSha512': - return 'ScramSha512'; - case 'gssapi': - return 'GSSAPI'; - case 'plain': - return 'PLAIN'; - default: - return 'API key'; + case 'apiKey': + return 'API key'; + case 'oauth2': + return 'OAuth2'; + case 'openIdConnect': + return 'Open ID'; + case 'http': + return 'HTTP'; + case 'userPassword': + return 'User/Password'; + case 'X509': + return 'X509'; + case 'symmetricEncryption': + return 'Symmetric Encription'; + case 'asymmetricEncryption': + return 'Asymmetric Encription'; + case 'httpApiKey': + return 'HTTP API key'; + case 'scramSha256': + return 'ScramSha256'; + case 'scramSha512': + return 'ScramSha512'; + case 'gssapi': + return 'GSSAPI'; + case 'plain': + return 'PLAIN'; + default: + return 'API key'; } } static flowName(value: string) { switch (value) { - case 'implicit': - return 'Implicit'; - case 'password': - return 'Password'; - case 'clientCredentials': - return 'Client credentials'; - case 'authorizationCode': - return 'Authorization Code'; - default: - return 'Implicit'; + case 'implicit': + return 'Implicit'; + case 'password': + return 'Password'; + case 'clientCredentials': + return 'Client credentials'; + case 'authorizationCode': + return 'Authorization Code'; + default: + return 'Implicit'; } } - static getKafkaSecurity(protocol: string, securitySchema: { type: () => any; }) { + static getKafkaSecurity(protocol: string, securitySchema: { type: () => any }) { let securityProtocol; let saslMechanism; if (protocol === 'kafka') { @@ -528,24 +513,24 @@ class ServerHelper { } if (securitySchema) { switch (securitySchema.type()) { - case 'plain': - saslMechanism = 'PLAIN'; - break; - case 'scramSha256': - saslMechanism = 'SCRAM-SHA-256'; - break; - case 'scramSha512': - saslMechanism = 'SCRAM-SHA-512'; - break; - case 'oauth2': - saslMechanism = 'OAUTHBEARER'; - break; - case 'gssapi': - saslMechanism = 'GSSAPI'; - break; - case 'X509': - securityProtocol = 'SSL'; - break; + case 'plain': + saslMechanism = 'PLAIN'; + break; + case 'scramSha256': + saslMechanism = 'SCRAM-SHA-256'; + break; + case 'scramSha512': + saslMechanism = 'SCRAM-SHA-512'; + break; + case 'oauth2': + saslMechanism = 'OAUTHBEARER'; + break; + case 'gssapi': + saslMechanism = 'GSSAPI'; + break; + case 'X509': + securityProtocol = 'SSL'; + break; } } @@ -554,12 +539,14 @@ class ServerHelper { } class MessageHelper { - static getPayloadExamples(message: { examples: () => { (): any; new(): any; all: { (): any; new(): any; }; }; payload: () => any; }) { + static getPayloadExamples(message: { examples: () => { (): any; new (): any; all: { (): any; new (): any } }; payload: () => any }) { const examples = message.examples().all(); if (Array.isArray(examples) && examples.some(e => e.payload())) { const messageExamples = examples .map(e => { - if (!e.payload()) {return;} + if (!e.payload()) { + return; + } return { name: e.name(), summary: e.summary(), @@ -567,24 +554,26 @@ class MessageHelper { }; }) .filter(Boolean); - + if (messageExamples.length > 0) { return messageExamples; } } - + const payload = message.payload(); if (payload?.examples()) { return payload.examples().map((example: any) => ({ example })); } } - - static getHeadersExamples(message: { examples: () => { (): any; new(): any; all: { (): any; new(): any; }; }; headers: () => any; }) { + + static getHeadersExamples(message: { examples: () => { (): any; new (): any; all: { (): any; new (): any } }; headers: () => any }) { const examples = message.examples().all(); if (Array.isArray(examples) && examples.some(e => e.headers())) { const messageExamples = examples .map(e => { - if (!e.headers()) {return;} + if (!e.headers()) { + return; + } return { name: e.name(), summary: e.summary(), @@ -592,12 +581,12 @@ class MessageHelper { }; }) .filter(Boolean); - + if (messageExamples.length > 0) { return messageExamples; } } - + const headers = message.headers(); if (headers?.examples()) { return headers.examples().map((example: any) => ({ example })); @@ -609,490 +598,633 @@ class MessageHelper { } } -function addServers(asyncapi: any){ +function addServers(asyncapi: any) { return { - isEmpty: ()=> (asyncapi.servers)? false : true, - all: ()=>{ - return Object.entries(asyncapi.servers || {}).map((server: any)=>{ - return{ - id: ()=> server[0], - url: ()=> (server[1] && server[1].host)? server[1].host : "", - protocol: ()=> (server[1] && server[1].protocol)? server[1].protocol : "", - protocolVersion: ()=> "", - hasDescription: ()=> (server[1] && server[1].description)? true : false, - description: ()=> (server[1])? server[1].description : "", - variables: ()=> (server[1] && server[1].variables)? {all: ()=> Object.entries(server[1].variables || {}).map((entry: any)=>{ - return { - id: ()=> (entry[0])? entry[0] : "", - description: ()=> (entry[1] && entry[1].description)? entry[1].description : "", - hasDefaultValue: ()=> (entry[1] && entry[1].default)? true : false, - defaultValue: ()=> (entry[1] && entry[1].default)? entry[1].default : "", - hasAllowedValues: ()=> (entry[1] && entry[1].enum)? true : false, - allowedValues: ()=> (entry[1] && entry[1].enum)? entry[1].enum : [] - - }; - }) }: "", - security: ()=> { - return server[1].security?.map( (sec: any)=>{ + isEmpty: () => (asyncapi.servers ? false : true), + all: () => { + return Object.entries(asyncapi.servers || {}).map((server: any) => { + return { + id: () => server[0], + url: () => (server[1] && server[1].host ? server[1].host : ''), + protocol: () => (server[1] && server[1].protocol ? server[1].protocol : ''), + protocolVersion: () => '', + hasDescription: () => (server[1] && server[1].description ? true : false), + description: () => (server[1] ? server[1].description : ''), + variables: () => + server[1] && server[1].variables + ? { + all: () => + Object.entries(server[1].variables || {}).map((entry: any) => { + return { + id: () => (entry[0] ? entry[0] : ''), + description: () => (entry[1] && entry[1].description ? entry[1].description : ''), + hasDefaultValue: () => (entry[1] && entry[1].default ? true : false), + defaultValue: () => (entry[1] && entry[1].default ? entry[1].default : ''), + hasAllowedValues: () => (entry[1] && entry[1].enum ? true : false), + allowedValues: () => (entry[1] && entry[1].enum ? entry[1].enum : []), + }; + }), + } + : '', + security: () => { + return server[1].security?.map((sec: any) => { return { - all: ()=> Object.entries(sec || {}).map((security: any)=>{ - return { - scheme: ()=>{ + all: () => + Object.entries(sec || {}).map((security: any) => { return { - type: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()])? asyncapi.components.securitySchemes[security[1].split('/').pop()].type : "", - hasDescription: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()] && asyncapi.components.securitySchemes[security[1].split('/').pop()].description )? true : false, - description: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].description, - name: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].name, - in: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].in, - bearerFormat: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].bearerFormat, - openIdConnectUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].openIdConnectUrl, - scheme: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].scheme, - flows: ()=> { - if(!asyncapi.components.securitySchemes[security[1].split('/').pop()].flows) {return;} + scheme: () => { return { - authorizationCode: ()=> { return { - authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode.authorizationUrl, - refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.refreshUrl, - tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.tokenUrl, - scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.availableScopes || [] - };}, - clientCredentials: ()=> { return { - authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.authorizationUrl, - refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.refreshUrl, - tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.tokenUrl, - scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.availableScopes || [] - };}, - implicit: ()=> { return { - authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.authorizationUrl, - refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.refreshUrl, - tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.tokenUrl, - scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.availableScopes || [] - };}, - password: ()=> { return { - authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.authorizationUrl, - refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.refreshUrl, - tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.tokenUrl, - scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.availableScopes || [] - };} + type: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] + ? asyncapi.components.securitySchemes[security[1].split('/').pop()].type + : '', + hasDescription: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] && + asyncapi.components.securitySchemes[security[1].split('/').pop()].description + ? true + : false, + description: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].description, + name: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].name, + in: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].in, + bearerFormat: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].bearerFormat, + openIdConnectUrl: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].openIdConnectUrl, + scheme: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].scheme, + flows: () => { + if (!asyncapi.components.securitySchemes[security[1].split('/').pop()].flows) { + return; + } + return { + authorizationCode: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode + .authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode + ?.availableScopes || [], + }; + }, + clientCredentials: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials + ?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials + ?.availableScopes || [], + }; + }, + implicit: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.availableScopes || + [], + }; + }, + password: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.availableScopes || + [], + }; + }, + }; + }, }; - } + }, + scopes: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] + ? asyncapi.components.securitySchemes[security[1].split('/').pop()].scopes || [] + : '', }; - }, - scopes: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()])? asyncapi.components.securitySchemes[security[1].split('/').pop()].scopes || [] : "" - }; - }) - }; + }), + }; }); }, - extensions: ()=> { + extensions: () => { return { - all: ()=> Object.entries(server[1].extensions || {}).map((extension: any)=>{ - return { - id: ()=> extension[1].id, - value: ()=> extension[1].value - }; - }) + all: () => + Object.entries(server[1].extensions || {}).map((extension: any) => { + return { + id: () => extension[1].id, + value: () => extension[1].value, + }; + }), }; }, - bindings: ()=>{ + bindings: () => { return { - isEmpty: ()=> (server[1].bindings)? false : true, - all: ()=> { - return Object.entries(server[1].bindings || {}).map((binding : any)=>{ + isEmpty: () => (server[1].bindings ? false : true), + all: () => { + return Object.entries(server[1].bindings || {}).map((binding: any) => { return { - protocol: ()=> (binding[1] && binding[1].protocol)? binding[1].protocol : "", - json: ()=> (binding[1] && binding[1].json)? binding[1].json : "", - type: ()=> (binding[1] && binding[1].type)? binding[1].type : "" + protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), + json: () => (binding[1] && binding[1].json ? binding[1].json : ''), + type: () => (binding[1] && binding[1].type ? binding[1].type : ''), }; }); - } + }, }; }, - tags: ()=> { + tags: () => { return { - isEmpty: ()=> (server[1].tags)? false : true, - all: ()=> Object.entries(server[1].tags || {}).map((tag: any)=>{ - return { - name: ()=> (tag[1] && tag[1].name)? tag[1].name : "", - description: ()=> (tag[1] && tag[1].description)? tag[1].description : "", - externalDocs: ()=> (tag[1] && tag[1].externalDocs)? { - url: ()=> tag[1].externalDocs.url, - description: ()=> tag[1].externalDocs.description - } : "" - - }; - }) + isEmpty: () => (server[1].tags ? false : true), + all: () => + Object.entries(server[1].tags || {}).map((tag: any) => { + return { + name: () => (tag[1] && tag[1].name ? tag[1].name : ''), + description: () => (tag[1] && tag[1].description ? tag[1].description : ''), + externalDocs: () => + tag[1] && tag[1].externalDocs + ? { + url: () => tag[1].externalDocs.url, + description: () => tag[1].externalDocs.description, + } + : '', + }; + }), }; - } + }, }; }); - } + }, }; } export default async function asyncapiMarkdown(asyncapi: any, context: vscode.ExtensionContext) { - - const templatePath = path.join(context.extensionPath,'dist', 'components','Asyncapi.ejs'); - if(!asyncapi.isAsyncapiParser){ + const templatePath = path.join(context.extensionPath, 'dist', 'components', 'Asyncapi.ejs'); + if (!asyncapi.isAsyncapiParser) { return await ejs.renderFile(templatePath, { info: { - title: (asyncapi.info && asyncapi.info.title)? asyncapi.info.title : "", - version: (asyncapi.info && asyncapi.info.version)? asyncapi.info.version : "", - defaultContentType: (asyncapi.defaultContentType)? asyncapi.defaultContentType : "", - specId: asyncapi.info && (asyncapi.info.specId)? asyncapi.info.specId : "", - termsOfService: (asyncapi.info && asyncapi.info.termsOfService)? asyncapi.info.termsOfService : "", - license: (asyncapi.info && asyncapi.info.license)? {url: ()=> asyncapi.info.license.url, name: ()=> asyncapi.info.license.name} : null, - contact: (asyncapi.info && asyncapi.info.contact)? {name: ()=> asyncapi.info.contact.name, url: ()=> asyncapi.info.contact.url, email: asyncapi.info.contact.email} : null, - externalDocs: (asyncapi.info && asyncapi.info.externalDocs)? {url: ()=> asyncapi.info.externalDocs.url(), description: ()=> asyncapi.info.externalDocs.description()} : null, - hasDescription: (asyncapi.info && asyncapi.info.description)? true: false, - description:(asyncapi.info)? md.render(asyncapi.info.description || "") : "", - tags: { - isEmpty: ()=> (asyncapi.info.tags)? false : true, - all: ()=> Object.entries(asyncapi.info.tags || {}).map((tag: any)=>{ - return { - name: ()=> (tag[1] && tag[1].name)? tag[1].name : "", - description: ()=> (tag[1] && tag[1].description)? tag[1].description : "", - externalDocs: ()=> (tag[1] && tag[1].externalDocs)? { - url: ()=> tag[1].externalDocs.url, - description: ()=> tag[1].externalDocs?.description, - hasDescription: ()=> tag[1].externalDocs?.description? true : false - } : "" - }; - }) - } + title: asyncapi.info && asyncapi.info.title ? asyncapi.info.title : '', + version: asyncapi.info && asyncapi.info.version ? asyncapi.info.version : '', + defaultContentType: asyncapi.defaultContentType ? asyncapi.defaultContentType : '', + specId: asyncapi.info && asyncapi.info.specId ? asyncapi.info.specId : '', + termsOfService: asyncapi.info && asyncapi.info.termsOfService ? asyncapi.info.termsOfService : '', + license: + asyncapi.info && asyncapi.info.license ? { url: () => asyncapi.info.license.url, name: () => asyncapi.info.license.name } : null, + contact: + asyncapi.info && asyncapi.info.contact + ? { name: () => asyncapi.info.contact.name, url: () => asyncapi.info.contact.url, email: asyncapi.info.contact.email } + : null, + externalDocs: + asyncapi.info && asyncapi.info.externalDocs + ? { url: () => asyncapi.info.externalDocs.url(), description: () => asyncapi.info.externalDocs.description() } + : null, + hasDescription: asyncapi.info && asyncapi.info.description ? true : false, + description: asyncapi.info ? md.render(asyncapi.info.description || '') : '', + tags: { + isEmpty: () => (asyncapi.info.tags ? false : true), + all: () => + Object.entries(asyncapi.info.tags || {}).map((tag: any) => { + return { + name: () => (tag[1] && tag[1].name ? tag[1].name : ''), + description: () => (tag[1] && tag[1].description ? tag[1].description : ''), + externalDocs: () => + tag[1] && tag[1].externalDocs + ? { + url: () => tag[1].externalDocs.url, + description: () => tag[1].externalDocs?.description, + hasDescription: () => (tag[1].externalDocs?.description ? true : false), + } + : '', + }; + }), + }, }, - servers:{ - servers: addServers(asyncapi), - schemaHelper: SchemaHelper, - serverHelper: ServerHelper, - md + servers: { + servers: addServers(asyncapi), + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + md, }, - operations:{ + operations: { channels: { - isEmpty: ()=> (asyncapi.channels)? false : true, - all: ()=> Object.entries(asyncapi.channels || {}).map((channel: any)=>{ - return { - servers: ()=> addServers(asyncapi), - operations: ()=> { - return { - all: ()=> Object.entries(asyncapi.operations || {}).filter((operation: any)=> operation[1].channel?.$ref.split('channels/').pop().replaceAll('~1','/') === channel[0]).map((operation: any)=>{ - return { - operationId: ()=> (operation[0])? operation[0] : "", - isSend: ()=> (operation[1] && operation[1].action === 'send')? true : false, - isReceive: ()=> (operation[1] && operation[1].action === 'receive')? true : false, - reply: ()=> (operation[1] && operation[1].reply)? operation[1].reply : false, - summary: ()=> (operation[1] && operation[1].summary)? operation[1].summary : "", - hasDescription: ()=> (operation[1] && operation[1].description)? true : false, - description: ()=> (operation[1] && operation[1].description)? operation[1].description : "", - externalDocs: ()=> (operation[1] && operation[1].externalDocs)? { - url: ()=> operation[1].externalDocs.url, - description: ()=> operation[1].externalDocs.description, - hasDescription: ()=> operation[1].externalDocs.description? true : false - } : "", - tags: ()=> { - return { - isEmpty: ()=> (operation[1].tags)? false : true, - all: ()=> Object.entries(operation[1].tags || {}).map((tag: any)=>{ - return { - name: ()=> (tag[1] && tag[1].name)? tag[1].name : "", - description: ()=> (tag[1] && tag[1].description)? tag[1].description : "", - externalDocs: ()=> (tag[1] && tag[1].externalDocs)? { - url: ()=> tag[1].externalDocs?.url, - description: ()=> tag[1].externalDocs?.description, - hasDescription: ()=> tag[1].externalDocs?.description? true : false - } : "" - - }; - }) - }; - }, - extensions: ()=> { - return { - all: ()=> Object(operation[1].extensions).map((extension: any)=>{ - return { - id: ()=> extension[1].id, - value: ()=> extension[1].value - }; - }) - }; - }, - bindings: ()=>{ - return { - isEmpty: ()=> (operation[1].bindings)? false : true, - all: ()=> { - return Object.entries(operation[1].bindings || {}).map((binding : any)=>{ + isEmpty: () => (asyncapi.channels ? false : true), + all: () => + Object.entries(asyncapi.channels || {}).map((channel: any) => { + return { + servers: () => addServers(asyncapi), + operations: () => { + return { + all: () => + Object.entries(asyncapi.operations || {}) + .filter( + (operation: any) => operation[1].channel?.$ref.split('channels/').pop().replaceAll('~1', '/') === channel[0] + ) + .map((operation: any) => { + return { + operationId: () => (operation[0] ? operation[0] : ''), + isSend: () => (operation[1] && operation[1].action === 'send' ? true : false), + isReceive: () => (operation[1] && operation[1].action === 'receive' ? true : false), + reply: () => (operation[1] && operation[1].reply ? operation[1].reply : false), + summary: () => (operation[1] && operation[1].summary ? operation[1].summary : ''), + hasDescription: () => (operation[1] && operation[1].description ? true : false), + description: () => (operation[1] && operation[1].description ? operation[1].description : ''), + externalDocs: () => + operation[1] && operation[1].externalDocs + ? { + url: () => operation[1].externalDocs.url, + description: () => operation[1].externalDocs.description, + hasDescription: () => (operation[1].externalDocs.description ? true : false), + } + : '', + tags: () => { return { - protocol: ()=> (binding[1] && binding[1].protocol)? binding[1].protocol : "", - json: ()=> (binding[1] && binding[1].json)? binding[1].json : "", - type: ()=> (binding[1] && binding[1].type)? binding[1].type : "" + isEmpty: () => (operation[1].tags ? false : true), + all: () => + Object.entries(operation[1].tags || {}).map((tag: any) => { + return { + name: () => (tag[1] && tag[1].name ? tag[1].name : ''), + description: () => (tag[1] && tag[1].description ? tag[1].description : ''), + externalDocs: () => + tag[1] && tag[1].externalDocs + ? { + url: () => tag[1].externalDocs?.url, + description: () => tag[1].externalDocs?.description, + hasDescription: () => (tag[1].externalDocs?.description ? true : false), + } + : '', + }; + }), }; - }); - } - }; - }, - security: ()=> { - return operation[1].security?.map( (sec: any)=>{ - return { - all: ()=> Object.entries(sec || {}).map((security: any)=>{ - return { - scheme: ()=>{ - return { - type: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()])? asyncapi.components.securitySchemes[security[1].split('/').pop()].type : "", - hasDescription: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()] && asyncapi.components.securitySchemes[security[1].split('/').pop()].description )? true : false, - description: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].description, - name: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].name, - in: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].in, - bearerFormat: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].bearerFormat, - openIdConnectUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].openIdConnectUrl, - scheme: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].scheme, - flows: ()=> { - if(!asyncapi.components.securitySchemes[security[1].split('/').pop()].flows) {return;} + }, + extensions: () => { + return { + all: () => + Object(operation[1].extensions).map((extension: any) => { return { - authorizationCode: ()=> { return { - authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode.authorizationUrl, - refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.refreshUrl, - tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.tokenUrl, - scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()].flows?.authorizationCode?.availableScopes || [] - };}, - clientCredentials: ()=> { return { - authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.authorizationUrl, - refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.refreshUrl, - tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.tokenUrl, - scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.clientCredentials?.availableScopes || [] - };}, - implicit: ()=> { return { - authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.authorizationUrl, - refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.refreshUrl, - tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.tokenUrl, - scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit?.availableScopes || [] - };}, - password: ()=> { return { - authorizationUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.authorizationUrl, - refreshUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.refreshUrl, - tokenUrl: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.tokenUrl, - scopes: ()=> asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password?.availableScopes || [] - };} + id: () => extension[1].id, + value: () => extension[1].value, }; - } - }; - }, - scopes: ()=> (asyncapi.components && asyncapi.components.securitySchemes && asyncapi.components.securitySchemes[security[1].split('/').pop()])? asyncapi.components.securitySchemes[security[1].split('/').pop()].scopes || [] : "" - }; - }) - }; - }); - }, - messages: ()=>{ - return { - all: ()=>{ - let tmp: any = Object.values(operation[1].messages); - if(tmp[0]?.$ref) { - return [{incorrect: true, refs: Object.values(operation[1].messages)}]; - } - return Object.entries(operation[1].messages|| {}).map((message: any)=>{ + }), + }; + }, + bindings: () => { return { - id: ()=> message[0], - title: ()=> message[1].title, - name: ()=> message[1].name, - hasDescription: ()=> (message[1].description)? true : false, - description: ()=> message[1].description, - contentType: ()=> message[1].contentType, - summary: ()=> message[1].summary, - correlationId: ()=> { - return { - location: ()=> message[1].correlationId?.location, - hasDescription: ()=> message[1].correlationId? true : false, - description: ()=> message[1].correlationId?.description - }; - }, - externalDocs: ()=> { - return { - url: ()=> message[1].externalDocs?.url, - description: ()=> message[1].externalDocs?.description - }; - }, - headers: ()=> { - return { - incorrect: true, - ...message[1].headers - }; - }, - payload: ()=> { - return { - incorrect: true, - ...message[1].payload - }; - }, - tags: ()=> { - return { - isEmpty: ()=> (operation[1].tags)? false : true, - all: ()=> Object.entries(operation[1].tags || {}).map((tag: any)=>{ - return { - name: ()=> (tag[1] && tag[1].name)? tag[1].name : "", - description: ()=> (tag[1] && tag[1].description)? tag[1].description : "", - externalDocs: ()=> (tag[1] && tag[1].externalDocs)? { - url: ()=> tag[1].externalDocs.url, - description: ()=> tag[1].externalDocs?.description, - hasDescription: ()=> tag[1].externalDocs?.description? true : false - } : "" - - }; - }) - }; + isEmpty: () => (operation[1].bindings ? false : true), + all: () => { + return Object.entries(operation[1].bindings || {}).map((binding: any) => { + return { + protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), + json: () => (binding[1] && binding[1].json ? binding[1].json : ''), + type: () => (binding[1] && binding[1].type ? binding[1].type : ''), + }; + }); }, - extensions: ()=> { - return { - all: ()=> Object.entries(message[1].extensions || {}).map((extension: any)=>{ + }; + }, + security: () => { + return operation[1].security?.map((sec: any) => { + return { + all: () => + Object.entries(sec || {}).map((security: any) => { return { - id: ()=> extension[1].id, - value: ()=> extension[1].value + scheme: () => { + return { + type: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] + ? asyncapi.components.securitySchemes[security[1].split('/').pop()].type + : '', + hasDescription: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] && + asyncapi.components.securitySchemes[security[1].split('/').pop()].description + ? true + : false, + description: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].description, + name: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].name, + in: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].in, + bearerFormat: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].bearerFormat, + openIdConnectUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].openIdConnectUrl, + scheme: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].scheme, + flows: () => { + if (!asyncapi.components.securitySchemes[security[1].split('/').pop()].flows) { + return; + } + return { + authorizationCode: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows + ?.authorizationCode.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows + ?.authorizationCode?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows + ?.authorizationCode?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows + ?.authorizationCode?.availableScopes || [], + }; + }, + clientCredentials: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows + ?.clientCredentials?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows + ?.clientCredentials?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows + ?.clientCredentials?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows + ?.clientCredentials?.availableScopes || [], + }; + }, + implicit: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit + ?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit + ?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit + ?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit + ?.availableScopes || [], + }; + }, + password: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password + ?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password + ?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password + ?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password + ?.availableScopes || [], + }; + }, + }; + }, + }; + }, + scopes: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] + ? asyncapi.components.securitySchemes[security[1].split('/').pop()].scopes || [] + : '', }; - }) - }; - }, - bindings: ()=>{ - return { - isEmpty: ()=> (message[1].bindings)? false : true, - all: ()=> { - return Object.entries(message[1].bindings || {}).map((binding : any)=>{ + }), + }; + }); + }, + messages: () => { + return { + all: () => { + let tmp: any = Object.values(operation[1].messages || {}); + if (tmp[0]?.$ref) { + return [{ incorrect: true, refs: Object.values(operation[1].messages || {}) }]; + } + return Object.entries(operation[1].messages || {}).map((message: any) => { + return { + id: () => message[0], + title: () => message[1].title, + name: () => message[1].name, + hasDescription: () => (message[1].description ? true : false), + description: () => message[1].description, + contentType: () => message[1].contentType, + summary: () => message[1].summary, + correlationId: () => { + return { + location: () => message[1].correlationId?.location, + hasDescription: () => (message[1].correlationId ? true : false), + description: () => message[1].correlationId?.description, + }; + }, + externalDocs: () => { + return { + url: () => message[1].externalDocs?.url, + description: () => message[1].externalDocs?.description, + }; + }, + headers: () => { + return { + incorrect: true, + ...message[1].headers, + }; + }, + payload: () => { + return { + incorrect: true, + ...message[1].payload, + }; + }, + tags: () => { return { - protocol: ()=> (binding[1] && binding[1].protocol)? binding[1].protocol : "", - json: ()=> (binding[1] && binding[1].json)? binding[1].json : "", - type: ()=> (binding[1] && binding[1].type)? binding[1].type : "" + isEmpty: () => (operation[1].tags ? false : true), + all: () => + Object.entries(operation[1].tags || {}).map((tag: any) => { + return { + name: () => (tag[1] && tag[1].name ? tag[1].name : ''), + description: () => (tag[1] && tag[1].description ? tag[1].description : ''), + externalDocs: () => + tag[1] && tag[1].externalDocs + ? { + url: () => tag[1].externalDocs.url, + description: () => tag[1].externalDocs?.description, + hasDescription: () => (tag[1].externalDocs?.description ? true : false), + } + : '', + }; + }), }; - }); - } - }; - } + }, + extensions: () => { + return { + all: () => + Object.entries(message[1].extensions || {}).map((extension: any) => { + return { + id: () => extension[1].id, + value: () => extension[1].value, + }; + }), + }; + }, + bindings: () => { + return { + isEmpty: () => (message[1].bindings ? false : true), + all: () => { + return Object.entries(message[1].bindings || {}).map((binding: any) => { + return { + protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), + json: () => (binding[1] && binding[1].json ? binding[1].json : ''), + type: () => (binding[1] && binding[1].type ? binding[1].type : ''), + }; + }); + }, + }; + }, + }; + }); + }, }; - }); - } - }; - } - }; - }), - - }; - }, - address: ()=> (channel[1])? channel[1].address : "", - hasDescription: ()=> (channel[1] && channel[1].description)? true : false, - description: ()=> (channel[1] && channel[1].description)? channel[1].description : "", - parameters: ()=> { - return { - all: ()=> Object.entries(channel[1].parameters || {}).map((parameter: any)=> { - return { - id: ()=> parameter[0], - schema: ()=> { + }, + }; + }), + }; + }, + address: () => (channel[1] ? channel[1].address : ''), + hasDescription: () => (channel[1] && channel[1].description ? true : false), + description: () => (channel[1] && channel[1].description ? channel[1].description : ''), + parameters: () => { + return { + all: () => + Object.entries(channel[1].parameters || {}).map((parameter: any) => { return { - json: ()=>{ - return{ - type: parameter[1].schema?.type, - title: parameter[1].schema?.title, - required: parameter[1].schema?.required + id: () => parameter[0], + schema: () => { + return { + json: () => { + return { + type: parameter[1].schema?.type, + title: parameter[1].schema?.title, + required: parameter[1].schema?.required, + }; + }, }; - } + }, + description: () => parameter[1].description, + location: () => parameter[1].location, }; - }, - description: ()=>parameter[1].description, - location: ()=>parameter[1].location - }; - }) - }; - }, - extensions: ()=> { - return { - all: ()=> Object.entries(channel[1].extensions || {}).map((extension: any)=>{ - return { - id: ()=> extension[1].id, - value: ()=> extension[1].value - }; - }) - }; - }, - bindings: ()=>{ - return { - isEmpty: ()=> (channel[1].bindings)? false : true, - all: ()=> { - return Object.entries(channel[1].bindings || {}).map((binding : any)=>{ - return { - protocol: ()=> (binding[1] && binding[1].protocol)? binding[1].protocol : "", - json: ()=> (binding[1] && binding[1].json)? binding[1].json : "", - type: ()=> (binding[1] && binding[1].type)? binding[1].type : "" - }; - }); - } - }; - } - - }; - }) + }), + }; + }, + extensions: () => { + return { + all: () => + Object.entries(channel[1].extensions || {}).map((extension: any) => { + return { + id: () => extension[1].id, + value: () => extension[1].value, + }; + }), + }; + }, + bindings: () => { + return { + isEmpty: () => (channel[1].bindings ? false : true), + all: () => { + return Object.entries(channel[1].bindings || {}).map((binding: any) => { + return { + protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), + json: () => (binding[1] && binding[1].json ? binding[1].json : ''), + type: () => (binding[1] && binding[1].type ? binding[1].type : ''), + }; + }); + }, + }; + }, + }; + }), }, - isV3: (asyncapi.asyncapi)? asyncapi.asyncapi.split('.')[0] === '3' : true, + isV3: asyncapi.asyncapi ? asyncapi.asyncapi.split('.')[0] === '3' : true, schemaHelper: SchemaHelper, serverHelper: ServerHelper, messageHelper: MessageHelper, - allServersLength: (asyncapi.servers)? Object.keys(asyncapi.servers).length : 0, - md + allServersLength: asyncapi.servers ? Object.keys(asyncapi.servers).length : 0, + md, }, - path:{ - infoPath: path.join(context.extensionPath,'dist', 'components','Info.ejs'), - tagsPath: path.join(context.extensionPath,'dist', 'components','Tags.ejs'), - serversPath: path.join(context.extensionPath,'dist', 'components','Servers.ejs'), - securityPath: path.join(context.extensionPath,'dist', 'components','Security.ejs'), - bindingsPath: path.join(context.extensionPath,'dist', 'components','Bindings.ejs'), - extensionsPath: path.join(context.extensionPath,'dist', 'components','Extensions.ejs'), - schemaPath: path.join(context.extensionPath,'dist', 'components','Schema.ejs'), - operationsPath: path.join(context.extensionPath,'dist', 'components','Operations.ejs'), - messagePath: path.join(context.extensionPath,'dist', 'components','Message.ejs') - } - }); - }else{ - + path: { + infoPath: path.join(context.extensionPath, 'dist', 'components', 'Info.ejs'), + tagsPath: path.join(context.extensionPath, 'dist', 'components', 'Tags.ejs'), + serversPath: path.join(context.extensionPath, 'dist', 'components', 'Servers.ejs'), + securityPath: path.join(context.extensionPath, 'dist', 'components', 'Security.ejs'), + bindingsPath: path.join(context.extensionPath, 'dist', 'components', 'Bindings.ejs'), + extensionsPath: path.join(context.extensionPath, 'dist', 'components', 'Extensions.ejs'), + schemaPath: path.join(context.extensionPath, 'dist', 'components', 'Schema.ejs'), + operationsPath: path.join(context.extensionPath, 'dist', 'components', 'Operations.ejs'), + messagePath: path.join(context.extensionPath, 'dist', 'components', 'Message.ejs'), + }, + }); + } else { const info = asyncapi.info(); return await ejs.renderFile(templatePath, { - info: { - title: info.title(), - version: info.version(), - defaultContentType: asyncapi.defaultContentType(), - specId: info.id(), - termsOfService: info.termsOfService(), - license: info.license(), - contact: info.contact(), - externalDocs: info.externalDocs(), - extensions: info.extensions(), - hasDescription: info.hasDescription(), - description: md.render(info.description() || ""), - tags: info.tags(), - - }, - servers:{ - servers: asyncapi.servers(), - schemaHelper: SchemaHelper, - serverHelper: ServerHelper, - md - }, - operations:{ - channels: asyncapi.channels(), - isV3: asyncapi.version().split('.')[0] === '3', - schemaHelper: SchemaHelper, - serverHelper: ServerHelper, - messageHelper: MessageHelper, - allServersLength: asyncapi.servers().all().length, - md - }, - path:{ - infoPath: path.join(context.extensionPath,'dist', 'components','Info.ejs'), - tagsPath: path.join(context.extensionPath,'dist', 'components','Tags.ejs'), - serversPath: path.join(context.extensionPath,'dist', 'components','Servers.ejs'), - securityPath: path.join(context.extensionPath,'dist', 'components','Security.ejs'), - bindingsPath: path.join(context.extensionPath,'dist', 'components','Bindings.ejs'), - extensionsPath: path.join(context.extensionPath,'dist', 'components','Extensions.ejs'), - schemaPath: path.join(context.extensionPath,'dist', 'components','Schema.ejs'), - operationsPath: path.join(context.extensionPath,'dist', 'components','Operations.ejs'), - messagePath: path.join(context.extensionPath,'dist', 'components','Message.ejs') - } + info: { + title: info.title(), + version: info.version(), + defaultContentType: asyncapi.defaultContentType(), + specId: info.id(), + termsOfService: info.termsOfService(), + license: info.license(), + contact: info.contact(), + externalDocs: info.externalDocs(), + extensions: info.extensions(), + hasDescription: info.hasDescription(), + description: md.render(info.description() || ''), + tags: info.tags(), + }, + servers: { + servers: asyncapi.servers(), + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + md, + }, + operations: { + channels: asyncapi.channels(), + isV3: asyncapi.version().split('.')[0] === '3', + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + messageHelper: MessageHelper, + allServersLength: asyncapi.servers().all().length, + md, + }, + path: { + infoPath: path.join(context.extensionPath, 'dist', 'components', 'Info.ejs'), + tagsPath: path.join(context.extensionPath, 'dist', 'components', 'Tags.ejs'), + serversPath: path.join(context.extensionPath, 'dist', 'components', 'Servers.ejs'), + securityPath: path.join(context.extensionPath, 'dist', 'components', 'Security.ejs'), + bindingsPath: path.join(context.extensionPath, 'dist', 'components', 'Bindings.ejs'), + extensionsPath: path.join(context.extensionPath, 'dist', 'components', 'Extensions.ejs'), + schemaPath: path.join(context.extensionPath, 'dist', 'components', 'Schema.ejs'), + operationsPath: path.join(context.extensionPath, 'dist', 'components', 'Operations.ejs'), + messagePath: path.join(context.extensionPath, 'dist', 'components', 'Message.ejs'), + }, }); } - - -} \ No newline at end of file +} diff --git a/src/ClassDiagram.ts b/src/ClassDiagram.ts new file mode 100644 index 0000000..7834245 --- /dev/null +++ b/src/ClassDiagram.ts @@ -0,0 +1,363 @@ +import * as vscode from 'vscode'; +import * as ejs from 'ejs'; +import * as path from 'path'; + +export default async function classDiagram(asyncapi: any, context: vscode.ExtensionContext) { + const templatePath = path.join(context.extensionPath, 'dist', 'components', 'ClassDiagram.ejs'); + let data: any = { + title: asyncapi?.info?.title, + channels: [...Object.entries(asyncapi.channels || {}), ...Object.entries(asyncapi.components?.channels || {})], + operations: [...Object.entries(asyncapi.operations || {}), ...Object.entries(asyncapi.components?.operations || {})], + messages: [...new Set(Object.entries(asyncapi.components?.messages || {}))], + payloads: [], + headers: [], + others: [], + relations: [], + }; + + function recursiveObjectSplit(dest: any, source: any, parent: string, destLength: number) { + Object.entries(source || {}).map(([sourceName, sourceInfo]: [string, any]) => { + if (sourceName !== '$ref') { + if (!dest[dest.length - 1][1][sourceName]) { + Object.defineProperty(dest[dest.length - 1][1], sourceName, { value: sourceInfo }); + } + } + }); + Object.entries(source || {}).map(([sourceName, sourceInfo]: [string, any]) => { + if (sourceName === '$ref') { + let parsedRef = String(sourceInfo).split('/'); + if (Object.keys(asyncapi.components?.schemas || {}).indexOf(parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')) > -1) { + recursiveObjectSplit( + data.others, + asyncapi.components.schemas[parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')], + `${parent}.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, + dest.length + ); + } + } else { + if (typeof sourceInfo === 'object' && !Array.isArray(sourceInfo)) { + data.others.push([`${parent}.${sourceName}`, {}]); + data.relations.push( + `${parent.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${parent.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_${sourceName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + recursiveObjectSplit(data.others, sourceInfo, `${parent}.${sourceName}`, dest.length); + } + } + }); + } + + data.messages?.map(([messageName, messageInfo]: [string, any]) => { + if (!messageInfo.payload) { + return; + } + if (messageInfo.payload.$ref) { + let parsedRef = String(messageInfo.payload.$ref).split('/'); + let schemas = Object.entries(asyncapi.components?.schemas || {}); + if ( + schemas + .map(v => { + return v[0]; + }) + .indexOf(parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')) > -1 + ) { + data.payloads.push([`${messageName}.payload.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, {}]); + data.relations.push( + `${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_payload_${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/').replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + recursiveObjectSplit( + data.payloads, + asyncapi.components?.schemas[parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')], + `${messageName}.payload.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, + data.payloads.length + ); + } + } else if (messageInfo.payload.schemaFormat) { + if (messageInfo.payload.schema?.$ref) { + let parsedRef = String(messageInfo.payload.schema.$ref).split('/'); + let schemas = Object.entries(asyncapi.components?.schemas || {}); + if ( + schemas + .map(v => { + return v[0]; + }) + .indexOf(parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')) > -1 + ) { + data.payloads.push([ + `${messageName}.payload.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, + { schemaFormat: messageInfo.payload.schemaFormat }, + ]); + data.relations.push( + `${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_payload_${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/').replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + recursiveObjectSplit( + data.payloads, + asyncapi.components?.schemas[parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')], + `${messageName}.payload.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, + data.payloads.length + ); + } + } else { + data.payloads.push([`${messageName}.payload`, { schemaFormat: messageInfo.payload.schemaFormat }]); + data.relations.push( + `${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_payload` + ); + recursiveObjectSplit(data.payloads, messageInfo.payload.schema, `${messageName}.payload`, data.payloads.length); + } + } else { + data.payloads.push([`${messageName}.payload`, {}]); + data.relations.push( + `${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_payload` + ); + recursiveObjectSplit(data.payloads, messageInfo.payload, `${messageName}.payload`, data.payloads.length); + } + }); + + data.messages?.map(([messageName, messageInfo]: [string, any]) => { + if (!messageInfo.headers) { + return; + } + if (messageInfo.headers.$ref) { + let parsedRef = String(messageInfo.headers.$ref).split('/'); + let schemas = Object.entries(asyncapi.components?.schemas || {}); + if ( + schemas + .map(v => { + return v[0]; + }) + .indexOf(parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')) > -1 + ) { + data.headers.push([`${messageName}.headers.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, {}]); + data.relations.push( + `${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_headers_${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/').replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + recursiveObjectSplit( + data.headers, + asyncapi.components?.schemas[parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')], + `${messageName}.headers.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, + data.headers.length + ); + } + } else if (messageInfo.headers.schemaFormat) { + if (messageInfo.headers.schema?.$ref) { + let parsedRef = String(messageInfo.headers.schema.$ref).split('/'); + let schemas = Object.entries(asyncapi.components?.schemas || {}); + if ( + schemas + .map(v => { + return v[0]; + }) + .indexOf(parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')) > -1 + ) { + data.headers.push([ + `${messageName}.headers.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, + { schemaFormat: messageInfo.headers.schemaFormat }, + ]); + data.relations.push( + `${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_headers_${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/').replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + recursiveObjectSplit( + data.headers, + asyncapi.components?.scheheadersmas[parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')], + `${messageName}.headers.${parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')}`, + data.headers.length + ); + } + } else { + data.headers.push([`${messageName}.headers`, { schemaFormat: messageInfo.headers.schemaFormat }]); + data.relations.push( + `${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_headers` + ); + recursiveObjectSplit(data.headers, messageInfo.headers.schema, `${messageName}.headers`, data.headers.length); + } + } else { + data.headers.push([`${messageName}.headers`, {}]); + data.relations.push( + `${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_headers` + ); + recursiveObjectSplit(data.headers, messageInfo.headers, `${messageName}.headers`, data.headers.length); + } + }); + + Object.entries({ ...asyncapi.channels, ...asyncapi.components?.channels } || {}).map(([channelName, channelInfo]: [string, any]) => { + if (!asyncapi.asyncapi || asyncapi.asyncapi.split('.')[0] !== '2') { + Object.entries(channelInfo.messages || {}).map(([messageName, messageInfo]: [string, any]) => { + if (!messageInfo.$ref) { + if (data.messages.map((v: any[]) => v[0]).indexOf(messageName) === -1) { + data.messages.push([messageName, messageInfo]); + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}` + ); + } else { + data.messages.push([`${channelName}_${messageName}`, messageInfo]); + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${channelName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + } + } else { + let parsedRef = String(messageInfo.$ref).split('/'); + if (data.messages.map((v: any[]) => v[0]).indexOf(parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')) > -1) { + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${(parsedRef.pop() || '') + .replace(/~1/gi, '/') + .replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + } + } + }); + } else if (asyncapi.asyncapi.split('.')[0] === '2') { + Object.entries({ subscribe: channelInfo.subscribe, publish: channelInfo.publish } || {}).map( + ([operationName, operationInfo]: [string, any]) => { + if (!operationInfo) { + return; + } + data.operations.push([`${channelName}_${operationName}`, operationInfo]); + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${channelName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_${operationName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + if (operationInfo.message?.oneOf) { + operationInfo.message.oneOf.map((message: any) => { + Object.entries(message).map(([messageName, messageInfo]: [string, any]) => { + if (messageName === '$ref') { + let parsedMsg = String(messageInfo).split('/'); + let finalMsgStr = + data.messages.map((v: any[]) => v[0]).indexOf(`${parsedMsg[parsedMsg.length - 2]}_${parsedMsg[parsedMsg.length - 1]}`) > + -1 + ? `${parsedMsg[parsedMsg.length - 2]}_${parsedMsg[parsedMsg.length - 1]}` + : (parsedMsg.pop() || '').replace(/~1/gi, '/'); + if (data.messages.map((v: any[]) => v[0]).indexOf(finalMsgStr) > -1) { + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${(finalMsgStr || '') + .replace(/~1/gi, '/') + .replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + } + } else { + data.messages.push([`${channelName}_${messageName}`, messageInfo]); + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${channelName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + } + }); + }); + } else { + Object.entries(operationInfo.message).map(([messageName, messageInfo]: [string, any]) => { + if (messageName === '$ref') { + let parsedMsg = String(messageInfo).split('/'); + let finalMsgStr = + data.messages.map((v: any[]) => v[0]).indexOf(`${parsedMsg[parsedMsg.length - 2]}_${parsedMsg[parsedMsg.length - 1]}`) > + -1 + ? `${parsedMsg[parsedMsg.length - 2]}_${parsedMsg[parsedMsg.length - 1]}` + : (parsedMsg.pop() || '').replace(/~1/gi, '/'); + if (data.messages.map((v: any[]) => v[0]).indexOf(finalMsgStr) > -1) { + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${(finalMsgStr || '') + .replace(/~1/gi, '/') + .replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + } + } else { + if (data.messages.map((v: any[]) => v[0]).indexOf(messageName) === -1) { + data.messages.push([messageName, messageInfo]); + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${messageName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}` + ); + } else { + data.messages.push([`${channelName}_${messageName}`, messageInfo]); + data.relations.push( + `${channelName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${channelName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}_${messageName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + } + } + }); + } + } + ); + } + }); + + Object.entries({ ...asyncapi.operations, ...asyncapi.components?.operations } || {}).map( + ([operationName, operationInfo]: [string, any]) => { + if (asyncapi.asyncapi.split('.')[0] !== '2') { + operationInfo.messages?.map((message: any) => { + Object.entries(message || {}).map(([messageName, messageInfo]: [string, any]) => { + let parsedMsg = String(messageInfo).split('/'); + let finalMsgStr = + data.messages.map((v: any[]) => v[0]).indexOf(`${parsedMsg[parsedMsg.length - 2]}_${parsedMsg[parsedMsg.length - 1]}`) > -1 + ? `${parsedMsg[parsedMsg.length - 2]}_${parsedMsg[parsedMsg.length - 1]}` + : (parsedMsg.pop() || '').replace(/~1/gi, '/'); + if (data.messages.map((v: any[]) => v[0]).indexOf(finalMsgStr) > -1) { + data.relations.push( + `${operationName.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${(finalMsgStr || '') + .replace(/~1/gi, '/') + .replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')}` + ); + } + }); + }); + + Object.entries(operationInfo.channel || {}).map(([channelName, channelInfo]: [string, any]) => { + let parsedRef = String(channelInfo).split('/'); + if (data.channels.map((v: any[]) => v[0]).indexOf(parsedRef[parsedRef.length - 1].replace(/~1/gi, '/')) > -1) { + data.relations.push( + `${(parsedRef.pop() || '') + .replace(/~1/gi, '/') + .replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '_')} <-- ${operationName.replace( + /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, + '_' + )}` + ); + } + }); + } + } + ); + + return await ejs.renderFile(templatePath, { + ...data, + }); +} diff --git a/src/Flowchart.ts b/src/Flowchart.ts new file mode 100644 index 0000000..7d4a374 --- /dev/null +++ b/src/Flowchart.ts @@ -0,0 +1,103 @@ +import * as vscode from 'vscode'; +import * as ejs from 'ejs'; +import * as path from 'path'; + +export default async function flowchart(asyncapi: any, context: vscode.ExtensionContext) { + + const templatePath = path.join(context.extensionPath,'dist', 'components','Flowchart.ejs'); + let data: any = { + title: asyncapi?.info?.title, + servers:[...Object.keys(asyncapi.servers || {}),...Object.keys(asyncapi.components?.servers || {})], + channels:[...Object.keys(asyncapi.channels || {}),...Object.keys(asyncapi.components?.channels || {})], + operations:[...Object.keys(asyncapi.operations || {}),...Object.keys(asyncapi.components?.operations || {})], + messages:[...new Set(Object.keys(asyncapi.components?.messages || {}))], + relations:[] + }; + Object.entries({...asyncapi.channels,...asyncapi.components?.channels} || {}).map(([channelName, channelInfo]: [string, any]) => { + if(!asyncapi.asyncapi || asyncapi.asyncapi.split('.')[0] !== '2'){ + Object.entries(channelInfo.messages || {}).map(([messageName, messageInfo]: [string, any]) =>{ + if(!messageInfo.$ref) { + if(data.messages.indexOf(messageName) === -1){ + data.messages.push(messageName); + data.relations.push(`${messageName} --> ${channelName}`); + } + else { + data.messages.push(`${channelName}_${messageName}`); + data.relations.push(`${channelName}_${messageName} --> ${channelName}`); + } + }else{ + let parsedRef = String(messageInfo.$ref).split('/'); + if(data.messages.indexOf(parsedRef[parsedRef.length-1].replace(/~1/gi,"/")) > -1) + {data.relations.push(`${(parsedRef.pop() || "").replace(/~1/gi,"/")} --> ${channelName}`);} + } + }); + channelInfo.servers?.map((server: any)=>{ + let parsedRef = String(server.$ref).split('/'); + if(data.servers.indexOf(parsedRef[parsedRef.length-1].replace(/~1/gi,"/")) > -1) + {data.relations.push(`${channelName} --> ${(parsedRef.pop() || "").replace(/~1/gi,"/")}`);} + + }); + }else if(asyncapi.asyncapi.split('.')[0] === '2'){ + Object.entries({"subscribe": channelInfo.subscribe, "publish": channelInfo.publish} || {}).map(([operationName, operationInfo] : [string, any])=>{ + if(!operationInfo) {return;} + data.operations.push(`${channelName}_${operationName}`); + data.relations.push(`${channelName}_${operationName} --> ${channelName}`); + if(operationInfo.message?.oneOf){ + operationInfo.message.oneOf.map((message: any)=>{ + Object.entries(message).map(([messageName,messageInfo]:[string,any])=>{ + if(messageName === '$ref'){ + let parsedMsg = String(messageInfo).split('/'); + let finalMsgStr = (data.messages.indexOf(`${parsedMsg[parsedMsg.length-2].replace(/~1/gi,"/")}_${parsedMsg[parsedMsg.length-1].replace(/~1/gi,"/")}`) > -1)? `${parsedMsg[parsedMsg.length-2].replace(/~1/gi,"/")}_${parsedMsg[parsedMsg.length-1].replace(/~1/gi,"/")}`: ( parsedMsg.pop() || "").replace(/~1/gi,"/"); + if(data.messages.indexOf(finalMsgStr) > -1) + {data.relations.push(`${finalMsgStr} --> ${channelName}`);} + }else{ + data.messages.push(`${channelName}_${messageName}`); + data.relations.push(`${channelName}_${messageName} --> ${channelName}`); + } + }); + }); + }else{ + Object.entries(operationInfo.message).map(([messageName, messageInfo]:[string, any])=>{ + if(messageName === '$ref'){ + let parsedMsg = String(messageInfo).split('/'); + let finalMsgStr = (data.messages.indexOf(`${parsedMsg[parsedMsg.length-2].replace(/~1/gi,"/")}_${parsedMsg[parsedMsg.length-1].replace(/~1/gi,"/")}`) > -1)? `${parsedMsg[parsedMsg.length-2].replace(/~1/gi,"/")}_${parsedMsg[parsedMsg.length-1].replace(/~1/gi,"/")}`: (parsedMsg.pop() || "").replace(/~1/gi,"/"); + if(data.messages.indexOf((finalMsgStr || "").replace(/~1/gi,"/")) > -1) + {data.relations.push(`${(finalMsgStr || "").replace(/~1/gi,"/")} --> ${channelName}`);} + }else{ + if(data.messages.indexOf(messageName) === -1){ + data.messages.push(`${messageName}`); + data.relations.push(`${messageName} --> ${channelName}`); + }else{ + data.messages.push(`${channelName}_${messageName}`); + data.relations.push(`${channelName}_${messageName} --> ${channelName}`); + } + } + }); + } + }); + } + }); + + Object.entries({...asyncapi.operations, ...asyncapi.components?.operations} || {}).map(([operationName, operationInfo]: [string, any]) => { + if(asyncapi.asyncapi.split('.')[0] !== '2'){ + operationInfo.messages?.map((message: any)=> { + Object.entries(message || {}).map(([messageName, messageInfo]: [string, any])=>{ + let parsedMsg = String(messageInfo).split('/'); + let finalMsgStr = (data.messages.indexOf(`${parsedMsg[parsedMsg.length-2].replace(/~1/gi,"/")}_${parsedMsg[parsedMsg.length-1].replace(/~1/gi,"/")}`) > -1)? `${parsedMsg[parsedMsg.length-2].replace(/~1/gi,"/")}_${parsedMsg[parsedMsg.length-1].replace(/~1/gi,"/")}`: (parsedMsg.pop() || "").replace(/~1/gi,"/"); + if(data.messages.indexOf(finalMsgStr) > -1) + {data.relations.push(`${finalMsgStr?.replace(/~1/gi,"/")} --> ${operationName}`);} + }); + }); + + Object.entries(operationInfo.channel || {}).map(([channelName, channelInfo]: [string, any])=>{ + let parsedRef = String(channelInfo).split('/'); + if(data.channels.indexOf(parsedRef[parsedRef.length-1].replace(/~1/gi,"/")) > -1) + {data.relations.push(`${operationName} --> ${(parsedRef.pop() || "").replace(/~1/gi,"/")}`);} + }); + } + }); + + return await ejs.renderFile(templatePath,{ + ...data + }); +} \ No newline at end of file diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts index 112aaef..faa50ef 100644 --- a/src/PreviewMarkdown.ts +++ b/src/PreviewMarkdown.ts @@ -8,15 +8,22 @@ import { AvroSchemaParser } from '@asyncapi/avro-schema-parser'; import Asyncapi from './Asyncapi'; import { ISpectralDiagnostic } from '@stoplight/spectral-core'; import { parse } from 'yaml'; +import Flowchart from './Flowchart'; +import ClassDiagram from './ClassDiagram'; + +const parser = new Parser(); +parser.registerSchemaParser(AvroSchemaParser()); function parsedAsyncapiPreview(){ - const editor: any = vscode.window.activeTextEditor; + + const editor: any = vscode.window.activeTextEditor; if(!editor) {return;} const document = editor.document; const filePath: any = document?.fileName; const fullPath = path.resolve(filePath); const content = fs.readFileSync(fullPath, 'utf8'); + let parsedData; if (filePath.endsWith('.json')) { parsedData = JSON.parse(content); @@ -26,13 +33,10 @@ import { parse } from 'yaml'; vscode.window.showInformationMessage('Unsupported file type.'); return; } - - return parsedData; + return parsedData || ""; } -const parser = new Parser(); -parser.registerSchemaParser(AvroSchemaParser()); async function buildMarkdown(document: any, diagnostics: ISpectralDiagnostic[], context: vscode.ExtensionContext){ @@ -64,6 +68,19 @@ async function buildMarkdown(document: any, diagnostics: ISpectralDiagnostic[], } +async function buildDiagrams(context: vscode.ExtensionContext){ + let parsedData: any = parsedAsyncapiPreview(); + let flowchart; + let classDiagram; + + if(parsedData){ + flowchart = await Flowchart(parsedData, context); + classDiagram = await ClassDiagram(parsedData, context); + } + + return {flowchart, classDiagram}; +} + export function previewMarkdown(context: vscode.ExtensionContext) { return async (uri: vscode.Uri) => { uri = uri || (await promptForAsyncapiFile()) as vscode.Uri; @@ -98,10 +115,10 @@ export async function openAsyncAPIMarkdown(context: vscode.ExtensionContext, uri const { document, diagnostics } = await fromFile(parser, uri.fsPath).parse(); let result = await buildMarkdown(document, diagnostics, context); - + let {flowchart, classDiagram} = await buildDiagrams(context); panel.title = path.basename(uri.fsPath); - panel.webview.html = getWebviewContent(context, panel.webview, uri, result); + panel.webview.html = getWebviewContent(context, panel.webview, uri, result, flowchart, classDiagram); panel.onDidDispose(() => { delete openAsyncapiMdFiles[uri.fsPath]; @@ -125,10 +142,13 @@ async function promptForAsyncapiFile() { return uris?.[0]; } -function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Webview, asyncapiFile: vscode.Uri, result:any) { +function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Webview, asyncapiFile: vscode.Uri, result: any, flowchart: any, classDiagram: any) { const mermaidJs = webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/mermaid/dist/mermaid.min.js') ); + const panzoomJs = webview.asWebviewUri( + vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/panzoom/dist/panzoom.min.js') + ); const globalsCSS = webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'dist/globals.css') ); @@ -143,8 +163,22 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web
    ${result}
    -
    Section 2
    -
    Section 3
    +
    ${flowchart}
    +
    ${classDiagram}
    +
    +
    +
    +
    +
    -
    +
    +
    +
    +
    +
    +
    Zoom : 1
    +
    Scroll : 0, 0
    +
    Zoom : 1
    +
    Scroll : 0, 0
    +
    @@ -154,13 +188,147 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web
    + + diff --git a/src/components/classDiagram.ejs b/src/components/classDiagram.ejs index e69de29..72645ac 100644 --- a/src/components/classDiagram.ejs +++ b/src/components/classDiagram.ejs @@ -0,0 +1,59 @@ +
    +    %%{
    +        init: {
    +          'theme': 'base',
    +          "themeVariables": {
    +          "primaryColor": "#fff",
    +          "primaryBorderColor": "#646466",
    +          "tertiaryColor": "#fff"
    +        }
    +        }
    +    }%%
    +    
    +    classDiagram
    +    <% for( let channel of channels){ %>
    +        class <%= channel[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= channel[0] %>"]{
    +            <% for( let prop of Object.entries(channel[1])){ %>
    +                + <%= typeof prop[1] %> <%= prop[0] %>
    +            <% } %>
    +        }
    +    <% } %>
    +    <% for( let operation of operations){ %>
    +        class <%= operation[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= operation[0] %>"]{
    +            <% for( let prop of Object.entries(operation[1])){ %>
    +                + <%= typeof prop[1] %> <%= prop[0] %>
    +            <% } %>
    +        }
    +    <% } %>
    +    <% for( let message of messages){ %>
    +        class <%= message[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= message[0] %>"]{
    +            <% for( let prop of Object.entries(message[1])){ %>
    +                + <%= typeof prop[1] %> <%= prop[0] %>
    +            <% } %>
    +        }
    +    <% } %>
    +    <% for( let payload of payloads){ %>
    +        class <%= payload[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= payload[0] %>"]{
    +            <% Object.getOwnPropertyNames(payload[1]).map(prop=>{ %>
    +                + <%= typeof payload[1][prop] %> <%= prop %>
    +            <% }) %>
    +        }
    +    <% } %>
    +    <% for( let header of headers){ %>
    +        class <%= header[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= header[0] %>"]{
    +            <% Object.getOwnPropertyNames(header[1]).map(prop=>{ %>
    +                + <%= typeof header[1][prop] %> <%= prop %>
    +            <% }) %>
    +        }
    +    <% } %>
    +    <% for( let other of others){ %>
    +        class <%= other[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= other[0] %>"]{
    +            <% Object.getOwnPropertyNames(other[1]).map(prop=>{ %>
    +                + <%= typeof other[1][prop] %> <%= prop %>
    +            <% }) %>
    +        }
    +    <% } %>
    +    <% for( let relation of relations) {  %>
    +        <%= relation %>
    +        <% } %>
    +
    \ No newline at end of file diff --git a/src/components/flowchart.ejs b/src/components/flowchart.ejs index e69de29..e9c2af2 100644 --- a/src/components/flowchart.ejs +++ b/src/components/flowchart.ejs @@ -0,0 +1,26 @@ +
    +    flowchart TD
    +        subgraph "\nServers"
    +        <% for( let server of servers){ %>
    +            <%= server.replaceAll(/[\(\)\[\]\{\}]/g, "")%>(["<%= server %>"])
    +        <% } %> 
    +        end
    +        subgraph "\nChannels"
    +        <% for( let channel of channels){ %>
    +            <%= channel.replaceAll(/[\(\)\[\]\{\}]/g, "")%>(["<%= channel %>"])
    +        <% } %> 
    +        end
    +        subgraph "\nOperations"
    +        <% for( let operation of operations){ %>
    +            <%= operation.replaceAll(/[\(\)\[\]\{\}]/g, "")%>(["<%= operation %>"])
    +        <% } %> 
    +        end
    +        subgraph "\nMessages"
    +        <% for( let message of messages){ %>
    +            <%= message.replaceAll(/[\(\)\[\]\{\}]/g, "")%>(["<%= message %>"])
    +        <% } %> 
    +        end
    +        <% for( let relation of relations) {  %>
    +        <%= relation.replaceAll(/[\(\)\[\]\{\}]/g, "") %>
    +        <% } %>
    +
    \ No newline at end of file diff --git a/src/globals.css b/src/globals.css index 9cbe607..0873491 100644 --- a/src/globals.css +++ b/src/globals.css @@ -1,5 +1,6 @@ html{ scroll-behavior: smooth; + scrollbar-color: unset; } body { color: #121212; @@ -10,6 +11,11 @@ body { display: flex; flex-direction: column; height: 100vh; + user-select: text; +} +::-webkit-scrollbar { + width: 6px!important; + height: 6px!important; } h1 { color: #121212; @@ -19,17 +25,21 @@ h1 { overflow: hidden; } .section { + position: relative; flex: 0 0 100%; box-sizing: border-box; padding: 20px; aspect-ratio: 1; - overflow-y: auto; + overflow: auto; height:calc(100vh - 60px);; } .button-container { display: flex; justify-content: center; margin: 10px; + position: fixed; + bottom: 0px; + width: calc(100% - 25px); } .button { padding: 10px 20px; @@ -247,4 +257,94 @@ a:hover { } .value { color: blue; -} \ No newline at end of file +} + +#section2, #section3{ + display:flex; + justify-content: center; + align-items: center; + width: 100%; +} +.mermaid{ + width: inherit; +} + +#control-panel { + position: absolute; + right: 30px; + bottom: 80px; + width: 120px; + height: 120px; + display: none; + justify-content: center; + align-items: center; + background-color: rgba(0, 0, 0, 0.7); + border-radius: 50%; + padding: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); + user-select: none; +} + +.control-button { + width: 40px; + height: 40px; + background-color: #cbcaca; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + font-size: 25px; + font-weight: bold; + color: #333; + position: absolute; + cursor: pointer; + transition: background-color 0.3s; + box-sizing: border-box; + padding-bottom: 2px; +} + +.control-button:hover { + background-color: #f7f7f7; +} + +#zoom-in { top: 50px; left: 50%; transform: translate(-50%, -50%); } +#zoom-out { top: 50px; left: 50%; transform: translate(-50%, -50%); } +#pan-up { top: 90px; left: 50%; transform: translate(-50%, -100px); } +#pan-down { top: 70px; left: 50%; transform: translate(-50%, 40px); } +#pan-left { top: 70px; left: -10px; transform: translateY(-50%); } +#pan-right { top: 70px; right: -10px; transform: translateY(-50%); } + +#zoom-info { + position: absolute; + display: none; + left: 30px; + bottom: 80px; + background-color: rgba(0, 0, 0, 0.7); + color: #fff; + padding: 10px; + border-radius: 5px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); + flex-direction: column; +} + +#zoom-in { + width: 80px; + height: 40px; + border-top-left-radius: 80px; + border-top-right-radius: 80px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + left: 50%; + transform: translate(-50%, -50%); +} + +#zoom-out { + width: 80px; + height: 40px; + border-bottom-left-radius: 80px; + border-bottom-right-radius: 80px; + border-top-left-radius: 0; + border-top-right-radius: 0; + left: 50%; + transform: translate(-50%, 50%); +} diff --git a/webpack.config.js b/webpack.config.js index e3a84da..b661998 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -64,6 +64,10 @@ const extensionConfig = { from: 'node_modules/mermaid/dist/mermaid.min.js', to: 'node_modules/mermaid/dist/mermaid.min.js', }, + { + from: 'node_modules/panzoom/dist/panzoom.min.js', + to: 'node_modules/panzoom/dist/panzoom.min.js', + }, { from: 'src/components', to: 'components' From 3f024b55922aeff44b6e7a3f96477cf055d7b678 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Sun, 7 Jul 2024 18:46:17 +0530 Subject: [PATCH 12/15] add enhancement to the code and add the export to MD feature --- package-lock.json | 20 + package.json | 2 + src/Asyncapi.ts | 1077 +++++++++++++++++++-------------- src/Diagnostics.ts | 1 - src/Flowchart.ts | 4 + src/PreviewMarkdown.ts | 94 +-- src/components/Asyncapi.ejs | 8 +- src/components/Info.ejs | 14 +- src/components/Message.ejs | 107 ++-- src/components/Operations.ejs | 39 +- src/components/Schema.ejs | 1 - src/components/Security.ejs | 7 +- src/components/Servers.ejs | 64 +- src/components/flowchart.ejs | 8 + src/globals.css | 31 + webpack.config.js | 3 + 16 files changed, 878 insertions(+), 602 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c2f920..27a360c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,10 +11,12 @@ "dependencies": { "@asyncapi/parser": "^3.0.7", "@types/markdown-it": "^13.0.7", + "@types/turndown": "^5.0.4", "ejs": "^3.1.9", "markdown-it": "^14.0.0", "mermaid": "^10.8.0", "panzoom": "^9.4.3", + "turndown": "^7.2.0", "yaml": "^2.4.2" }, "devDependencies": { @@ -311,6 +313,11 @@ "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==", "dev": true }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -808,6 +815,11 @@ "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", "dev": true }, + "node_modules/@types/turndown": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.4.tgz", + "integrity": "sha512-28GI33lCCkU4SGH1GvjDhFgOVr+Tym4PXGBIU1buJUa6xQolniPArtUT+kv42RR2N9MsMLInkr904Aq+ESHBJg==" + }, "node_modules/@types/unist": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", @@ -6559,6 +6571,14 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, + "node_modules/turndown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz", + "integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 05d9394..476226b 100644 --- a/package.json +++ b/package.json @@ -148,10 +148,12 @@ "dependencies": { "@asyncapi/parser": "^3.0.7", "@types/markdown-it": "^13.0.7", + "@types/turndown": "^5.0.4", "ejs": "^3.1.9", "markdown-it": "^14.0.0", "mermaid": "^10.8.0", "panzoom": "^9.4.3", + "turndown": "^7.2.0", "yaml": "^2.4.2" } } diff --git a/src/Asyncapi.ts b/src/Asyncapi.ts index 97b619e..c79415f 100644 --- a/src/Asyncapi.ts +++ b/src/Asyncapi.ts @@ -603,18 +603,33 @@ function addServers(asyncapi: any) { isEmpty: () => (asyncapi.servers ? false : true), all: () => { return Object.entries(asyncapi.servers || {}).map((server: any) => { + let finalServerObject:any = null; + if (server[1]?.$ref) { + const parsedStr = server[1].$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalServerObject = (asyncapi.components?.servers)? [server[0],asyncapi.components.servers[parsedStr[3]]] : server; + } else { + finalServerObject = server; + } return { - id: () => server[0], - url: () => (server[1] && server[1].host ? server[1].host : ''), - protocol: () => (server[1] && server[1].protocol ? server[1].protocol : ''), - protocolVersion: () => '', - hasDescription: () => (server[1] && server[1].description ? true : false), - description: () => (server[1] ? server[1].description : ''), + id: () => finalServerObject[0], + url: () => (finalServerObject[1] && finalServerObject[1].host ? finalServerObject[1].host : finalServerObject[1]?.url), + protocol: () => (finalServerObject[1] && finalServerObject[1].protocol ? finalServerObject[1].protocol : ''), + protocolVersion: () => (finalServerObject[1] && finalServerObject[1].protocolVersion ? finalServerObject[1].protocolVersion : ''), + hasDescription: () => (finalServerObject[1] && finalServerObject[1].description ? true : false), + description: () => (finalServerObject[1] ? finalServerObject[1].description : ''), + summary: () => (finalServerObject[1] ? finalServerObject[1].summary : ''), variables: () => - server[1] && server[1].variables + finalServerObject[1] && finalServerObject[1].variables ? { all: () => - Object.entries(server[1].variables || {}).map((entry: any) => { + Object.entries(finalServerObject[1].variables || {}).map((entry: any) => { + let finalVariablesObject = null; + if (entry[1]?.$ref) { + const parsedStr = entry[1].$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalVariablesObject = (asyncapi.components?.serverVariables)? [entry[0], asyncapi.components.serverVariables[parsedStr[3]]] : entry; + } else { + finalVariablesObject = entry; + } return { id: () => (entry[0] ? entry[0] : ''), description: () => (entry[1] && entry[1].description ? entry[1].description : ''), @@ -627,7 +642,7 @@ function addServers(asyncapi: any) { } : '', security: () => { - return server[1].security?.map((sec: any) => { + return finalServerObject[1].security?.map((sec: any) => { return { all: () => Object.entries(sec || {}).map((security: any) => { @@ -730,23 +745,30 @@ function addServers(asyncapi: any) { extensions: () => { return { all: () => - Object.entries(server[1].extensions || {}).map((extension: any) => { + Object.entries(finalServerObject[1].extensions || {}).map((extension: any) => { return { - id: () => extension[1].id, - value: () => extension[1].value, + id: () => extension[1]?.id, + value: () => extension[1]?.value, }; }), }; }, bindings: () => { return { - isEmpty: () => (server[1].bindings ? false : true), + isEmpty: () => (finalServerObject[1].bindings ? false : true), all: () => { - return Object.entries(server[1].bindings || {}).map((binding: any) => { + return Object.entries(finalServerObject[1].bindings || {}).map((binding: any) => { + let finalBindingsObject:any = null; + if (binding[1]?.$ref) { + const parsedStr = binding[1].$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalBindingsObject = (asyncapi?.components?.serverBindings)? [binding[0], asyncapi.components.serverBindings[parsedStr[3]]] : binding; + } else { + finalBindingsObject = binding; + } return { - protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), - json: () => (binding[1] && binding[1].json ? binding[1].json : ''), - type: () => (binding[1] && binding[1].type ? binding[1].type : ''), + protocol: () => (finalBindingsObject[1] && finalBindingsObject[1].protocol ? finalBindingsObject[1].protocol : ''), + json: () => (finalBindingsObject[1] && finalBindingsObject[1].json ? finalBindingsObject[1].json : ''), + type: () => (finalBindingsObject[1] && finalBindingsObject[1].type ? finalBindingsObject[1].type : ''), }; }); }, @@ -754,19 +776,27 @@ function addServers(asyncapi: any) { }, tags: () => { return { - isEmpty: () => (server[1].tags ? false : true), + isEmpty: () => (finalServerObject[1].tags ? false : true), all: () => - Object.entries(server[1].tags || {}).map((tag: any) => { + Object.entries(finalServerObject[1].tags || {}).map((tag: any) => { return { name: () => (tag[1] && tag[1].name ? tag[1].name : ''), description: () => (tag[1] && tag[1].description ? tag[1].description : ''), - externalDocs: () => - tag[1] && tag[1].externalDocs - ? { - url: () => tag[1].externalDocs.url, - description: () => tag[1].externalDocs.description, - } - : '', + externalDocs: () => { + let finalexternalDocsObject:any = null; + if (tag[1]?.externalDocs?.$ref) { + const parsedStr = tag[1].externalDocs.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalexternalDocsObject = (asyncapi.components?.externalDocs)? asyncapi.components.externalDocs[parsedStr[3]] : tag[1]; + + } else { + finalexternalDocsObject = tag[1]; + } + return { + url: () => finalexternalDocsObject?.externalDocs?.url, + description: () => finalexternalDocsObject?.externalDocs?.description, + hasDescription: () => (finalexternalDocsObject?.externalDocs?.description ? true : false), + }; + }, }; }), }; @@ -778,453 +808,606 @@ function addServers(asyncapi: any) { } export default async function asyncapiMarkdown(asyncapi: any, context: vscode.ExtensionContext) { - const templatePath = path.join(context.extensionPath, 'dist', 'components', 'Asyncapi.ejs'); - if (!asyncapi.isAsyncapiParser) { - return await ejs.renderFile(templatePath, { - info: { - title: asyncapi.info && asyncapi.info.title ? asyncapi.info.title : '', - version: asyncapi.info && asyncapi.info.version ? asyncapi.info.version : '', - defaultContentType: asyncapi.defaultContentType ? asyncapi.defaultContentType : '', - specId: asyncapi.info && asyncapi.info.specId ? asyncapi.info.specId : '', - termsOfService: asyncapi.info && asyncapi.info.termsOfService ? asyncapi.info.termsOfService : '', - license: - asyncapi.info && asyncapi.info.license ? { url: () => asyncapi.info.license.url, name: () => asyncapi.info.license.name } : null, - contact: - asyncapi.info && asyncapi.info.contact - ? { name: () => asyncapi.info.contact.name, url: () => asyncapi.info.contact.url, email: asyncapi.info.contact.email } - : null, - externalDocs: - asyncapi.info && asyncapi.info.externalDocs - ? { url: () => asyncapi.info.externalDocs.url(), description: () => asyncapi.info.externalDocs.description() } - : null, - hasDescription: asyncapi.info && asyncapi.info.description ? true : false, - description: asyncapi.info ? md.render(asyncapi.info.description || '') : '', - tags: { - isEmpty: () => (asyncapi.info.tags ? false : true), - all: () => - Object.entries(asyncapi.info.tags || {}).map((tag: any) => { - return { - name: () => (tag[1] && tag[1].name ? tag[1].name : ''), - description: () => (tag[1] && tag[1].description ? tag[1].description : ''), - externalDocs: () => - tag[1] && tag[1].externalDocs - ? { - url: () => tag[1].externalDocs.url, - description: () => tag[1].externalDocs?.description, - hasDescription: () => (tag[1].externalDocs?.description ? true : false), - } - : '', - }; - }), + try{ + if(!asyncapi || !context) {return;} + const templatePath = path.join(context.extensionPath, 'dist', 'components', 'Asyncapi.ejs'); + if (!asyncapi.isAsyncapiParser) { + return await ejs.renderFile(templatePath, { + info: { + title: asyncapi.info && asyncapi.info.title ? asyncapi.info.title : '', + version: asyncapi.info && asyncapi.info.version ? asyncapi.info.version : '', + defaultContentType: asyncapi.defaultContentType ? asyncapi.defaultContentType : '', + specId: asyncapi.info && asyncapi.info.specId ? asyncapi.info.specId : '', + termsOfService: asyncapi.info && asyncapi.info.termsOfService ? asyncapi.info.termsOfService : '', + license: + asyncapi.info && asyncapi.info.license ? { url: () => asyncapi.info.license.url, name: () => asyncapi.info.license.name } : null, + contact: + asyncapi.info && asyncapi.info.contact + ? { name: () => asyncapi.info.contact.name, url: () => asyncapi.info.contact.url, email:()=> asyncapi.info.contact.email } + : null, + externalDocs: + asyncapi.info && asyncapi.info.externalDocs + ? { url: () => asyncapi.info.externalDocs.url, description: () => (asyncapi.info.externalDocs.description || asyncapi.info.externalDocs.$ref) } + : null, + hasDescription: asyncapi.info && asyncapi.info.description ? true : false, + description: asyncapi.info ? md.render(asyncapi.info.description || '') : '', + tags: { + isEmpty: () => (asyncapi.info.tags ? false : true), + all: () => + Object.entries(asyncapi.info.tags || {}).map((tag: any) => { + return { + name: () => (tag[1] && tag[1].name ? tag[1].name : ''), + description: () => (tag[1] && tag[1].description ? tag[1].description : ''), + externalDocs: () => { + let finalexternalDocsObject:any = null; + if (tag[1]?.externalDocs?.$ref) { + const parsedStr = tag[1].externalDocs.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalexternalDocsObject = (asyncapi.components?.externalDocs)? asyncapi.components.externalDocs[parsedStr[3]] : tag[1]; + } else { + finalexternalDocsObject = tag[1]; + } + return { + url: () => finalexternalDocsObject?.externalDocs?.url, + description: () => finalexternalDocsObject?.externalDocs?.description, + hasDescription: () => (finalexternalDocsObject?.externalDocs?.description ? true : false), + }; + } + }; + }), + }, }, - }, - servers: { - servers: addServers(asyncapi), - schemaHelper: SchemaHelper, - serverHelper: ServerHelper, - md, - }, - operations: { - channels: { - isEmpty: () => (asyncapi.channels ? false : true), - all: () => - Object.entries(asyncapi.channels || {}).map((channel: any) => { - return { - servers: () => addServers(asyncapi), - operations: () => { - return { - all: () => - Object.entries(asyncapi.operations || {}) - .filter( - (operation: any) => operation[1].channel?.$ref.split('channels/').pop().replaceAll('~1', '/') === channel[0] - ) - .map((operation: any) => { - return { - operationId: () => (operation[0] ? operation[0] : ''), - isSend: () => (operation[1] && operation[1].action === 'send' ? true : false), - isReceive: () => (operation[1] && operation[1].action === 'receive' ? true : false), - reply: () => (operation[1] && operation[1].reply ? operation[1].reply : false), - summary: () => (operation[1] && operation[1].summary ? operation[1].summary : ''), - hasDescription: () => (operation[1] && operation[1].description ? true : false), - description: () => (operation[1] && operation[1].description ? operation[1].description : ''), - externalDocs: () => - operation[1] && operation[1].externalDocs - ? { - url: () => operation[1].externalDocs.url, - description: () => operation[1].externalDocs.description, - hasDescription: () => (operation[1].externalDocs.description ? true : false), - } - : '', - tags: () => { - return { - isEmpty: () => (operation[1].tags ? false : true), - all: () => - Object.entries(operation[1].tags || {}).map((tag: any) => { - return { - name: () => (tag[1] && tag[1].name ? tag[1].name : ''), - description: () => (tag[1] && tag[1].description ? tag[1].description : ''), - externalDocs: () => - tag[1] && tag[1].externalDocs - ? { - url: () => tag[1].externalDocs?.url, - description: () => tag[1].externalDocs?.description, - hasDescription: () => (tag[1].externalDocs?.description ? true : false), - } - : '', - }; - }), - }; - }, - extensions: () => { - return { - all: () => - Object(operation[1].extensions).map((extension: any) => { - return { - id: () => extension[1].id, - value: () => extension[1].value, - }; - }), - }; - }, - bindings: () => { - return { - isEmpty: () => (operation[1].bindings ? false : true), - all: () => { - return Object.entries(operation[1].bindings || {}).map((binding: any) => { - return { - protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), - json: () => (binding[1] && binding[1].json ? binding[1].json : ''), - type: () => (binding[1] && binding[1].type ? binding[1].type : ''), + servers: { + servers: addServers(asyncapi), + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + md, + }, + operations: { + channels: { + isEmpty: () => (asyncapi.channels ? false : true), + all: () => + Object.entries(asyncapi.channels || {}).map((channel: any) => { + return { + servers: () => addServers(asyncapi), + operations: () => { + return { + all: () => + Object.entries(asyncapi.operations || { + [channel[1]?.subscribe?.operationId || "subscribe"]: { + ...channel[1]?.subscribe, + "channel": {"$ref": channel[1]?.subscribe? `#/channels/${channel[0]}`: null}, + "action": 'send', + "messages": (!channel[1]?.subscribe?.message?.oneOf)? { + "subscribeMessage": channel[1]?.subscribe?.message + } : channel[1]?.subscribe?.message?.oneOf, + "address": channel[0] + }, + [channel[1]?.publish?.operationId || "publish"]: { + ...channel[1]?.publish, + "channel": {"$ref": channel[1]?.publish? `#/channels/${channel[0]}`: null}, + "action": 'receive', + "messages": (!channel[1]?.publish?.message?.oneOf)? { + "publishMessage": channel[1]?.publish?.message + } : channel[1]?.publish?.message?.oneOf + }}) + .filter( + (operation: any) => operation[1].channel?.$ref?.split('channels/').pop().replaceAll('~1', '/') === channel[0] + ) + .map((operation: any) => { + return { + operationId: () => (operation[0] ? operation[0] : ''), + isSend: () => (operation[1] && operation[1].action === 'send' ? true : false), + isReceive: () => (operation[1] && operation[1].action === 'receive' ? true : false), + reply: () => (operation[1] && operation[1].reply ? operation[1].reply : false), + summary: () => (operation[1] && operation[1].summary ? operation[1].summary : ''), + hasDescription: () => (operation[1] && operation[1].description ? true : false), + description: () => (operation[1] && operation[1].description ? operation[1].description : ''), + externalDocs: () =>{ + let finalexternalDocsObject:any = null; + if (operation[1]?.externalDocs?.$ref) { + const parsedStr = operation[1].externalDocs.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalexternalDocsObject = (asyncapi.components?.externalDocs)? asyncapi.components.externalDocs[parsedStr[3]] : operation[1]; + } else { + finalexternalDocsObject = operation[1]; + } + return { + url: () => finalexternalDocsObject?.externalDocs?.url, + description: () => finalexternalDocsObject?.externalDocs?.description, + hasDescription: () => (finalexternalDocsObject?.externalDocs?.description ? true : false), }; - }); - }, - }; - }, - security: () => { - return operation[1].security?.map((sec: any) => { + }, + tags: () => { return { + isEmpty: () => (operation[1].tags ? false : true), all: () => - Object.entries(sec || {}).map((security: any) => { + Object.entries(operation[1].tags || {}).map((tag: any) => { return { - scheme: () => { - return { - type: () => - asyncapi.components && - asyncapi.components.securitySchemes && - asyncapi.components.securitySchemes[security[1].split('/').pop()] - ? asyncapi.components.securitySchemes[security[1].split('/').pop()].type - : '', - hasDescription: () => - asyncapi.components && - asyncapi.components.securitySchemes && - asyncapi.components.securitySchemes[security[1].split('/').pop()] && - asyncapi.components.securitySchemes[security[1].split('/').pop()].description - ? true - : false, - description: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()].description, - name: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].name, - in: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].in, - bearerFormat: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()].bearerFormat, - openIdConnectUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()].openIdConnectUrl, - scheme: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].scheme, - flows: () => { - if (!asyncapi.components.securitySchemes[security[1].split('/').pop()].flows) { - return; - } - return { - authorizationCode: () => { - return { - authorizationUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()].flows - ?.authorizationCode.authorizationUrl, - refreshUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()].flows - ?.authorizationCode?.refreshUrl, - tokenUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()].flows - ?.authorizationCode?.tokenUrl, - scopes: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()].flows - ?.authorizationCode?.availableScopes || [], - }; - }, - clientCredentials: () => { - return { - authorizationUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows - ?.clientCredentials?.authorizationUrl, - refreshUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows - ?.clientCredentials?.refreshUrl, - tokenUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows - ?.clientCredentials?.tokenUrl, - scopes: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows - ?.clientCredentials?.availableScopes || [], - }; - }, - implicit: () => { - return { - authorizationUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit - ?.authorizationUrl, - refreshUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit - ?.refreshUrl, - tokenUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit - ?.tokenUrl, - scopes: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit - ?.availableScopes || [], - }; - }, - password: () => { - return { - authorizationUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password - ?.authorizationUrl, - refreshUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password - ?.refreshUrl, - tokenUrl: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password - ?.tokenUrl, - scopes: () => - asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password - ?.availableScopes || [], - }; - }, + name: () => (tag[1] && tag[1].name ? tag[1].name : ''), + description: () => (tag[1] && tag[1].description ? tag[1].description : ''), + externalDocs: () =>{ + let finalexternalDocsObject:any = null; + if (tag[1]?.externalDocs?.$ref) { + const parsedStr = tag[1].externalDocs.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalexternalDocsObject = (asyncapi?.components?.externalDocs)? asyncapi.components.externalDocs[parsedStr[3]] : tag[1]; + } else { + finalexternalDocsObject = tag[1]; + } + return { + url: () => finalexternalDocsObject?.externalDocs?.url, + description: () => finalexternalDocsObject?.externalDocs?.description, + hasDescription: () => (finalexternalDocsObject?.externalDocs?.description ? true : false), }; - }, - }; }, - scopes: () => - asyncapi.components && - asyncapi.components.securitySchemes && - asyncapi.components.securitySchemes[security[1].split('/').pop()] - ? asyncapi.components.securitySchemes[security[1].split('/').pop()].scopes || [] - : '', }; }), }; - }); - }, - messages: () => { - return { - all: () => { - let tmp: any = Object.values(operation[1].messages || {}); - if (tmp[0]?.$ref) { - return [{ incorrect: true, refs: Object.values(operation[1].messages || {}) }]; - } - return Object.entries(operation[1].messages || {}).map((message: any) => { - return { - id: () => message[0], - title: () => message[1].title, - name: () => message[1].name, - hasDescription: () => (message[1].description ? true : false), - description: () => message[1].description, - contentType: () => message[1].contentType, - summary: () => message[1].summary, - correlationId: () => { - return { - location: () => message[1].correlationId?.location, - hasDescription: () => (message[1].correlationId ? true : false), - description: () => message[1].correlationId?.description, - }; - }, - externalDocs: () => { - return { - url: () => message[1].externalDocs?.url, - description: () => message[1].externalDocs?.description, - }; - }, - headers: () => { - return { - incorrect: true, - ...message[1].headers, - }; - }, - payload: () => { + }, + extensions: () => { + return { + all: () => + Object.values(operation[1]?.extensions).map((extension: any) => { + return { + id: () => extension?.id, + value: () => extension?.value, + }; + }), + }; + }, + bindings: () => { + return { + isEmpty: () => (operation[1]?.bindings ? false : true), + all: () => { + return Object.entries(operation[1]?.bindings || {}).map((binding: any) => { + let finalBindingsObject:any = null; + if (binding[1]?.$ref) { + const parsedStr = binding[1].$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalBindingsObject = (asyncapi?.components?.operationBindings)? [binding[0], asyncapi.components.operationBindings[parsedStr[3]]] : binding; + } else { + finalBindingsObject = binding; + } + return { + protocol: () => (finalBindingsObject[1] && finalBindingsObject[1].protocol ? finalBindingsObject[1].protocol : ''), + json: () => (finalBindingsObject[1] && finalBindingsObject[1].json ? finalBindingsObject[1].json : ''), + type: () => (finalBindingsObject[1] && finalBindingsObject[1].type ? finalBindingsObject[1].type : ''), + }; + }); + }, + }; + }, + security: () => { + return operation[1]?.security?.map((sec: any) => { + return { + all: () => + Object.entries(sec || {}).map((security: any) => { return { - incorrect: true, - ...message[1].payload, + scheme: () => { + return { + type: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] + ? asyncapi.components.securitySchemes[security[1].split('/').pop()].type + : '', + hasDescription: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] && + asyncapi.components.securitySchemes[security[1].split('/').pop()].description + ? true + : false, + description: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].description, + name: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].name, + in: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].in, + bearerFormat: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].bearerFormat, + openIdConnectUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].openIdConnectUrl, + scheme: () => asyncapi.components.securitySchemes[security[1].split('/').pop()].scheme, + flows: () => { + if (!asyncapi.components.securitySchemes[security[1].split('/').pop()].flows) { + return; + } + return { + authorizationCode: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows + ?.authorizationCode.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows + ?.authorizationCode?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows + ?.authorizationCode?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()].flows + ?.authorizationCode?.availableScopes || [], + }; + }, + clientCredentials: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows + ?.clientCredentials?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows + ?.clientCredentials?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows + ?.clientCredentials?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows + ?.clientCredentials?.availableScopes || [], + }; + }, + implicit: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit + ?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit + ?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit + ?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.implicit + ?.availableScopes || [], + }; + }, + password: () => { + return { + authorizationUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password + ?.authorizationUrl, + refreshUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password + ?.refreshUrl, + tokenUrl: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password + ?.tokenUrl, + scopes: () => + asyncapi.components.securitySchemes[security[1].split('/').pop()]?.flows?.password + ?.availableScopes || [], + }; + }, + }; + }, + }; + }, + scopes: () => + asyncapi.components && + asyncapi.components.securitySchemes && + asyncapi.components.securitySchemes[security[1].split('/').pop()] + ? asyncapi.components.securitySchemes[security[1].split('/').pop()].scopes || [] + : '', }; - }, - tags: () => { + }), + }; + }); + }, + messages: () => { + return { + all: () => { + let tmp: any = Object.values(operation[1].messages || {}); + return tmp.map((value:any)=>{ + let finalMessageObject:any = null; + if (value?.$ref) { + const parsedStr = value.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + if(parsedStr[1] === "channels"){ + const messageInstance = (asyncapi.channels[parsedStr[2]]?.messages)? asyncapi.channels[parsedStr[2]]?.messages[parsedStr[4]] : null; + finalMessageObject = messageInstance?.$ref? asyncapi?.components?.messages[messageInstance?.$ref?.split("/").pop()] : messageInstance; + }else{ + finalMessageObject = (asyncapi?.components?.messages)? asyncapi.components.messages[parsedStr[3]] : null; + } + } else { + finalMessageObject = value; + } return { - isEmpty: () => (operation[1].tags ? false : true), - all: () => - Object.entries(operation[1].tags || {}).map((tag: any) => { + id: () => finalMessageObject?.id, + title: () => finalMessageObject?.title, + name: () => finalMessageObject?.name, + hasDescription: () => (finalMessageObject?.description ? true : false), + description: () => finalMessageObject?.description, + contentType: () => finalMessageObject?.contentType, + summary: () => finalMessageObject?.summary, + correlationId: () => { + let finalcorrelationIdObject:any = null; + if (finalMessageObject?.correlationId?.$ref) { + const parsedStr = finalMessageObject.correlationId.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalcorrelationIdObject = (asyncapi?.components?.correlationIds)? asyncapi.components.correlationIds[parsedStr[3]] : finalMessageObject?.correlationId; + } else { + finalcorrelationIdObject = finalMessageObject?.correlationId; + } + return { + location: () => finalcorrelationIdObject?.location, + hasDescription: () => (finalcorrelationIdObject?.description ? true : false), + description: () => finalcorrelationIdObject?.description, + }; + }, + externalDocs: () => { + let finalexternalDocsObject:any = null; + if (finalMessageObject?.externalDocs?.$ref) { + const parsedStr = finalMessageObject.externalDocs.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalexternalDocsObject = (asyncapi?.components?.externalDocs)? asyncapi.components.externalDocs[parsedStr[3]] : finalMessageObject?.externalDocs; + } else { + finalexternalDocsObject = finalMessageObject?.externalDocs; + } + return { + url: () => finalexternalDocsObject?.url, + description: () => finalexternalDocsObject?.description, + hasDescription: () => (finalexternalDocsObject?.description ? true : false), + }; + }, + headers: () => { + if(finalMessageObject?.headers?.$ref){ + const parsedStr = finalMessageObject.headers.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + let finalHeadersObject = (asyncapi?.components?.schemas)? asyncapi.components.schemas[parsedStr[3]] : finalMessageObject?.headers; return { - name: () => (tag[1] && tag[1].name ? tag[1].name : ''), - description: () => (tag[1] && tag[1].description ? tag[1].description : ''), - externalDocs: () => - tag[1] && tag[1].externalDocs - ? { - url: () => tag[1].externalDocs.url, - description: () => tag[1].externalDocs?.description, - hasDescription: () => (tag[1].externalDocs?.description ? true : false), - } - : '', + incorrect: true, + ...finalHeadersObject, }; - }), - }; - }, - extensions: () => { - return { - all: () => - Object.entries(message[1].extensions || {}).map((extension: any) => { + }else if(finalMessageObject?.headers?.schemaFormat){ return { - id: () => extension[1].id, - value: () => extension[1].value, + incorrect: true, + schemaFormat: finalMessageObject.headers.schemaFormat, + ...finalMessageObject?.headers?.schemaFormat?.schema, }; - }), - }; - }, - bindings: () => { - return { - isEmpty: () => (message[1].bindings ? false : true), - all: () => { - return Object.entries(message[1].bindings || {}).map((binding: any) => { + }else{ return { - protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), - json: () => (binding[1] && binding[1].json ? binding[1].json : ''), - type: () => (binding[1] && binding[1].type ? binding[1].type : ''), + incorrect: true, + ...finalMessageObject?.headers, }; - }); + } }, + payload: () => { + if(finalMessageObject?.payload?.$ref){ + const parsedStr = finalMessageObject.payload.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + let finalPayloadObject = (asyncapi?.components?.schemas)? asyncapi.components.schemas[parsedStr[3]] : finalMessageObject.payload; + return { + incorrect: true, + ...finalPayloadObject, + }; + }else if(finalMessageObject?.payload?.schemaFormat){ + return { + incorrect: true, + schemaFormat: finalMessageObject.payload.schemaFormat, + ...finalMessageObject?.payload?.schemaFormat?.schema, + }; + }else{ + return { + incorrect: true, + ...finalMessageObject?.payload, + }; + } + }, + tags: () => { + return { + isEmpty: () => (finalMessageObject?.tags ? false : true), + all: () => + Object.entries(finalMessageObject?.tags || {}).map((tag: any) => { + return { + name: () => (tag[1] && tag[1].name ? tag[1].name : ''), + description: () => (tag[1] && tag[1].description ? tag[1].description : ''), + externalDocs: () =>{ + let finalexternalDocsObject:any = null; + if (tag[1]?.externalDocs?.$ref) { + const parsedStr = tag[1].externalDocs.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalexternalDocsObject = (asyncapi?.components?.externalDocs)? asyncapi.components.externalDocs[parsedStr[3]] : tag[1]; + } else { + finalexternalDocsObject = tag[1]; + } + return { + url: () => finalexternalDocsObject?.externalDocs?.url, + description: () => finalexternalDocsObject?.externalDocs?.description, + hasDescription: () => (finalexternalDocsObject?.externalDocs?.description ? true : false), + }; + }, + }; + }), + }; + }, + extensions: () => { + return { + all: () => + Object.entries(finalMessageObject?.extensions || {}).map((extension: any) => { + return { + id: () => extension[1]?.id, + value: () => extension[1]?.value, + }; + }), + }; + }, + bindings: () => { + return { + isEmpty: () => (finalMessageObject?.bindings ? false : true), + all: () => { + return Object.entries(finalMessageObject?.bindings || {}).map((binding: any) => { + let finalBindingsObject:any = null; + if (binding[1]?.$ref) { + const parsedStr = binding[1].$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalBindingsObject = (asyncapi?.components?.messageBindings)? [binding[0], asyncapi.components.messageBindings[parsedStr[3]]] : binding; + } else { + finalBindingsObject = binding; + } + return { + protocol: () => (finalBindingsObject[1] && finalBindingsObject[1].protocol ? finalBindingsObject[1].protocol : ''), + json: () => (finalBindingsObject[1] && finalBindingsObject[1].json ? finalBindingsObject[1].json : ''), + type: () => (finalBindingsObject[1] && finalBindingsObject[1].type ? finalBindingsObject[1].type : ''), + }; + }); + }, + }; + }, + traits: ()=>{ + let finalTraitsObject: any = []; + if(Array.isArray(finalMessageObject?.traits)){ + finalMessageObject.traits.map((trait: any)=>{ + if (trait?.$ref) { + const parsedStr = trait.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalTraitsObject.push((asyncapi?.components?.messageTraits)? asyncapi.components.messageTraits[parsedStr[3]] : trait); + } else { + finalTraitsObject.push(trait); + } + }); + } + return {incorrect: true, ...finalTraitsObject}; + } }; - }, - }; - }); + + }); + }, + }; + }, + traits: ()=>{ + let finalTraitsObject: any = []; + if(Array.isArray(operation[1]?.traits)) { + operation[1].traits.map((trait: any)=>{ + if (trait?.$ref) { + const parsedStr = trait.$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalTraitsObject.push((asyncapi?.components?.messageTraits)? asyncapi.components.operationTraits[parsedStr[3]] : trait); + } else { + finalTraitsObject.push(trait); + } + }); + } + return {incorrect: true, ...finalTraitsObject}; + } + }; + }), + }; + }, + address: () => (channel[1]?.address ? channel[1].address : channel[0]), + hasDescription: () => (channel[1] && channel[1].description ? true : false), + description: () => (channel[1] && channel[1].description ? channel[1].description : ''), + parameters: () => { + return { + all: () => + Object.entries(channel[1]?.parameters || {}).map((parameter: any) => { + let finalParametersObject:any = null; + if (parameter[1]?.$ref) { + const parsedStr = parameter[1].$ref.split('/').map((pathComponent: any)=> pathComponent?.replaceAll("~1","/")); + finalParametersObject = (asyncapi.components?.parameters)? [parameter[0], asyncapi.components.parameters[parsedStr[3]]] : parameter; + } else { + finalParametersObject = parameter; + } + return { + id: () => finalParametersObject[0], + schema: () => { + return { + json: () => { + return { + type: finalParametersObject[1]?.schema?.type, + title: finalParametersObject[1]?.schema?.title, + required: finalParametersObject[1]?.schema?.required, + }; }, }; }, + description: () => finalParametersObject[1]?.description, + location: () => finalParametersObject[1]?.location, }; }), - }; - }, - address: () => (channel[1] ? channel[1].address : ''), - hasDescription: () => (channel[1] && channel[1].description ? true : false), - description: () => (channel[1] && channel[1].description ? channel[1].description : ''), - parameters: () => { - return { - all: () => - Object.entries(channel[1].parameters || {}).map((parameter: any) => { - return { - id: () => parameter[0], - schema: () => { - return { - json: () => { - return { - type: parameter[1].schema?.type, - title: parameter[1].schema?.title, - required: parameter[1].schema?.required, - }; - }, - }; - }, - description: () => parameter[1].description, - location: () => parameter[1].location, - }; - }), - }; - }, - extensions: () => { - return { - all: () => - Object.entries(channel[1].extensions || {}).map((extension: any) => { - return { - id: () => extension[1].id, - value: () => extension[1].value, - }; - }), - }; - }, - bindings: () => { - return { - isEmpty: () => (channel[1].bindings ? false : true), - all: () => { - return Object.entries(channel[1].bindings || {}).map((binding: any) => { - return { - protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), - json: () => (binding[1] && binding[1].json ? binding[1].json : ''), - type: () => (binding[1] && binding[1].type ? binding[1].type : ''), - }; - }); - }, - }; - }, - }; - }), + }; + }, + extensions: () => { + return { + all: () => + Object.entries(channel[1]?.extensions || {}).map((extension: any) => { + return { + id: () => extension[1]?.id, + value: () => extension[1]?.value, + }; + }), + }; + }, + bindings: () => { + return { + isEmpty: () => (channel[1]?.bindings ? false : true), + all: () => { + return Object.entries(channel[1]?.bindings || {}).map((binding: any) => { + return { + protocol: () => (binding[1] && binding[1].protocol ? binding[1].protocol : ''), + json: () => (binding[1] && binding[1].json ? binding[1].json : ''), + type: () => (binding[1] && binding[1].type ? binding[1].type : ''), + }; + }); + }, + }; + }, + }; + }), + }, + isV3: asyncapi.asyncapi ? asyncapi.asyncapi.split('.')[0] === '3' : true, + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + messageHelper: MessageHelper, + allServersLength: asyncapi.servers ? Object.keys(asyncapi.servers).length : 0, + md, + }, + path: { + infoPath: path.join(context.extensionPath, 'dist', 'components', 'Info.ejs'), + tagsPath: path.join(context.extensionPath, 'dist', 'components', 'Tags.ejs'), + serversPath: path.join(context.extensionPath, 'dist', 'components', 'Servers.ejs'), + securityPath: path.join(context.extensionPath, 'dist', 'components', 'Security.ejs'), + bindingsPath: path.join(context.extensionPath, 'dist', 'components', 'Bindings.ejs'), + extensionsPath: path.join(context.extensionPath, 'dist', 'components', 'Extensions.ejs'), + schemaPath: path.join(context.extensionPath, 'dist', 'components', 'Schema.ejs'), + operationsPath: path.join(context.extensionPath, 'dist', 'components', 'Operations.ejs'), + messagePath: path.join(context.extensionPath, 'dist', 'components', 'Message.ejs'), + }, + }); + } else { + const info = asyncapi.info(); + return await ejs.renderFile(templatePath, { + info: { + title: info.title(), + version: info.version(), + defaultContentType: asyncapi.defaultContentType(), + specId: info.id(), + termsOfService: info.termsOfService(), + license: info.license(), + contact: info.contact(), + externalDocs: info.externalDocs(), + extensions: info.extensions(), + hasDescription: info.hasDescription(), + description: md.render(info.description() || ''), + tags: info.tags(), + }, + servers: { + servers: asyncapi.servers(), + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + md, + }, + operations: { + channels: asyncapi.channels(), + isV3: asyncapi.version().split('.')[0] === '3', + schemaHelper: SchemaHelper, + serverHelper: ServerHelper, + messageHelper: MessageHelper, + allServersLength: asyncapi.servers().all().length, + md, }, - isV3: asyncapi.asyncapi ? asyncapi.asyncapi.split('.')[0] === '3' : true, - schemaHelper: SchemaHelper, - serverHelper: ServerHelper, - messageHelper: MessageHelper, - allServersLength: asyncapi.servers ? Object.keys(asyncapi.servers).length : 0, - md, - }, - path: { - infoPath: path.join(context.extensionPath, 'dist', 'components', 'Info.ejs'), - tagsPath: path.join(context.extensionPath, 'dist', 'components', 'Tags.ejs'), - serversPath: path.join(context.extensionPath, 'dist', 'components', 'Servers.ejs'), - securityPath: path.join(context.extensionPath, 'dist', 'components', 'Security.ejs'), - bindingsPath: path.join(context.extensionPath, 'dist', 'components', 'Bindings.ejs'), - extensionsPath: path.join(context.extensionPath, 'dist', 'components', 'Extensions.ejs'), - schemaPath: path.join(context.extensionPath, 'dist', 'components', 'Schema.ejs'), - operationsPath: path.join(context.extensionPath, 'dist', 'components', 'Operations.ejs'), - messagePath: path.join(context.extensionPath, 'dist', 'components', 'Message.ejs'), - }, - }); - } else { - const info = asyncapi.info(); - return await ejs.renderFile(templatePath, { - info: { - title: info.title(), - version: info.version(), - defaultContentType: asyncapi.defaultContentType(), - specId: info.id(), - termsOfService: info.termsOfService(), - license: info.license(), - contact: info.contact(), - externalDocs: info.externalDocs(), - extensions: info.extensions(), - hasDescription: info.hasDescription(), - description: md.render(info.description() || ''), - tags: info.tags(), - }, - servers: { - servers: asyncapi.servers(), - schemaHelper: SchemaHelper, - serverHelper: ServerHelper, - md, - }, - operations: { - channels: asyncapi.channels(), - isV3: asyncapi.version().split('.')[0] === '3', - schemaHelper: SchemaHelper, - serverHelper: ServerHelper, - messageHelper: MessageHelper, - allServersLength: asyncapi.servers().all().length, - md, - }, - path: { - infoPath: path.join(context.extensionPath, 'dist', 'components', 'Info.ejs'), - tagsPath: path.join(context.extensionPath, 'dist', 'components', 'Tags.ejs'), - serversPath: path.join(context.extensionPath, 'dist', 'components', 'Servers.ejs'), - securityPath: path.join(context.extensionPath, 'dist', 'components', 'Security.ejs'), - bindingsPath: path.join(context.extensionPath, 'dist', 'components', 'Bindings.ejs'), - extensionsPath: path.join(context.extensionPath, 'dist', 'components', 'Extensions.ejs'), - schemaPath: path.join(context.extensionPath, 'dist', 'components', 'Schema.ejs'), - operationsPath: path.join(context.extensionPath, 'dist', 'components', 'Operations.ejs'), - messagePath: path.join(context.extensionPath, 'dist', 'components', 'Message.ejs'), - }, - }); + path: { + infoPath: path.join(context.extensionPath, 'dist', 'components', 'Info.ejs'), + tagsPath: path.join(context.extensionPath, 'dist', 'components', 'Tags.ejs'), + serversPath: path.join(context.extensionPath, 'dist', 'components', 'Servers.ejs'), + securityPath: path.join(context.extensionPath, 'dist', 'components', 'Security.ejs'), + bindingsPath: path.join(context.extensionPath, 'dist', 'components', 'Bindings.ejs'), + extensionsPath: path.join(context.extensionPath, 'dist', 'components', 'Extensions.ejs'), + schemaPath: path.join(context.extensionPath, 'dist', 'components', 'Schema.ejs'), + operationsPath: path.join(context.extensionPath, 'dist', 'components', 'Operations.ejs'), + messagePath: path.join(context.extensionPath, 'dist', 'components', 'Message.ejs'), + }, + }); + } + + }catch(err){ + console.error(err); } } + + diff --git a/src/Diagnostics.ts b/src/Diagnostics.ts index 5d24ec1..5d2a4f7 100644 --- a/src/Diagnostics.ts +++ b/src/Diagnostics.ts @@ -10,7 +10,6 @@ export default async function diagnosticsMarkdown(diagnostics: ISpectralDiagnost let joinedPath: string = ""; diagnostics.forEach(diagnostic =>{ joinedPath = diagnostic.path.join(' / '); - console.log(joinedPath, recentErrorPath, data.length); if(joinedPath.indexOf(recentErrorPath) === -1 || !recentErrorPath){ recentErrorPath = joinedPath; data.push({ diff --git a/src/Flowchart.ts b/src/Flowchart.ts index 7d4a374..30acc01 100644 --- a/src/Flowchart.ts +++ b/src/Flowchart.ts @@ -75,6 +75,10 @@ export default async function flowchart(asyncapi: any, context: vscode.Extension }); } }); + channelInfo.servers?.map((server: any)=>{ + if(typeof server === "string") + {data.relations.push(`${channelName} --> ${server.replace(/~1/gi,"/")}`);} + }); } }); diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts index faa50ef..5159639 100644 --- a/src/PreviewMarkdown.ts +++ b/src/PreviewMarkdown.ts @@ -14,56 +14,47 @@ import ClassDiagram from './ClassDiagram'; const parser = new Parser(); parser.registerSchemaParser(AvroSchemaParser()); - function parsedAsyncapiPreview(){ - - const editor: any = vscode.window.activeTextEditor; - if(!editor) {return;} - const document = editor.document; - const filePath: any = document?.fileName; - const fullPath = path.resolve(filePath); - const content = fs.readFileSync(fullPath, 'utf8'); - - - let parsedData; - if (filePath.endsWith('.json')) { - parsedData = JSON.parse(content); - } else if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) { - parsedData = parse(content); - } else { - vscode.window.showInformationMessage('Unsupported file type.'); - return; - } - return parsedData || ""; +function parsedAsyncapiPreview(){ + + const editor: any = vscode.window.activeTextEditor; + if(!editor) {return;} + const document = editor.document; + const filePath: any = document?.fileName; + const fullPath = path.resolve(filePath); + const content = fs.readFileSync(fullPath, 'utf8'); + + + let parsedData; + if (filePath.endsWith('.json')) { + parsedData = JSON.parse(content); + } else if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) { + parsedData = parse(content); + } else { + vscode.window.showInformationMessage('Unsupported file type.'); + return; + } + return parsedData || ""; } async function buildMarkdown(document: any, diagnostics: ISpectralDiagnostic[], context: vscode.ExtensionContext){ - - - let content = ''; - + + + let content: any = ''; + if(document !== undefined){ - vscode.window.onDidChangeActiveTextEditor(()=>null); document.isAsyncapiParser = true; - content = await Asyncapi(document, context); + content = await Asyncapi(document, context) || ""; }else{ - content = await Diagnostics(diagnostics, context); - vscode.window.onDidChangeActiveTextEditor(async()=>{ - - let parsedData: any = parsedAsyncapiPreview(); - if(parsedData){ - parsedData.isAsyncapiParser = false; - content += await Asyncapi(parsedData, context); - } - }); let parsedData: any = parsedAsyncapiPreview(); if(parsedData){ parsedData.isAsyncapiParser = false; - content += await Asyncapi(parsedData, context); + content = await Diagnostics(diagnostics, context); + content += await Asyncapi(parsedData, context) || ""; } } - + return content; } @@ -149,6 +140,9 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web const panzoomJs = webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/panzoom/dist/panzoom.min.js') ); + const turndownJs = webview.asWebviewUri( + vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/turndown/dist/turndown.js') + ); const globalsCSS = webview.asWebviewUri( vscode.Uri.joinPath(context.extensionUri, 'dist/globals.css') ); @@ -187,16 +181,20 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web
    - +
    Copy
    +
    Copied!
    + + diff --git a/src/components/Operations.ejs b/src/components/Operations.ejs index 683daba..a00baef 100644 --- a/src/components/Operations.ejs +++ b/src/components/Operations.ejs @@ -20,6 +20,7 @@ type = 'receive'; } } %> + <%- md.render(`${getRenderedTypeForOperation({type})} \`${channel.address()}\` Operation`) %> <% if(operation.summary()) { %> <%- md.render(`*${operation.summary().trim()}*`) %> @@ -84,7 +85,7 @@
      <%= renderObject(operation.traits(), 0) %>
    <% } %> - +
    <% } %> <% } %> <% } %> diff --git a/src/components/classDiagram.ejs b/src/components/classDiagram.ejs index 72645ac..4e0f122 100644 --- a/src/components/classDiagram.ejs +++ b/src/components/classDiagram.ejs @@ -11,49 +11,53 @@ }%% classDiagram + + <% if(!channels.length && !operations.length && !payloads.length && !others.length && !relations.length) { %> + AsyncAPI + <% } %> + <% for( let channel of channels){ %> - class <%= channel[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= channel[0] %>"]{ - <% for( let prop of Object.entries(channel[1])){ %> - + <%= typeof prop[1] %> <%= prop[0] %> + class <%= replaceInvalidChars(`CHANNEL_${channel[0]}`) %>["<%= `${channel[0]}` %>"]{ + <%= `<>` %> + <% for( let prop of Object.entries(channel[1])){ + let parsedRef = String(prop[1]?.$ref).split('/'); + %> + + <%= (Array.isArray(parsedRef))? (parsedRef[parsedRef.length-1]) : typeof prop[1] %> <%= prop[0] %> <% } %> } <% } %> <% for( let operation of operations){ %> - class <%= operation[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= operation[0] %>"]{ - <% for( let prop of Object.entries(operation[1])){ %> - + <%= typeof prop[1] %> <%= prop[0] %> - <% } %> - } - <% } %> - <% for( let message of messages){ %> - class <%= message[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= message[0] %>"]{ - <% for( let prop of Object.entries(message[1])){ %> - + <%= typeof prop[1] %> <%= prop[0] %> - <% } %> + class <%= replaceInvalidChars(`OPERATION_${operation[0]}`) %>["<%= `${operation[0]}` %>"]{ + <%= `<>` %> + <% for( let prop of Object.entries(operation[1])){ + if(String(prop[0]).toLowerCase() === 'action') { %> + + <%= prop[0] %> <%= prop[1] %> + <% } } %> } <% } %> + <% for( let payload of payloads){ %> - class <%= payload[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= payload[0] %>"]{ + class <%= replaceInvalidChars(payload[0]) %>["<%= payload[0] %>"]{ + <%= `<>` %> <% Object.getOwnPropertyNames(payload[1]).map(prop=>{ %> - + <%= typeof payload[1][prop] %> <%= prop %> - <% }) %> - } - <% } %> - <% for( let header of headers){ %> - class <%= header[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= header[0] %>"]{ - <% Object.getOwnPropertyNames(header[1]).map(prop=>{ %> - + <%= typeof header[1][prop] %> <%= prop %> + + <%= payload[1][prop].type || typeof payload[1][prop] %> <%= prop %> <% }) %> } <% } %> - <% for( let other of others){ %> - class <%= other[0].replaceAll(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_") %>["<%= other[0] %>"]{ + + <% for( let other of others){ + let elements = other[0].split('.'); + %> + class <%= replaceInvalidChars(other[0]) %>["<%= elements[elements.length-1] %>"]{ + <%= `<>` %> <% Object.getOwnPropertyNames(other[1]).map(prop=>{ %> - + <%= typeof other[1][prop] %> <%= prop %> + + <%= other[1][prop].type || typeof other[1][prop] %> <%= prop %> <% }) %> } <% } %> <% for( let relation of relations) { %> <%= relation %> <% } %> - \ No newline at end of file + + +<% function replaceInvalidChars(str) { return str.replaceAll(/[`~!@#$%^&*()|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,"_")} %> \ No newline at end of file diff --git a/src/components/flowchart.ejs b/src/components/flowchart.ejs index 3334de5..d574887 100644 --- a/src/components/flowchart.ejs +++ b/src/components/flowchart.ejs @@ -1,3 +1,4 @@ +<% let highlighter = []; %>
         flowchart TD
           <% if(servers?.length) { %>
    @@ -30,5 +31,9 @@
           <% } %>  
             <% for( let relation of relations) {  %>
             <%= relation.replaceAll(/[\(\)\[\]\{\}]/g, "") %>
    +        <% let [leftSideObject, rightSideObject] = relation.replaceAll(/[\(\)\[\]\{\}]/g, "").split(" --> "); %>
    +        
             <% } %>
    -
    \ No newline at end of file + + + \ No newline at end of file diff --git a/src/globals.css b/src/globals.css index dc22c00..ab7ea2d 100644 --- a/src/globals.css +++ b/src/globals.css @@ -379,3 +379,13 @@ a:hover { border-radius: 1px; transition: opacity 0.3s ease-in; } + +.highlight-node { + fill: #96dafb !important; + stroke: #0056b3 !important; +} + +.highlight-edge { + stroke-width: 5px !important; +} + From 2f595bf7a26310e83d891af197dad4156ca02a75 Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Thu, 22 Aug 2024 18:35:22 +0530 Subject: [PATCH 14/15] clean the code and crop the icon image --- .../icons/open-markdown-preview_black.svg | 20 +++++++++---------- .../icons/open-markdown-preview_white.svg | 20 +++++++++---------- src/ClassDiagram.ts | 1 - 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/resources/icons/open-markdown-preview_black.svg b/resources/icons/open-markdown-preview_black.svg index c18526d..f8741fe 100644 --- a/resources/icons/open-markdown-preview_black.svg +++ b/resources/icons/open-markdown-preview_black.svg @@ -1,19 +1,17 @@ - - - + Created with Fabric.js 3.6.6 - - + + - - + + - - + + - - M + + M \ No newline at end of file diff --git a/resources/icons/open-markdown-preview_white.svg b/resources/icons/open-markdown-preview_white.svg index 33ff8bd..f9daea5 100644 --- a/resources/icons/open-markdown-preview_white.svg +++ b/resources/icons/open-markdown-preview_white.svg @@ -1,19 +1,17 @@ - - - + Created with Fabric.js 3.6.6 - - + + - - + + - - + + - - M + + M \ No newline at end of file diff --git a/src/ClassDiagram.ts b/src/ClassDiagram.ts index a5d5368..1a65faa 100644 --- a/src/ClassDiagram.ts +++ b/src/ClassDiagram.ts @@ -241,7 +241,6 @@ export default async function classDiagram(asyncapi: any, context: vscode.Extens } } ); - console.log(data); return await ejs.renderFile(templatePath, { ...data, }); From 4476a790485fe001e97d8333fcf4439ec00ed37c Mon Sep 17 00:00:00 2001 From: nikhilkalburgi Date: Tue, 3 Sep 2024 19:31:39 +0530 Subject: [PATCH 15/15] indexing on the markdown preview --- src/PreviewMarkdown.ts | 97 +++++++++++++++++++++++++- src/components/Info.ejs | 2 +- src/components/Operations.ejs | 124 ++++++++++++++++------------------ src/globals.css | 102 ++++++++++++++++++++++++++++ 4 files changed, 258 insertions(+), 67 deletions(-) diff --git a/src/PreviewMarkdown.ts b/src/PreviewMarkdown.ts index 7367c96..d909ec6 100644 --- a/src/PreviewMarkdown.ts +++ b/src/PreviewMarkdown.ts @@ -192,7 +192,15 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web - +
    +
    <
    +
    >
    +
    +
    +

    Index

    + Info +

    Operations

    +
    ${result}
    ${flowchart}
    @@ -362,7 +370,91 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web const { x, y } = panZoomClassDiagramInstance.getTransform() panZoomClassDiagramInstance.smoothMoveTo(x+50, y); } - }); + }); + + function toggleSection(event) { + const title = event.currentTarget; + const content = title.nextElementSibling; + const arrow = title.querySelector('.arrow'); + + title.style.outline = '0px'; + title.style.border = '0px'; + + if (content?.style?.display === 'none') { + content.style.display = 'block'; + arrow.style.transform = 'rotate(90deg)'; + } else { + content.style.display = 'none'; + arrow.style.transform = 'rotate(0deg)'; + } + } + + const expandContractBtn = document.querySelector('.expand-contract-btn'); + const expandBtn = document.querySelector('.expand-btn'); + const contractBtn = document.querySelector('.contract-btn'); + const index = document.querySelector('#index'); + + expandBtn.addEventListener('click',()=>{ + index.style.width = '20%' ; + index.style.padding = '10px' + expandContractBtn.style.left = "calc(20% - 10px)"; + }) + + contractBtn.addEventListener('click',()=>{ + index.style.width = '0%' ; + index.style.padding = '0px' + expandContractBtn.style.left = "-35px"; + }) + + const indexSections = document.querySelectorAll('.index-section'); + let channelList = []; + let msgList = []; + let newSection = '
    '; + indexSections.forEach((part)=> { + + const channel = part.querySelectorAll('p'); + const operationId = part.querySelectorAll('li'); + const h4Elements = part.querySelectorAll('h4'); + const h5Elements = part.querySelectorAll('h5'); + + channel[0].id = 'id_' + parseInt(Math.random() * 1000 * (channel[0].textContent.length ?? 3)); + operationId[0].id = 'id_' + parseInt(Math.random() * 1000 * (operationId[0].textContent.length ?? 3)); + + newSection += '
    > '+operationId[0].textContent?.replaceAll("Operation ID:","")+'
    '; + }); + + newSection += '

    Channels

      '; + channelList.forEach(element => { + newSection += element; + }); + newSection += '

    Messages

      '; + msgList.forEach(element => { + newSection += element; + }); + newSection += '
    '; + index.innerHTML += newSection; + + // Add event listeners to all section and list item titles + const sectionTitles = document.querySelectorAll('.index-part-title'); + sectionTitles.forEach(title => { + console.log(title); + title.addEventListener('click', toggleSection); + }); }); document.getElementById('copy-button').addEventListener('click', function() { @@ -447,6 +539,7 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web edge.addEventListener('mouseleave', removeHighlights); }); } + diff --git a/src/components/Info.ejs b/src/components/Info.ejs index ae9f241..7bcb6ed 100644 --- a/src/components/Info.ejs +++ b/src/components/Info.ejs @@ -1,4 +1,4 @@ -

    <%= title %> <%= version %> documentation

    +

    <%= title %> <%= version %> documentation

      <% if (specId) { %> diff --git a/src/components/Operations.ejs b/src/components/Operations.ejs index a00baef..88db994 100644 --- a/src/components/Operations.ejs +++ b/src/components/Operations.ejs @@ -6,7 +6,6 @@ <% let type; const applyToAllServers = allServersLength === channel.servers().all().length; const servers = applyToAllServers ? [] : channel.servers().all(); - const showInfoList = operation.operationId() || (servers && servers.length); if (operation.isSend()) { if (operation.reply()) { type = 'request'; @@ -20,72 +19,69 @@ type = 'receive'; } } %> - - <%- md.render(`${getRenderedTypeForOperation({type})} \`${channel.address()}\` Operation`) %> - <% if(operation.summary()) { %> - <%- md.render(`*${operation.summary().trim()}*`) %> - <% } %> - <% if(showInfoList) { %> -
        - <% if(operation.operationId()) { %> -
      • Operation ID: <%= operation.operationId() %>
      • - <% if(servers && servers.length) { %> -
      • Available Only on Server: - <%= servers.map(s => { - const serverId = s.id(); - const slug = FormatHelpers.slugify(serverId); - return `[${serverId}](#${slug}-server)`; - }).join(', ') %> -
      • - <% } %> - <% } %> -
      - <% } %> - <% if(channel.hasDescription()) { %> - <%- md.render(channel.description()) %> - <% } %> - <% if(operation.hasDescription()) { %> - <%- md.render(operation.description()) %> - <% } %> - <% if(operation.externalDocs()?.hasDescription() ) { %> - <%= (operation.externalDocs().description() || 'Find more info here.') %> - <% } %> - - <%- include(tagsPath,{ name:"Operation tags", tags: operation.tags() }) %> - - <% const parameters = schemaHelper.parametersToSchema(channel.parameters().all()); %> - <% if(parameters) { %> -

      Parameters

      - <%- include(schemaPath,{ schema: parameters, schemaName: "Parameters", hideTitle: true, schemaHelper, md, path:"" }) %> - <% } %> - - <%- include(securityPath,{ header:'Additional security requirements', protocol: null, security: operation.security(), serverHelper, md }) %> - - - <%- include(bindingsPath,{ name:"Channel specific information", bindings: channel.bindings(), schemaHelper, schemaPath, md }) %> - <%- include(bindingsPath,{ name:"Operation specific information", bindings: operation.bindings(), schemaHelper, schemaPath, md }) %> - <%- include(extensionsPath,{ name:"Channel extensions", extensions: channel.extensions(), schemaHelper, schemaPath, md }) %> - <%- include(extensionsPath,{ name:"Operation extensions", extensions: operation.extensions(), schemaHelper, schemaPath, md }) %> - - - <% const messages = operation.messages().all(); %> - <% if (messages.length !== 0) { %> - <% const messageText = getOperationMessageText({type}); %> - <% if(messages.length > 1) { %> -

      <%- md.render(messageText) %>

      +
      + <%- md.render(`${getRenderedTypeForOperation({type})} \`${channel.address()}\` Operation`) %> + <% if(operation.summary()) { %> + <%- md.render(`*${operation.summary().trim()}*`) %> + <% } %> +
        +
      • Operation ID: <%= operation.operationId() ?? 'Operation_ID_not_available' %>
      • + <% if(servers && servers.length) { %> +
      • Available Only on Server: + <%= servers.map(s => { + const serverId = s.id(); + const slug = FormatHelpers.slugify(serverId); + return `[${serverId}](#${slug}-server)`; + }).join(', ') %> +
      • + <% } %> +
      + <% if(channel.hasDescription()) { %> + <%- md.render(channel.description()) %> <% } %> - <% for(let message of messages) { %> - <%- include(messagePath,{message, bindingsPath, extensionsPath, schemaHelper, schemaPath, md, messageHelper}) %> + <% if(operation.hasDescription()) { %> + <%- md.render(operation.description()) %> <% } %> + <% if(operation.externalDocs()?.hasDescription() ) { %> + <%= (operation.externalDocs().description() || 'Find more info here.') %> + <% } %> + + <%- include(tagsPath,{ name:"Operation tags", tags: operation.tags() }) %> + + <% const parameters = schemaHelper.parametersToSchema(channel.parameters().all()); %> + <% if(parameters) { %> +

      Parameters

      + <%- include(schemaPath,{ schema: parameters, schemaName: "Parameters", hideTitle: true, schemaHelper, md, path:"" }) %> + <% } %> + + <%- include(securityPath,{ header:'Additional security requirements', protocol: null, security: operation.security(), serverHelper, md }) %> + + + <%- include(bindingsPath,{ name:"Channel specific information", bindings: channel.bindings(), schemaHelper, schemaPath, md }) %> + <%- include(bindingsPath,{ name:"Operation specific information", bindings: operation.bindings(), schemaHelper, schemaPath, md }) %> + <%- include(extensionsPath,{ name:"Channel extensions", extensions: channel.extensions(), schemaHelper, schemaPath, md }) %> + <%- include(extensionsPath,{ name:"Operation extensions", extensions: operation.extensions(), schemaHelper, schemaPath, md }) %> + + + <% const messages = operation.messages().all(); %> + <% if (messages.length !== 0) { %> + <% const messageText = getOperationMessageText({type}); %> + <% if(messages.length > 1) { %> +

      <%- md.render(messageText) %>

      + <% } %> + <% for(let message of messages) { %> + <%- include(messagePath,{message, bindingsPath, extensionsPath, schemaHelper, schemaPath, md, messageHelper}) %> + <% } %> + <% } %> + + <% if(operation.traits().incorrect && Object.values(operation.traits() || []).length > 1) { %> +
      +
      Operation Traits
      +
        <%= renderObject(operation.traits(), 0) %>
      +
      <% } %> - - <% if(operation.traits().incorrect && Object.values(operation.traits() || []).length > 1) { %> -
      -
      Operation Traits
      -
        <%= renderObject(operation.traits(), 0) %>
      -
      - <% } %> -
      +
      +
      <% } %> <% } %> <% } %> diff --git a/src/globals.css b/src/globals.css index ab7ea2d..61578e4 100644 --- a/src/globals.css +++ b/src/globals.css @@ -389,3 +389,105 @@ a:hover { stroke-width: 5px !important; } +#index { + width: 0px; + padding: 0px; + background-color: #bbbbbb; + position: fixed; + height: 100%; + overflow-y: auto; + transition: width 0.4s, padding 0.4s; + z-index: 1; + white-space: nowrap; +} + +.index-part { + width: 40vw; + overflow: hidden; +} + +.index-part-title{ + cursor: pointer; + font-weight: bold; + margin-bottom: 10px; + display: flex; + align-items: center; +} + +#index ul { +list-style-type: none; +padding-left: 15px; +} +#index li { + white-space: nowrap; + padding-bottom: 5px; + width: 100%; + text-overflow: ellipsis; +} + + +.arrow { + display: inline-block; + margin-right: 10px; + transition: transform 0.3s ease; + font-family: cursive; + text-decoration: none; +} + +.index-part-content{ + display: none; + padding-left: 20px; +} + +h4, h5 { + margin-top: 20px; + margin-bottom: 10px; +} + +#index a{ + text-decoration: none; + color: #333; + padding-right: 5px; +} + +#index a:active { + border: 0px; + outline: 0px; +} + +#index a:hover { + text-decoration: underline; +} + +.expand-contract-btn { +display: flex; +flex-direction: row; +justify-content: center; +border: 0.5px solid #c9c8c8; +border-radius: 100%; +position: absolute; +top: 50%; +left: -35px; +z-index: 2; +width: 60px; +height: 60px; +background: #ddd; +transition: left 0.4s; +} + +.contract-btn, .expand-btn { + position: relative; + top: 50%; + transform: translateY(-30px); + font-size: 40px; + font-weight: bolder; + font-family: cursive; + cursor: pointer; +} + +.contract-btn { + border-right: 0.1px solid #8d8c8c; +} +.expand-btn { + border-left: 0.1px solid #8d8c8c; +}