From 7abb5fdfbf12277d210634885dbd63e3135e2422 Mon Sep 17 00:00:00 2001 From: Ansh Goyal Date: Thu, 17 Oct 2024 21:16:31 +0530 Subject: [PATCH 01/91] fix: run tests on branch pushes (#3296) --- .github/workflows/if-nodejs-pr-testing.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/if-nodejs-pr-testing.yml b/.github/workflows/if-nodejs-pr-testing.yml index c50814a4a17..769039d1a0a 100644 --- a/.github/workflows/if-nodejs-pr-testing.yml +++ b/.github/workflows/if-nodejs-pr-testing.yml @@ -4,6 +4,8 @@ name: PR testing - if Node project on: pull_request: types: [opened, reopened, synchronize, ready_for_review] + push: + branches: [master] jobs: test-nodejs-pr: From 9a1c3a62cdee842f1925b914fec76e88c1eaf8bf Mon Sep 17 00:00:00 2001 From: Akshat Nema <76521428+akshatnema@users.noreply.github.com> Date: Fri, 18 Oct 2024 23:17:33 +0530 Subject: [PATCH 02/91] fix: updated CSS for tools/generator page buttons (#3294) Co-authored-by: Ansh Goyal --- pages/tools/generator.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pages/tools/generator.tsx b/pages/tools/generator.tsx index 8a6b70124e5..0453fddf065 100644 --- a/pages/tools/generator.tsx +++ b/pages/tools/generator.tsx @@ -18,7 +18,7 @@ import Paragraph from '../../components/typography/Paragraph'; */ function renderButtons(): JSX.Element { return ( -
+
{/*
); } From 3a8f69ade7562c5753381ec33f9fba2d7ba07ff0 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Sun, 20 Oct 2024 17:29:27 +0200 Subject: [PATCH 03/91] docs(cli): update latest cli documentation (#3306) --- markdown/docs/tools/cli/usage.md | 66 ++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/markdown/docs/tools/cli/usage.md b/markdown/docs/tools/cli/usage.md index 95669e0efd6..269d438fa4d 100644 --- a/markdown/docs/tools/cli/usage.md +++ b/markdown/docs/tools/cli/usage.md @@ -1,11 +1,11 @@ --- -title: 'Usage' +title: "Usage" weight: 40 --- - The AsyncAPI CLI makes it easier to work with AsyncAPI documents. + # Usage + ```sh-session $ npm install -g @asyncapi/cli $ asyncapi COMMAND @@ -33,36 +35,38 @@ USAGE $ asyncapi COMMAND ... ``` + # Commands -* [`asyncapi bundle`](#asyncapi-bundle) -* [`asyncapi config`](#asyncapi-config) -* [`asyncapi config analytics`](#asyncapi-config-analytics) -* [`asyncapi config context`](#asyncapi-config-context) -* [`asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH`](#asyncapi-config-context-add-context-name-spec-file-path) -* [`asyncapi config context current`](#asyncapi-config-context-current) -* [`asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH`](#asyncapi-config-context-edit-context-name-new-spec-file-path) -* [`asyncapi config context init [CONTEXT-FILE-PATH]`](#asyncapi-config-context-init-context-file-path) -* [`asyncapi config context list`](#asyncapi-config-context-list) -* [`asyncapi config context remove CONTEXT-NAME`](#asyncapi-config-context-remove-context-name) -* [`asyncapi config context use CONTEXT-NAME`](#asyncapi-config-context-use-context-name) -* [`asyncapi config versions`](#asyncapi-config-versions) -* [`asyncapi convert [SPEC-FILE]`](#asyncapi-convert-spec-file) -* [`asyncapi diff OLD NEW`](#asyncapi-diff-old-new) -* [`asyncapi generate`](#asyncapi-generate) -* [`asyncapi generate fromTemplate ASYNCAPI TEMPLATE`](#asyncapi-generate-fromtemplate-asyncapi-template) -* [`asyncapi generate models LANGUAGE FILE`](#asyncapi-generate-models-language-file) -* [`asyncapi new`](#asyncapi-new) -* [`asyncapi new file`](#asyncapi-new-file) -* [`asyncapi new glee`](#asyncapi-new-glee) -* [`asyncapi new template`](#asyncapi-new-template) -* [`asyncapi optimize [SPEC-FILE]`](#asyncapi-optimize-spec-file) -* [`asyncapi start`](#asyncapi-start) -* [`asyncapi start studio`](#asyncapi-start-studio) -* [`asyncapi validate [SPEC-FILE]`](#asyncapi-validate-spec-file) + +- [`asyncapi bundle`](#asyncapi-bundle) +- [`asyncapi config`](#asyncapi-config) +- [`asyncapi config analytics`](#asyncapi-config-analytics) +- [`asyncapi config context`](#asyncapi-config-context) +- [`asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH`](#asyncapi-config-context-add-context-name-spec-file-path) +- [`asyncapi config context current`](#asyncapi-config-context-current) +- [`asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH`](#asyncapi-config-context-edit-context-name-new-spec-file-path) +- [`asyncapi config context init [CONTEXT-FILE-PATH]`](#asyncapi-config-context-init-context-file-path) +- [`asyncapi config context list`](#asyncapi-config-context-list) +- [`asyncapi config context remove CONTEXT-NAME`](#asyncapi-config-context-remove-context-name) +- [`asyncapi config context use CONTEXT-NAME`](#asyncapi-config-context-use-context-name) +- [`asyncapi config versions`](#asyncapi-config-versions) +- [`asyncapi convert [SPEC-FILE]`](#asyncapi-convert-spec-file) +- [`asyncapi diff OLD NEW`](#asyncapi-diff-old-new) +- [`asyncapi generate`](#asyncapi-generate) +- [`asyncapi generate fromTemplate ASYNCAPI TEMPLATE`](#asyncapi-generate-fromtemplate-asyncapi-template) +- [`asyncapi generate models LANGUAGE FILE`](#asyncapi-generate-models-language-file) +- [`asyncapi new`](#asyncapi-new) +- [`asyncapi new file`](#asyncapi-new-file) +- [`asyncapi new glee`](#asyncapi-new-glee) +- [`asyncapi new template`](#asyncapi-new-template) +- [`asyncapi optimize [SPEC-FILE]`](#asyncapi-optimize-spec-file) +- [`asyncapi start`](#asyncapi-start) +- [`asyncapi start studio`](#asyncapi-start-studio) +- [`asyncapi validate [SPEC-FILE]`](#asyncapi-validate-spec-file) ## `asyncapi bundle` @@ -715,8 +719,13 @@ USAGE $ asyncapi start ``` + +DESCRIPTION +main command for starting asyncapi services, currently studio only. + _See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/start/index.ts)_ + ## `asyncapi start studio` starts a new local instance of Studio @@ -765,4 +774,5 @@ DESCRIPTION ``` _See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/validate.ts)_ + From 7b7086192a857f0de9527a2301f47385b30baf6a Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Tue, 22 Oct 2024 11:06:36 +0200 Subject: [PATCH 04/91] docs(cli): update latest cli documentation (#3314) --- markdown/docs/tools/cli/usage.md | 121 +++++++++++++++---------------- 1 file changed, 58 insertions(+), 63 deletions(-) diff --git a/markdown/docs/tools/cli/usage.md b/markdown/docs/tools/cli/usage.md index 269d438fa4d..d4cae23662b 100644 --- a/markdown/docs/tools/cli/usage.md +++ b/markdown/docs/tools/cli/usage.md @@ -1,11 +1,11 @@ --- -title: "Usage" +title: 'Usage' weight: 40 --- - The AsyncAPI CLI makes it easier to work with AsyncAPI documents. - # Usage - ```sh-session $ npm install -g @asyncapi/cli $ asyncapi COMMAND running command... $ asyncapi (--version) -@asyncapi/cli/2.5.0 linux-x64 node-v18.20.4 +@asyncapi/cli/2.7.1 linux-x64 node-v18.20.4 $ asyncapi --help [COMMAND] USAGE $ asyncapi COMMAND ... ``` - # Commands - -- [`asyncapi bundle`](#asyncapi-bundle) -- [`asyncapi config`](#asyncapi-config) -- [`asyncapi config analytics`](#asyncapi-config-analytics) -- [`asyncapi config context`](#asyncapi-config-context) -- [`asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH`](#asyncapi-config-context-add-context-name-spec-file-path) -- [`asyncapi config context current`](#asyncapi-config-context-current) -- [`asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH`](#asyncapi-config-context-edit-context-name-new-spec-file-path) -- [`asyncapi config context init [CONTEXT-FILE-PATH]`](#asyncapi-config-context-init-context-file-path) -- [`asyncapi config context list`](#asyncapi-config-context-list) -- [`asyncapi config context remove CONTEXT-NAME`](#asyncapi-config-context-remove-context-name) -- [`asyncapi config context use CONTEXT-NAME`](#asyncapi-config-context-use-context-name) -- [`asyncapi config versions`](#asyncapi-config-versions) -- [`asyncapi convert [SPEC-FILE]`](#asyncapi-convert-spec-file) -- [`asyncapi diff OLD NEW`](#asyncapi-diff-old-new) -- [`asyncapi generate`](#asyncapi-generate) -- [`asyncapi generate fromTemplate ASYNCAPI TEMPLATE`](#asyncapi-generate-fromtemplate-asyncapi-template) -- [`asyncapi generate models LANGUAGE FILE`](#asyncapi-generate-models-language-file) -- [`asyncapi new`](#asyncapi-new) -- [`asyncapi new file`](#asyncapi-new-file) -- [`asyncapi new glee`](#asyncapi-new-glee) -- [`asyncapi new template`](#asyncapi-new-template) -- [`asyncapi optimize [SPEC-FILE]`](#asyncapi-optimize-spec-file) -- [`asyncapi start`](#asyncapi-start) -- [`asyncapi start studio`](#asyncapi-start-studio) -- [`asyncapi validate [SPEC-FILE]`](#asyncapi-validate-spec-file) +* [`asyncapi bundle`](#asyncapi-bundle) +* [`asyncapi config`](#asyncapi-config) +* [`asyncapi config analytics`](#asyncapi-config-analytics) +* [`asyncapi config context`](#asyncapi-config-context) +* [`asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH`](#asyncapi-config-context-add-context-name-spec-file-path) +* [`asyncapi config context current`](#asyncapi-config-context-current) +* [`asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH`](#asyncapi-config-context-edit-context-name-new-spec-file-path) +* [`asyncapi config context init [CONTEXT-FILE-PATH]`](#asyncapi-config-context-init-context-file-path) +* [`asyncapi config context list`](#asyncapi-config-context-list) +* [`asyncapi config context remove CONTEXT-NAME`](#asyncapi-config-context-remove-context-name) +* [`asyncapi config context use CONTEXT-NAME`](#asyncapi-config-context-use-context-name) +* [`asyncapi config versions`](#asyncapi-config-versions) +* [`asyncapi convert [SPEC-FILE]`](#asyncapi-convert-spec-file) +* [`asyncapi diff OLD NEW`](#asyncapi-diff-old-new) +* [`asyncapi generate`](#asyncapi-generate) +* [`asyncapi generate fromTemplate ASYNCAPI TEMPLATE`](#asyncapi-generate-fromtemplate-asyncapi-template) +* [`asyncapi generate models LANGUAGE FILE`](#asyncapi-generate-models-language-file) +* [`asyncapi new`](#asyncapi-new) +* [`asyncapi new file`](#asyncapi-new-file) +* [`asyncapi new glee`](#asyncapi-new-glee) +* [`asyncapi new template`](#asyncapi-new-template) +* [`asyncapi optimize [SPEC-FILE]`](#asyncapi-optimize-spec-file) +* [`asyncapi start`](#asyncapi-start) +* [`asyncapi start studio`](#asyncapi-start-studio) +* [`asyncapi validate [SPEC-FILE]`](#asyncapi-validate-spec-file) ## `asyncapi bundle` @@ -103,7 +99,7 @@ EXAMPLES $ asyncapi bundle ./asyncapi.yaml -o final-asyncapi.yaml --base ../public-api/main.yaml --baseDir ./social-media/comments-service ``` -_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/bundle.ts)_ +_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/bundle.ts)_ ## `asyncapi config` @@ -117,7 +113,7 @@ DESCRIPTION CLI config settings ``` -_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/index.ts)_ +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/index.ts)_ ## `asyncapi config analytics` @@ -137,7 +133,7 @@ DESCRIPTION Enable or disable analytics for metrics collection ``` -_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/analytics.ts)_ +_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/analytics.ts)_ ## `asyncapi config context` @@ -151,7 +147,7 @@ DESCRIPTION Manage short aliases for full paths to AsyncAPI documents ``` -_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/context/index.ts)_ +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/index.ts)_ ## `asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH` @@ -173,7 +169,7 @@ DESCRIPTION Add a context to the store ``` -_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/context/add.ts)_ +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/add.ts)_ ## `asyncapi config context current` @@ -190,7 +186,7 @@ DESCRIPTION Shows the current context that is being used ``` -_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/context/current.ts)_ +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/current.ts)_ ## `asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` @@ -211,7 +207,7 @@ DESCRIPTION Edit a context in the store ``` -_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/context/edit.ts)_ +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/edit.ts)_ ## `asyncapi config context init [CONTEXT-FILE-PATH]` @@ -234,7 +230,7 @@ DESCRIPTION Initialize context ``` -_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/context/init.ts)_ +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/init.ts)_ ## `asyncapi config context list` @@ -251,7 +247,7 @@ DESCRIPTION List all the stored contexts in the store ``` -_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/context/list.ts)_ +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/list.ts)_ ## `asyncapi config context remove CONTEXT-NAME` @@ -271,7 +267,7 @@ DESCRIPTION Delete a context from the store ``` -_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/context/remove.ts)_ +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/remove.ts)_ ## `asyncapi config context use CONTEXT-NAME` @@ -291,7 +287,7 @@ DESCRIPTION Set a context as current ``` -_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/context/use.ts)_ +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/use.ts)_ ## `asyncapi config versions` @@ -308,7 +304,7 @@ DESCRIPTION Show versions of AsyncAPI tools used ``` -_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/config/versions.ts)_ +_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/versions.ts)_ ## `asyncapi convert [SPEC-FILE]` @@ -336,7 +332,7 @@ DESCRIPTION Convert asyncapi documents older to newer versions or OpenAPI/postman-collection documents to AsyncAPI ``` -_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/convert.ts)_ +_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/convert.ts)_ ## `asyncapi diff OLD NEW` @@ -376,7 +372,7 @@ DESCRIPTION Find diff between two asyncapi files ``` -_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/diff.ts)_ +_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/diff.ts)_ ## `asyncapi generate` @@ -390,7 +386,7 @@ DESCRIPTION Generate typed models or other things like clients, applications or docs using AsyncAPI Generator templates. ``` -_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/generate/index.ts)_ +_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/generate/index.ts)_ ## `asyncapi generate fromTemplate ASYNCAPI TEMPLATE` @@ -435,7 +431,7 @@ EXAMPLES $ asyncapi generate fromTemplate asyncapi.yaml @asyncapi/html-template --param version=1.0.0 singleFile=true --output ./docs --force-write ``` -_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/generate/fromTemplate.ts)_ +_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/generate/fromTemplate.ts)_ ## `asyncapi generate models LANGUAGE FILE` @@ -506,7 +502,7 @@ DESCRIPTION Generates typed models ``` -_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/generate/models.ts)_ +_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/generate/models.ts)_ ## `asyncapi new` @@ -564,7 +560,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/new/index.ts)_ +_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/new/index.ts)_ ## `asyncapi new file` @@ -622,7 +618,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/new/file.ts)_ +_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/new/file.ts)_ ## `asyncapi new glee` @@ -644,7 +640,7 @@ DESCRIPTION Creates a new Glee project ``` -_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/new/glee.ts)_ +_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/new/glee.ts)_ ## `asyncapi new template` @@ -668,7 +664,7 @@ DESCRIPTION Creates a new template ``` -_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/new/template.ts)_ +_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/new/template.ts)_ ## `asyncapi optimize [SPEC-FILE]` @@ -710,21 +706,21 @@ EXAMPLES $ asyncapi optimize ./asyncapi.yaml --ignore=schema ``` -_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/optimize.ts)_ +_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/optimize.ts)_ ## `asyncapi start` +Starts AsyncAPI-related services. Currently, it supports launching the AsyncAPI Studio + ``` USAGE $ asyncapi start -``` - DESCRIPTION -main command for starting asyncapi services, currently studio only. - -_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/start/index.ts)_ + Starts AsyncAPI-related services. Currently, it supports launching the AsyncAPI Studio +``` +_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/start/index.ts)_ ## `asyncapi start studio` @@ -743,7 +739,7 @@ DESCRIPTION starts a new local instance of Studio ``` -_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/start/studio.ts)_ +_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/start/studio.ts)_ ## `asyncapi validate [SPEC-FILE]` @@ -773,6 +769,5 @@ DESCRIPTION validate asyncapi file ``` -_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.5.0/src/commands/validate.ts)_ - +_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/validate.ts)_ From 2be7824492b6228f376ba853bf62d6d0bb715aca Mon Sep 17 00:00:00 2001 From: Akshat Nema <76521428+akshatnema@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:06:24 +0530 Subject: [PATCH 05/91] fix: fixed dashboard scripts (#3304) Co-authored-by: Ansh Goyal %0ACo-authored-by: asyncapi-bot --- .../regenerate-meetings-and-videos.yml | 8 +- components/newsroom/Newsroom.tsx | 10 +- scripts/dashboard/build-dashboard.js | 190 +++++++++--------- 3 files changed, 106 insertions(+), 102 deletions(-) diff --git a/.github/workflows/regenerate-meetings-and-videos.yml b/.github/workflows/regenerate-meetings-and-videos.yml index 72aeda4e9e6..34509995d06 100644 --- a/.github/workflows/regenerate-meetings-and-videos.yml +++ b/.github/workflows/regenerate-meetings-and-videos.yml @@ -1,6 +1,6 @@ name: List everyday latest list of AsyncAPI Meetings, Newsroom Videos and Dashboard data. -on: +on: workflow_dispatch: schedule: #every day at midnight @@ -23,7 +23,7 @@ jobs: - name: Check package-lock version uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master id: lockversion - + - name: Use Node.js uses: actions/setup-node@v3 with: @@ -45,7 +45,7 @@ jobs: committer: asyncapi-bot author: asyncapi-bot title: 'chore: update meetings.json and newsrooom_videos.json' - branch: update-meetings/${{ github.job }} + branch: update-meetings/${{ github.sha }} - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel name: Report workflow run status to Slack uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #using https://github.com/8398a7/action-slack/releases/tag/v3.15.1 @@ -54,4 +54,4 @@ jobs: fields: repo,action,workflow text: 'AsyncAPI Meetings and Videos workflow failed' env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} \ No newline at end of file + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} diff --git a/components/newsroom/Newsroom.tsx b/components/newsroom/Newsroom.tsx index 87b8bdff180..a88c4e2f14c 100644 --- a/components/newsroom/Newsroom.tsx +++ b/components/newsroom/Newsroom.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { TwitterTimelineEmbed } from 'react-twitter-embed'; import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading'; import { ParagraphTypeStyle } from '@/types/typography/Paragraph'; @@ -69,19 +68,14 @@ export default function Newsroom() {
-
+
-
+
-
-
- -
-
diff --git a/scripts/dashboard/build-dashboard.js b/scripts/dashboard/build-dashboard.js index 49fbf8b5d4f..120109a05c2 100644 --- a/scripts/dashboard/build-dashboard.js +++ b/scripts/dashboard/build-dashboard.js @@ -1,34 +1,90 @@ const { writeFileSync } = require('fs'); const { resolve } = require('path'); const { graphql } = require('@octokit/graphql'); -const { Promise } = require('node-fetch'); const { Queries } = require('./issue-queries'); -async function getHotDiscussions(discussions) { - const result = await Promise.all( - discussions.map(async (discussion) => { +/** + * Introduces a delay in the execution flow. + * @param {number} ms - The number of milliseconds to pause. + * @returns {Promise} A promise that resolves after the specified delay. + */ +async function pause(ms) { + return new Promise((res) => { + setTimeout(res, ms); + }); +} + +async function getDiscussions(query, pageSize, endCursor = null) { + try { + const result = await graphql(query, { + first: pageSize, + after: endCursor, + headers: { + authorization: `token ${process.env.GITHUB_TOKEN}` + } + }); + + if (result.rateLimit.remaining <= 100) { + console.log( + `[WARNING] GitHub GraphQL rateLimit`, + `cost = ${result.rateLimit.cost}`, + `limit = ${result.rateLimit.limit}`, + `remaining = ${result.rateLimit.remaining}`, + `resetAt = ${result.rateLimit.resetAt}` + ); + } + + await pause(500); + + const { hasNextPage } = result.search.pageInfo; + + if (!hasNextPage) { + return result.search.nodes; + } + return result.search.nodes.concat(await getDiscussions(query, pageSize, result.search.pageInfo.endCursor)); + } catch (e) { + console.error(e); + + return Promise.reject(e); + } +} +async function getDiscussionByID(isPR, id) { + try { + const result = await graphql(isPR ? Queries.pullRequestById : Queries.issueById, { + id, + headers: { + authorization: `token ${process.env.GITHUB_TOKEN}` + } + }); + + return result; + } catch (e) { + console.error(e); + + return Promise.reject(e); + } +} + +async function processHotDiscussions(batch) { + return Promise.all( + batch.map(async (discussion) => { try { + // eslint-disable-next-line no-underscore-dangle const isPR = discussion.__typename === 'PullRequest'; if (discussion.comments.pageInfo.hasNextPage) { - let fetchedDiscussion = await getDiscussionByID(isPR, discussion.id); + const fetchedDiscussion = await getDiscussionByID(isPR, discussion.id); discussion = fetchedDiscussion.node; } const interactionsCount = discussion.reactions.totalCount + discussion.comments.totalCount + - discussion.comments.nodes.reduce( - (acc, curr) => acc + curr.reactions.totalCount, - 0 - ); + discussion.comments.nodes.reduce((acc, curr) => acc + curr.reactions.totalCount, 0); const finalInteractionsCount = isPR ? interactionsCount + - discussion.reviews.totalCount + - discussion.reviews.nodes.reduce( - (acc, curr) => acc + curr.comments.totalCount, - 0 - ) + discussion.reviews.totalCount + + discussion.reviews.nodes.reduce((acc, curr) => acc + curr.comments.totalCount, 0) : interactionsCount; return { id: discussion.id, @@ -37,31 +93,38 @@ async function getHotDiscussions(discussions) { title: discussion.title, author: discussion.author ? discussion.author.login : '', resourcePath: discussion.resourcePath, - repo: 'asyncapi/' + discussion.repository.name, + repo: `asyncapi/${discussion.repository.name}`, labels: discussion.labels ? discussion.labels.nodes : [], - score: - finalInteractionsCount / - Math.pow(monthsSince(discussion.timelineItems.updatedAt) + 2, 1.8), + score: finalInteractionsCount / (monthsSince(discussion.timelineItems.updatedAt) + 2) ** 1.8 }; } catch (e) { - console.error( - `there was some issues while parsing this item: ${JSON.stringify( - discussion - )}` - ); + console.error(`there was some issues while parsing this item: ${JSON.stringify(discussion)}`); throw e; } }) ); +} + +async function getHotDiscussions(discussions) { + const result = []; + const batchSize = 5; + + for (let i = 0; i < discussions.length; i += batchSize) { + const batch = discussions.slice(i, i + batchSize); + // eslint-disable-next-line no-await-in-loop + const batchResults = await processHotDiscussions(batch); + + // eslint-disable-next-line no-await-in-loop + await pause(1000); + + result.push(...batchResults); + } result.sort((ElemA, ElemB) => ElemB.score - ElemA.score); - const filteredResult = result.filter(issue => issue.author !== 'asyncapi-bot'); + const filteredResult = result.filter((issue) => issue.author !== 'asyncapi-bot'); return filteredResult.slice(0, 12); } async function writeToFile(content) { - writeFileSync( - resolve(__dirname, '..', '..', 'dashboard.json'), - JSON.stringify(content, null, ' ') - ); + writeFileSync(resolve(__dirname, '..', '..', 'dashboard.json'), JSON.stringify(content, null, ' ')); } async function mapGoodFirstIssues(issues) { return issues.map((issue) => ({ @@ -69,25 +132,20 @@ async function mapGoodFirstIssues(issues) { title: issue.title, isAssigned: !!issue.assignees.totalCount, resourcePath: issue.resourcePath, - repo: 'asyncapi/' + issue.repository.name, + repo: `asyncapi/${issue.repository.name}`, author: issue.author.login, area: getLabel(issue, 'area/') || 'Unknown', labels: issue.labels.nodes.filter( - (label) => - !label.name.startsWith('area/') && - !label.name.startsWith('good first issue') - ), + (label) => !label.name.startsWith('area/') && !label.name.startsWith('good first issue') + ) })); } function getLabel(issue, filter) { - const result = issue.labels.nodes.find((label) => - label.name.startsWith(filter) - ); - return result && result.name.split('/')[1]; + const result = issue.labels.nodes.find((label) => label.name.startsWith(filter)); + return result?.name.split('/')[1]; } - function monthsSince(date) { const seconds = Math.floor((new Date() - new Date(date)) / 1000); // 2592000 = number of seconds in a month = 30 * 24 * 60 * 60 @@ -95,72 +153,24 @@ function monthsSince(date) { return Math.floor(months); } -async function getDiscussions(query, pageSize, endCursor = null) { - try { - let result = await graphql(query, { - first: pageSize, - after: endCursor, - headers: { - authorization: `token ${process.env.GITHUB_TOKEN}`, - }, - }); - - if (result.rateLimit.remaining <= 100) { - console.log( - `[WARNING] GitHub GraphQL rateLimit`, - `cost = ${result.rateLimit.cost}`, - `limit = ${result.rateLimit.limit}`, - `remaining = ${result.rateLimit.remaining}`, - `resetAt = ${result.rateLimit.resetAt}` - ) - } - - const hasNextPage = result.search.pageInfo.hasNextPage; - - if (!hasNextPage) { - return result.search.nodes; - } else { - return result.search.nodes.concat( - await getDiscussions(query, pageSize, result.search.pageInfo.endCursor) - ); - } - } catch (e) { - console.error(e); - } -} -async function getDiscussionByID(isPR, id) { - try { - let result = await graphql(isPR ? Queries.pullRequestById : Queries.issueById, { - id, - headers: { - authorization: `token ${process.env.GITHUB_TOKEN}`, - }, - - } - ); - return result; - } catch (e) { - console.error(e); - } -} async function start() { try { const [issues, PRs, rawGoodFirstIssues] = await Promise.all([ getDiscussions(Queries.hotDiscussionsIssues, 20), getDiscussions(Queries.hotDiscussionsPullRequests, 20), - getDiscussions(Queries.goodFirstIssues, 20), + getDiscussions(Queries.goodFirstIssues, 20) ]); const discussions = issues.concat(PRs); const [hotDiscussions, goodFirstIssues] = await Promise.all([ getHotDiscussions(discussions), - mapGoodFirstIssues(rawGoodFirstIssues), + mapGoodFirstIssues(rawGoodFirstIssues) ]); writeToFile({ hotDiscussions, goodFirstIssues }); } catch (e) { - console.log('There were some issues parsing data from github.') + console.log('There were some issues parsing data from github.'); console.log(e); } } start(); -module.exports = { getLabel, monthsSince, mapGoodFirstIssues, getHotDiscussions, getDiscussionByID } \ No newline at end of file +module.exports = { getLabel, monthsSince, mapGoodFirstIssues, getHotDiscussions, getDiscussionByID }; From 6387b719d63f6893d6731e50fb70403a5f1d8667 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Wed, 23 Oct 2024 06:49:26 +0200 Subject: [PATCH 06/91] chore: update meetings.json and newsrooom_videos.json (#3316) --- config/meetings.json | 255 ++++++++++++++---------------------- config/newsroom_videos.json | 40 +++--- 2 files changed, 117 insertions(+), 178 deletions(-) diff --git a/config/meetings.json b/config/meetings.json index d17a57704fd..4fbe2b0b8e2 100644 --- a/config/meetings.json +++ b/config/meetings.json @@ -1,224 +1,163 @@ [ { - "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=ZzZ0OG1iNmkyZW5lbnF2bnE5ZnY5ZW9ua28gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1067", - "banner": "https://github.com/asyncapi/community/assets/40604284/897e0278-8da4-41dc-b2b2-b5add9370d6f", - "date": "2024-02-20T16:00:00.000Z" - }, - { - "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=dHJ1dGxncm81b3VvZjI0ZjE1MDkxY25lcjggY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1068", - "banner": "https://github.com/asyncapi/community/assets/40604284/70eff71e-5de5-4c99-bc89-86a1b9b81e81", - "date": "2024-03-05T08:00:00.000Z" - }, - { - "title": "Essential building blocks for AsyncAPI", - "calLink": "https://www.google.com/calendar/event?eid=dmoyY2ZjNXZ1cDh2cGRiZzFnNG92YzQzZHMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1084", + "title": "Essential Building Blocks Working Group", + "calLink": "https://www.google.com/calendar/event?eid=M2pxNGNwZnRqNGpjcDg2cXVnc3VqZ2wwMHMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1294", "banner": "", - "date": "2024-03-12T20:00:00.000Z" - }, - { - "title": "AACoT'24 Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=aG9xMzUyam82cDluaDNpY2c2aDBlb25pdDggY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1087", - "banner": "https://github.com/asyncapi/community/assets/66913810/43114d9e-ee7f-4479-8714-475d67a374aa", - "date": "2024-03-13T14:00:00.000Z" + "date": "2024-07-16T18:00:00.000Z" }, { "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=OTE2Y3YxdGVzNzhqNXJrZThqYml0M2Uwa2MgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1103", - "banner": "https://github-production-user-asset-6210df.s3.amazonaws.com/40604284/313431824-6d286502-6a69-4584-9c01-a2f6984d8320.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240316%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240316T213213Z&X-Amz-Expires=300&X-Amz-Signature=558069f389931870f0ec70cc3f7f4e3bf0e1c4f669a2bd74763f6ed5ae4b2206&X-Amz-SignedHeaders=host&actor_id=40604284&key_id=0&repo_id=347621559", - "date": "2024-03-19T08:00:00.000Z" + "calLink": "https://www.google.com/calendar/event?eid=am5kcG50YW9obGUzcmVucWZqMTQ4NDlsbjQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1305", + "banner": "https://github.com/asyncapi/community/assets/40604284/65376079-c5e8-467d-b513-21dfaba4570f", + "date": "2024-07-23T16:00:00.000Z" }, { - "title": "Let's talk about contributing GSoC FAQ", - "calLink": "https://www.google.com/calendar/event?eid=ZmVkcTI2aTNsZjhwcHZuNWZhb2UwNHE1a2MgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1104", - "banner": "https://github-production-user-asset-6210df.s3.amazonaws.com/40604284/313431821-e905e25c-87b1-466a-adc5-e8551556d7ba.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240316%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240316T213412Z&X-Amz-Expires=300&X-Amz-Signature=4bbf99e0b0da3bfd2b5c3a42394f49314acf5cec64be0394487a5809dc489d71&X-Amz-SignedHeaders=host&actor_id=40604284&key_id=0&repo_id=347621559", - "date": "2024-03-21T14:00:00.000Z" - }, - { - "title": "Essential building blocks", - "calLink": "https://www.google.com/calendar/event?eid=cjFnc2VrNjIzMGZmOXE2Y2FqazF1aHJobWMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1107", + "title": "Marketing WG Meeting", + "calLink": "https://www.google.com/calendar/event?eid=Z3NzN2JvcjdnY2diMnJpczA4dWMxMGh2ZGcgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1309", "banner": "", - "date": "2024-03-26T18:00:00.000Z" + "date": "2024-07-16T14:00:00.000Z" }, { - "title": "Essential building blocks", - "calLink": "https://www.google.com/calendar/event?eid=NW42YmtrcTl1ajRscThmMm9qMzhqMG05dHMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1108", + "title": "Marketing WG Meeting", + "calLink": "https://www.google.com/calendar/event?eid=b2twOWkyZ3ExcGxnYnAxbzBobzA1MWxvcW8gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1321", "banner": "", - "date": "2024-04-02T18:00:00.000Z" + "date": "2024-07-30T14:00:00.000Z" }, { - "title": "AsyncAPI Marketing in 2024 - kick off", - "calLink": "https://www.google.com/calendar/event?eid=bmkyZm9pMzZhNjNjM2RwMjllOHB1YnEwczggY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1109", - "banner": "", - "date": "2024-03-26T14:00:00.000Z" - }, - { - "title": "AACoT'24 Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=c24wbzZkM2VqMTh1MjUzNGoxOGszZXBxOGMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1110", - "banner": "https://github.com/asyncapi/community/assets/66913810/8769dbe0-baef-42f7-b55e-74f5a288da55", - "date": "2024-03-27T14:00:00.000Z" - }, - { - "title": "Community Growth Working Group", - "calLink": "https://www.google.com/calendar/event?eid=MXU4ZXJnOW5sbWZuOW5ndmE3MGwyYzRvdjggY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1118", + "title": "Essential Building Blocks Working Group", + "calLink": "https://www.google.com/calendar/event?eid=YzYyaHNiNTdqbGQ1OTNybjE1NDZlb2ppODAgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1331", "banner": "", - "date": "2024-03-27T16:00:00.000Z" + "date": "2024-08-13T18:00:00.000Z" }, { "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=bWdldGthMGpycXBtaHZ2MXA0dmJlOGpvOXMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1123", - "banner": "https://github.com/asyncapi/community/assets/40604284/10c8e2ef-8c1b-4758-9751-d37a7e123864", - "date": "2024-04-02T16:00:00.000Z" + "calLink": "https://www.google.com/calendar/event?eid=aG45bXYwN2I4NWthanBpZ290bzRnbjE1cWMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1335", + "banner": "https://github.com/user-attachments/assets/9d68eacc-c5b3-4f49-a7a2-4120ead380b0", + "date": "2024-08-06T08:00:00.000Z" }, { "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=ZGRuZ290dGk0aGQ3cmtoMXFhc205NHVsYW8gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1124", - "banner": "https://github.com/asyncapi/community/assets/40604284/e4085ee6-6e1a-45d7-8bbe-11b44432f8ef", - "date": "2024-04-16T08:00:00.000Z" + "calLink": "https://www.google.com/calendar/event?eid=cnIwc3U0c2o1a3FoaWM0M2VvZXFjNzJvZzQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1336", + "banner": "https://github.com/user-attachments/assets/7756ebe2-f8c7-4bda-91e3-6a678c1fad99", + "date": "2024-08-20T16:00:00.000Z" }, { - "title": "Cheat Sheet Poster - Content discussion", - "calLink": "https://www.google.com/calendar/event?eid=dHA1MWNlZTl2c3RkOWxwdTk4YzBkZWtxcGMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1126", + "title": "Marketing WG Meeting", + "calLink": "https://www.google.com/calendar/event?eid=dDNtNmxyODRkNzdvOTdvaWV0NjhtZnYyMGcgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1338", "banner": "", - "date": "2024-04-03T10:00:00.000Z" + "date": "2024-08-13T14:00:00.000Z" }, { - "title": "Essential building blocks", - "calLink": "https://www.google.com/calendar/event?eid=c2pqamo4YXUwMWg1YmdqbDE3bXZncWpzb2cgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1144", + "title": "Essential Building Blocks Working Group", + "calLink": "https://www.google.com/calendar/event?eid=c28zazMxcDk3MThpMWFpNG9lYzRrbmIzNW8gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1342", "banner": "", - "date": "2024-04-09T18:00:00.000Z" - }, - { - "title": "AACoT'24 Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=NmJlNWE0dmlhZnZvNmwzNnRmNGp1OW1sNzQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1147", - "banner": "https://github.com/asyncapi/community/assets/66913810/8769dbe0-baef-42f7-b55e-74f5a288da55", - "date": "2024-04-10T14:00:00.000Z" + "date": "2024-08-27T18:00:00.000Z" }, { - "title": "Community Growth Working Group", - "calLink": "https://www.google.com/calendar/event?eid=NWluOTRmcG9vYjVjcWoydjVocDAzbjJtb2sgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1154", + "title": "Marketing WG Meeting", + "calLink": "https://www.google.com/calendar/event?eid=MmpwdGxqb29wcHQyaGk3dXU1cTJ0M3E2aGMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1354", "banner": "", - "date": "2024-04-09T14:00:00.000Z" + "date": "2024-09-10T14:00:00.000Z" }, { - "title": "Essential Building Blocks Working Group", - "calLink": "https://www.google.com/calendar/event?eid=M2JoNHViMGE4MXQwZjdlM2RmMWRqczJpZXMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1159", - "banner": "", - "date": "2024-04-16T18:00:00.000Z" + "title": "Community Meeting", + "calLink": "https://www.google.com/calendar/event?eid=b2lsN3YwcGNmdWZiNTltNm1lM25wYXYwc3MgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1355", + "banner": "https://github.com/user-attachments/assets/399c2eec-5123-47e9-ad41-024cd478a667", + "date": "2024-09-03T08:00:00.000Z" }, { - "title": "Community Growth Working Group", - "calLink": "https://www.google.com/calendar/event?eid=a25zaTduazV2ZTI1NGcxYzJ2N2h2NXJ0MnMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1169", - "banner": "", - "date": "2024-04-15T14:00:00.000Z" + "title": "Community Meeting", + "calLink": "https://www.google.com/calendar/event?eid=dG1nMGxqMWg4ajVqZ3Z2NHRpYW42bmUyNWMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1356", + "banner": "https://github.com/user-attachments/assets/bfcd9509-ba05-4e23-9fbd-65fcaed1bccc", + "date": "2024-09-17T16:00:00.000Z" }, { - "title": "Marketing - Next steps", - "calLink": "https://www.google.com/calendar/event?eid=bG5rcGc3bWZuODhrajU2aGtxamtvajI4c28gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1175", + "title": "Design Onboarding Call", + "calLink": "https://www.google.com/calendar/event?eid=dTU0c212bjVpcTFtYmp0aXVqMGFidG1paDAgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1372", "banner": "", - "date": "2024-04-25T14:00:00.000Z" + "date": "2024-09-12T10:00:00.000Z" }, { - "title": "Essential Building Blocks Working Group", - "calLink": "https://www.google.com/calendar/event?eid=M2RqZ3FmODRyZzRxM3RwOW9uMHEyNzVudjQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1177", + "title": "Marketing WG Meeting,", + "calLink": "https://www.google.com/calendar/event?eid=NDVmcGpjM3Y2aGFxMDhhMjMxZGgyNzlkNGsgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1534", "banner": "", - "date": "2024-04-23T18:00:00.000Z" + "date": "2024-10-08T14:00:00.000Z" }, { - "title": "Maintainers Growth Working Group Meeting", - "calLink": "https://www.google.com/calendar/event?eid=NGZ0NWZiNWw0MzJsbGR0M2Ewdm5kcGNkYzEgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "date": "2024-04-22T14:00:00.000Z" + "title": "Community Meeting", + "calLink": "https://www.google.com/calendar/event?eid=MHRvMzJtb2pxZWs5bDM4a3Jxb2RhYmVhMmMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1545", + "banner": "https://github.com/user-attachments/assets/91fca5af-ae9a-46be-aa44-0f2ef20ce34e", + "date": "2024-10-15T08:00:00.000Z" }, { "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=cmk4OTNzZGxvZDd2NHZxb243cG44NzlibWsgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1184", - "banner": "https://github.com/asyncapi/community/assets/40604284/d5358c67-20c3-48a9-b61c-cbea54bbf95c", - "date": "2024-04-30T16:00:00.000Z" + "calLink": "https://www.google.com/calendar/event?eid=amw3ZTBwZWllOTViYmMzMGFpNDhtdW9pZDggY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1546", + "banner": "https://github.com/user-attachments/assets/123ebfbe-6662-47ae-b36c-c2ba2e5d40f9", + "date": "2024-10-29T16:00:00.000Z" }, { - "title": "Essential Building Blocks Working Group", - "calLink": "https://www.google.com/calendar/event?eid=cjNxYm9sOXIwNDlpazY5MmoyNHE3NGxoZHMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1186", - "banner": "", - "date": "2024-04-30T18:00:00.000Z" + "title": "Let's talk about contributing Hacktoberfest Edition", + "calLink": "https://www.google.com/calendar/event?eid=Zm9lMzRvM2F2MGljbWplZDJnNWYwczIwMzQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1549", + "banner": "https://github.com/user-attachments/assets/0cd48545-5e26-4240-aa8f-f39306617e94", + "date": "2024-10-08T12:00:00.000Z" }, { - "title": "Marketing - WG setup and hiring", - "calLink": "https://www.google.com/calendar/event?eid=cjdhZTcxM25zNG1pMzloc2g5b2I3aTMyaG8gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1192", - "banner": "", - "date": "2024-05-09T14:00:00.000Z" + "title": "AsyncAPI Mentorship Program FAQ", + "calLink": "https://www.google.com/calendar/event?eid=NGlzdDFubzY1YWlwNjhpbm8ycTJzNGU1ZjQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1550", + "banner": "https://github.com/user-attachments/assets/d9e9e2cd-714b-48a8-a40d-03c7683a973c", + "date": "2024-10-10T11:00:00.000Z" }, { - "title": "Maintainers Growth Working Group", - "calLink": "https://www.google.com/calendar/event?eid=ZG9tMTVxazhybm5vMnE2cHIxbG4wOHQ3djAgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1197", + "title": "Marketing WG Meeting", + "calLink": "https://www.google.com/calendar/event?eid=NDd1NzNqdWprNWdqc3U3aGsyZnBhOWpobXMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1553", "banner": "", - "date": "2024-05-08T14:00:00.000Z" + "date": "2024-10-22T14:00:00.000Z" }, { - "title": "Essential Building Blocks Working Group", - "calLink": "https://www.google.com/calendar/event?eid=ZzQ4aDFsbnZpaXBmZ2h2amdrdWpxZXZrYmcgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1200", + "title": "Marketing WG Meeting", + "calLink": "https://www.google.com/calendar/event?eid=MG9qY2RycjY2cm0xMW1ibTVpZGh2MXZuNjQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1554", "banner": "", - "date": "2024-05-14T18:00:00.000Z" - }, - { - "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=bG5pdGoxcWZjc3VxMnJib2p2ZXZpYW8xM3MgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1201", - "banner": "https://github.com/asyncapi/community/assets/40604284/0b128389-fad9-4342-bbc6-4e5624327374", - "date": "2024-05-14T08:00:00.000Z" + "date": "2024-11-05T14:00:00.000Z" }, { - "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=OWZwaWlyOWJ0dmExcDJ0c2llaXZiMXA3M3MgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1202", - "banner": "https://github.com/asyncapi/community/assets/40604284/be6af5ec-9697-4ba4-a70b-4b9dd2c54c78", - "date": "2024-05-28T16:00:00.000Z" - }, - { - "title": "Essential Building Blocks Working Group", - "calLink": "https://www.google.com/calendar/event?eid=Z2M2dWxkZWI1YzY1amJydTQzcTlrYW1uZzggY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1210", + "title": "Design Meeting", + "calLink": "https://www.google.com/calendar/event?eid=ZWptamE1cWRzdGE5Mjlybm9vcGlqYTJkOXMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1558", "banner": "", - "date": "2024-05-28T18:00:00.000Z" + "date": "2024-10-17T12:00:00.000Z" }, { - "title": "Maintainers Growth Working Group", - "calLink": "https://www.google.com/calendar/event?eid=ZG45NjF1dXIyc2ZuajkwMTQwMWtxNGhma28gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1212", + "title": "AsyncAPI Online Conference 2024 Dry-Run", + "calLink": "https://www.google.com/calendar/event?eid=cnY0NDB2Y2dvcm1uZ2V0MmlrdDdyc3ByNTAgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1559", "banner": "", - "date": "2024-05-22T14:00:00.000Z" + "date": "2024-10-18T16:00:00.000Z" }, { - "title": "Developer Experience Working Group", - "calLink": "https://www.google.com/calendar/event?eid=ZWd1bWVrMjNrN3JoM3A3cXJndmZvNGFsdmsgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1220", + "title": "AsyncAPI Online Conference 2024", + "calLink": "https://www.google.com/calendar/event?eid=cjZwdnVldDd2Z29zb3Jlcm9pdTBvYzJmMnMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1562", "banner": "", - "date": "2024-05-23T14:00:00.000Z" + "date": "2024-10-30T10:00:00.000Z" } ] \ No newline at end of file diff --git a/config/newsroom_videos.json b/config/newsroom_videos.json index 52eefddc49b..6a3893e2316 100644 --- a/config/newsroom_videos.json +++ b/config/newsroom_videos.json @@ -1,32 +1,32 @@ [ { - "image_url": "https://i.ytimg.com/vi/K7fvKbOfqOg/hqdefault.jpg", - "title": "Developer Experience Working Group, 14:00 UTC Thursday May 23rd 2024", - "description": "Define our vision and plans https://github.com/asyncapi/community/issues/1220.", - "videoId": "K7fvKbOfqOg" + "image_url": "https://i.ytimg.com/vi/2WUchTKDPfs/hqdefault.jpg", + "title": "Marketing WG Meeting, 14:00 UTC Tuesday October 22nd 2024", + "description": "https://github.com/asyncapi/community/issues/1553.", + "videoId": "2WUchTKDPfs" }, { - "image_url": "https://i.ytimg.com/vi/94SSXX78VCU/hqdefault.jpg", - "title": "Essential Building Blocks Working Group, 18:00 UTC Tuesday May 14th 2024", - "description": "https://github.com/asyncapi/community/issues/1200.", - "videoId": "94SSXX78VCU" + "image_url": "https://i.ytimg.com/vi/FzRxTpOeIDA/hqdefault.jpg", + "title": "Design Meeting, 12:00 UTC Thursday October 17th 2024", + "description": "https://github.com/asyncapi/community/issues/1558.", + "videoId": "FzRxTpOeIDA" }, { - "image_url": "https://i.ytimg.com/vi/RijgS6y_JAo/hqdefault.jpg", - "title": "Maintainers Growth Working Group, 14:00 UTC Wednesday May 8th 2024", - "description": "https://github.com/asyncapi/community/issues/1197.", - "videoId": "RijgS6y_JAo" + "image_url": "https://i.ytimg.com/vi/maMQC97q_6E/hqdefault.jpg", + "title": "Community Meeting, 8:00 UTC Tuesday October 15th 2024", + "description": "https://github.com/asyncapi/community/issues/1545.", + "videoId": "maMQC97q_6E" }, { - "image_url": "https://i.ytimg.com/vi/8F3mTwf7JEs/hqdefault.jpg", - "title": "Essential Building Blocks Working Group, 18:00 UTC Tuesday May 14th 2024", - "description": "https://github.com/asyncapi/community/issues/1200.", - "videoId": "8F3mTwf7JEs" + "image_url": "https://i.ytimg.com/vi/P1ZqaVBb6XM/hqdefault.jpg", + "title": "AsyncAPI Mentorship Program FAQ, 11:00 UTC Thursday October 10th 2024", + "description": "https://github.com/asyncapi/community/issues/1550.", + "videoId": "P1ZqaVBb6XM" }, { - "image_url": "https://i.ytimg.com/vi/eQed8AKDlsM/hqdefault.jpg", - "title": "Marketing - WG setup and hiring, 14:00 UTC Wednesday May 9th 2024", - "description": "https://github.com/asyncapi/community/issues/1192.", - "videoId": "eQed8AKDlsM" + "image_url": "https://i.ytimg.com/vi/4jaACa7geT0/hqdefault.jpg", + "title": "Design Onboarding Call, 10:00 UTC Thursday September 12th 2024", + "description": "https://github.com/asyncapi/community/issues/1372.", + "videoId": "4jaACa7geT0" } ] \ No newline at end of file From 0b09994e899077c86643bc5fe535b2ca020ed393 Mon Sep 17 00:00:00 2001 From: Ansh Goyal Date: Wed, 23 Oct 2024 12:46:21 +0530 Subject: [PATCH 07/91] test: add markdown tests (#3301) Co-authored-by: Akshat Nema <76521428+akshatnema@users.noreply.github.com> --- .github/workflows/if-nodejs-pr-testing.yml | 38 +++++- markdown/docs/migration/index.md | 1 + markdown/docs/migration/migrating-to-v3.md | 1 + package.json | 1 + scripts/markdown/check-markdown.js | 146 +++++++++++++++++++++ 5 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 scripts/markdown/check-markdown.js diff --git a/.github/workflows/if-nodejs-pr-testing.yml b/.github/workflows/if-nodejs-pr-testing.yml index 769039d1a0a..c8c3bec4d3c 100644 --- a/.github/workflows/if-nodejs-pr-testing.yml +++ b/.github/workflows/if-nodejs-pr-testing.yml @@ -61,8 +61,7 @@ jobs: name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: "${{ steps.nodeversion.outputs.version }}" - + node-version: '${{ steps.nodeversion.outputs.version }}' - name: Install dependencies run: npm ci - if: steps.packagejson.outputs.exists == 'true' @@ -76,6 +75,41 @@ jobs: shell: bash run: npm run generate:assets --if-present + # Run the test:md script and capture output + - if: steps.packagejson.outputs.exists == 'true' + name: Run markdown checks + id: markdown_check + run: | + ERRORS=$(npm run test:md | sed -n '/Errors in file/,$p') + echo "markdown_output<> $GITHUB_OUTPUT + echo "$ERRORS" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + # Post a comment using sticky-pull-request-comment + - name: Comment on PR with markdown issues + if: ${{ steps.markdown_check.outputs.markdown_output != '' }} + uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd + with: + header: markdown-check-error + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + message: | + ### Markdown Check Results + + We found issues in the following markdown files: + + ``` + ${{ steps.markdown_check.outputs.markdown_output }} + ``` + + # Delete the comment if there are no issues + - if: ${{ steps.markdown_check.outputs.markdown_output == '' }} + name: Delete markdown check comment + uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd + with: + header: markdown-check-error + delete: true + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + - if: steps.packagejson.outputs.exists == 'true' name: Upload Coverage to Codecov uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 diff --git a/markdown/docs/migration/index.md b/markdown/docs/migration/index.md index 195bcc35cf5..a8a57359ae2 100644 --- a/markdown/docs/migration/index.md +++ b/markdown/docs/migration/index.md @@ -1,5 +1,6 @@ --- title: "Overview" +weight: 1 --- Migration to a new major version is always difficult, and AsyncAPI is no exception, but we want to provide as smooth a transition as possible. diff --git a/markdown/docs/migration/migrating-to-v3.md b/markdown/docs/migration/migrating-to-v3.md index 85fa6bb47a7..00587645fee 100644 --- a/markdown/docs/migration/migrating-to-v3.md +++ b/markdown/docs/migration/migrating-to-v3.md @@ -1,5 +1,6 @@ --- title: "Migrating to v3" +weight: 2 --- diff --git a/package.json b/package.json index 04ba37b586e..29269ed3e1d 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "generate:videos": "node scripts/build-newsroom-videos.js", "generate:tools": "node scripts/build-tools.js", "test:netlify": "deno test --allow-env --trace-ops netlify/**/*.test.ts", + "test:md": "node scripts/markdown/check-markdown.js", "dev:storybook": "storybook dev -p 6006", "build:storybook": "storybook build" }, diff --git a/scripts/markdown/check-markdown.js b/scripts/markdown/check-markdown.js new file mode 100644 index 00000000000..8979f7e0b4a --- /dev/null +++ b/scripts/markdown/check-markdown.js @@ -0,0 +1,146 @@ +const fs = require('fs'); +const matter = require('gray-matter'); +const path = require('path'); + +/** + * Checks if a given string is a valid URL. + * @param {string} str - The string to validate as a URL. + * @returns {boolean} True if the string is a valid URL, false otherwise. + */ +function isValidURL(str) { + try { + new URL(str); + return true; + } catch (err) { + return false; + } +} + +/** + * Validates the frontmatter of a blog post. + * @param {object} frontmatter - The frontmatter object to validate. + * @param {string} filePath - The path to the file being validated. + * @returns {string[]|null} An array of validation error messages, or null if no errors. + */ +function validateBlogs(frontmatter) { + const requiredAttributes = ['title', 'date', 'type', 'tags', 'cover', 'authors']; + const errors = []; + + // Check for required attributes + requiredAttributes.forEach(attr => { + if (!frontmatter.hasOwnProperty(attr)) { + errors.push(`${attr} is missing`); + } + }); + + // Validate date format + if (frontmatter.date && Number.isNaN(Date.parse(frontmatter.date))) { + errors.push(`Invalid date format: ${frontmatter.date}`); + } + + // Validate tags format (must be an array) + if (frontmatter.tags && !Array.isArray(frontmatter.tags)) { + errors.push(`Tags should be an array`); + } + + // Validate cover is a string + if (frontmatter.cover && typeof frontmatter.cover !== 'string') { + errors.push(`Cover must be a string`); + } + + // Validate authors (must be an array with valid attributes) + if (frontmatter.authors) { + if (!Array.isArray(frontmatter.authors)) { + errors.push('Authors should be an array'); + } else { + frontmatter.authors.forEach((author, index) => { + if (!author.name) { + errors.push(`Author at index ${index} is missing a name`); + } + if (author.link && !isValidURL(author.link)) { + errors.push(`Invalid URL for author at index ${index}: ${author.link}`); + } + if (!author.photo) { + errors.push(`Author at index ${index} is missing a photo`); + } + }); + } + } + + return errors.length ? errors : null; +} + +/** + * Validates the frontmatter of a documentation file. + * @param {object} frontmatter - The frontmatter object to validate. + * @param {string} filePath - The path to the file being validated. + * @returns {string[]|null} An array of validation error messages, or null if no errors. + */ +function validateDocs(frontmatter) { + const errors = []; + + // Check if title exists and is a string + if (!frontmatter.title || typeof frontmatter.title !== 'string') { + errors.push('Title is missing or not a string'); + } + + // Check if weight exists and is a number + if (frontmatter.weight === undefined || typeof frontmatter.weight !== 'number') { + errors.push('Weight is missing or not a number'); + } + + return errors.length ? errors : null; +} + +/** + * Recursively checks markdown files in a folder and validates their frontmatter. + * @param {string} folderPath - The path to the folder to check. + * @param {Function} validateFunction - The function used to validate the frontmatter. + * @param {string} [relativePath=''] - The relative path of the folder for logging purposes. + */ +function checkMarkdownFiles(folderPath, validateFunction, relativePath = '') { + fs.readdir(folderPath, (err, files) => { + if (err) { + console.error('Error reading directory:', err); + return; + } + + files.forEach(file => { + const filePath = path.join(folderPath, file); + const relativeFilePath = path.join(relativePath, file); + + // Skip the folder 'docs/reference/specification' + if (relativeFilePath.includes('reference/specification')) { + return; + } + + fs.stat(filePath, (err, stats) => { + if (err) { + console.error('Error reading file stats:', err); + return; + } + + // Recurse if directory, otherwise validate markdown file + if (stats.isDirectory()) { + checkMarkdownFiles(filePath, validateFunction, relativeFilePath); + } else if (path.extname(file) === '.md') { + const fileContent = fs.readFileSync(filePath, 'utf-8'); + const { data: frontmatter } = matter(fileContent); + + const errors = validateFunction(frontmatter); + if (errors) { + console.log(`Errors in file ${relativeFilePath}:`); + errors.forEach(error => console.log(` - ${error}`)); + process.exitCode = 1; + } + } + }); + }); + }); +} + +const docsFolderPath = path.resolve(__dirname, '../../markdown/docs'); +const blogsFolderPath = path.resolve(__dirname, '../../markdown/blog'); + +checkMarkdownFiles(docsFolderPath, validateDocs); +checkMarkdownFiles(blogsFolderPath, validateBlogs); From 62d6e9a415d7e1ad20da7e854b173d78308a304d Mon Sep 17 00:00:00 2001 From: Ansh Goyal Date: Wed, 23 Oct 2024 17:36:23 +0530 Subject: [PATCH 08/91] fix: restrict markdown tests to ubuntu runner (#3318) --- .github/workflows/if-nodejs-pr-testing.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/if-nodejs-pr-testing.yml b/.github/workflows/if-nodejs-pr-testing.yml index c8c3bec4d3c..a0fb664221c 100644 --- a/.github/workflows/if-nodejs-pr-testing.yml +++ b/.github/workflows/if-nodejs-pr-testing.yml @@ -2,7 +2,7 @@ name: PR testing - if Node project on: - pull_request: + pull_request_target: types: [opened, reopened, synchronize, ready_for_review] push: branches: [master] @@ -42,6 +42,9 @@ jobs: - if: steps.should_run.outputs.shouldrun == 'true' name: Checkout repository uses: actions/checkout@v4 + with: + ref: refs/pull/${{ github.event.pull_request.number }}/merge + - if: steps.should_run.outputs.shouldrun == 'true' name: Check if Node.js project and has package.json id: packagejson @@ -76,7 +79,7 @@ jobs: run: npm run generate:assets --if-present # Run the test:md script and capture output - - if: steps.packagejson.outputs.exists == 'true' + - if: ${{ steps.packagejson.outputs.exists == 'true' && matrix.os == 'ubuntu-latest' }} name: Run markdown checks id: markdown_check run: | @@ -87,7 +90,7 @@ jobs: # Post a comment using sticky-pull-request-comment - name: Comment on PR with markdown issues - if: ${{ steps.markdown_check.outputs.markdown_output != '' }} + if: ${{ steps.markdown_check.outputs.markdown_output != '' && matrix.os == 'ubuntu-latest' }} uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd with: header: markdown-check-error @@ -102,7 +105,7 @@ jobs: ``` # Delete the comment if there are no issues - - if: ${{ steps.markdown_check.outputs.markdown_output == '' }} + - if: ${{ steps.markdown_check.outputs.markdown_output == '' && matrix.os == 'ubuntu-latest' }} name: Delete markdown check comment uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd with: From adb4832c3c4734f87a44cf51e01a2233bdb79475 Mon Sep 17 00:00:00 2001 From: Akshat Nema <76521428+akshatnema@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:44:13 +0530 Subject: [PATCH 09/91] fix: fixed rate limiting (#3319) Co-authored-by: asyncapi-bot --- scripts/dashboard/build-dashboard.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/dashboard/build-dashboard.js b/scripts/dashboard/build-dashboard.js index 120109a05c2..5b0a34bee17 100644 --- a/scripts/dashboard/build-dashboard.js +++ b/scripts/dashboard/build-dashboard.js @@ -155,11 +155,9 @@ function monthsSince(date) { async function start() { try { - const [issues, PRs, rawGoodFirstIssues] = await Promise.all([ - getDiscussions(Queries.hotDiscussionsIssues, 20), - getDiscussions(Queries.hotDiscussionsPullRequests, 20), - getDiscussions(Queries.goodFirstIssues, 20) - ]); + const issues = await getDiscussions(Queries.hotDiscussionsIssues, 20); + const PRs = await getDiscussions(Queries.hotDiscussionsPullRequests, 20); + const rawGoodFirstIssues = await getDiscussions(Queries.goodFirstIssues, 20); const discussions = issues.concat(PRs); const [hotDiscussions, goodFirstIssues] = await Promise.all([ getHotDiscussions(discussions), From b3eeb0115135b64a4dc77f0fa75eb62f8072b852 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Wed, 23 Oct 2024 14:24:37 +0200 Subject: [PATCH 10/91] chore: update meetings.json and newsrooom_videos.json (#3321) --- dashboard.json | 675 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 439 insertions(+), 236 deletions(-) diff --git a/dashboard.json b/dashboard.json index 53053b94e94..1b19808d255 100644 --- a/dashboard.json +++ b/dashboard.json @@ -1,366 +1,518 @@ { "hotDiscussions": [ { - "id": "I_kwDOFLhIt85_y16Y", + "id": "I_kwDOFLhIt84-OUI3", "isPR": false, - "isAssigned": true, - "title": "Automate Slack user groups + channels creation and management", - "author": "smoya", - "resourcePath": "/asyncapi/community/issues/1072", + "isAssigned": false, + "title": "Create educational & technical video explaining AsyncAPI's main features", + "author": "quetzalliwrites", + "resourcePath": "/asyncapi/community/issues/155", "repo": "asyncapi/community", "labels": [ { "name": "enhancement", "color": "a2eeef" - }, - { - "name": "bounty", - "color": "0E8A16" } ], - "score": 104.24437571598092 + "score": 34.46095064991105 }, { - "id": "PR_kwDOFLhIt85js7KX", + "id": "PR_kwDOFLhIt855u7Eb", "isPR": true, "isAssigned": false, - "title": "chore: add documents CoC Committee and Incident Resolution Procedures", - "author": "Barbanio", - "resourcePath": "/asyncapi/community/pull/1013", + "title": "docs: added community marketing strategy doc", + "author": "iambami", + "resourcePath": "/asyncapi/community/pull/1358", "repo": "asyncapi/community", "labels": [], - "score": 22.9739670999407 + "score": 19.527872034949596 }, { - "id": "PR_kwDOFLhIt85bqKL8", + "id": "PR_kwDOFLhIt85oVQqh", "isPR": true, "isAssigned": false, - "title": "docs: add Bounty Program Rules", - "author": "aeworxet", - "resourcePath": "/asyncapi/community/pull/897", + "title": "feat: docs automation for website", + "author": "AnimeshKumar923", + "resourcePath": "/asyncapi/community/pull/1082", "repo": "asyncapi/community", "labels": [], - "score": 22.112443333692923 + "score": 18.37917367995256 }, { - "id": "I_kwDOBW5R_c580Z0o", - "isPR": false, + "id": "PR_kwDOBW5R_c52BRgf", + "isPR": true, "isAssigned": false, - "title": "New Contributor Guide and Maintenance Setup", - "author": "derberg", - "resourcePath": "/asyncapi/website/issues/2586", + "title": "feat: added test for build-rss.js", + "author": "vishvamsinh28", + "resourcePath": "/asyncapi/website/pull/3101", "repo": "asyncapi/website", + "labels": [], + "score": 17.517649913704783 + }, + { + "id": "I_kwDOGQYLdM5AX1lK", + "isPR": false, + "isAssigned": true, + "title": "Brand Refresh: Mascot", + "author": "mcturco", + "resourcePath": "/asyncapi/brand/issues/12", + "repo": "asyncapi/brand", "labels": [ { - "name": "enhancement", - "color": "84b6eb" + "name": ":art: design", + "color": "0D67D3" + }, + { + "name": "bounty", + "color": "0E8A16" } ], - "score": 18.091999091203302 + "score": 15.794602381209232 }, { - "id": "I_kwDOCVQpZM5M_dcV", - "isPR": false, - "isAssigned": true, - "title": "DocsUI: Messages Object output", - "author": "mcturco", - "resourcePath": "/asyncapi/asyncapi-react/issues/618", - "repo": "asyncapi/asyncapi-react", + "id": "PR_kwDOFLhIt853IEwA", + "isPR": true, + "isAssigned": false, + "title": "docs: added asyncapi student ambassador md file", + "author": "iambami", + "resourcePath": "/asyncapi/community/pull/1333", + "repo": "asyncapi/community", "labels": [], - "score": 17.230475324955524 + "score": 15.220253203710714 }, { - "id": "PR_kwDOBW5R_c5p28Vu", - "isPR": true, + "id": "I_kwDOFLhIt85bebeO", + "isPR": false, "isAssigned": false, - "title": "fix: navigation to correct heading in tools section", - "author": "Vishal2002", - "resourcePath": "/asyncapi/website/pull/2790", - "repo": "asyncapi/website", + "title": "Meeting Banners Storage", + "author": "AceTheCreator", + "resourcePath": "/asyncapi/community/issues/568", + "repo": "asyncapi/community", "labels": [], "score": 14.933078614961456 }, { - "id": "PR_kwDOCoBobc5tRBZn", + "id": "PR_kwDOCHlHJM54CmhW", "isPR": true, "isAssigned": false, - "title": "chore: introduce the turborepo to the parser.js", - "author": "ayushnau", - "resourcePath": "/asyncapi/parser-js/pull/992", - "repo": "asyncapi/parser-js", + "title": "fix: add the migration guide and nunjucks depreciation notes", + "author": "Gmin2", + "resourcePath": "/asyncapi/generator/pull/1253", + "repo": "asyncapi/generator", "labels": [], - "score": 14.358729437462937 + "score": 13.78438025996442 }, { - "id": "I_kwDOFi_gUM5hpuWl", + "id": "I_kwDODou01c5o2x-Z", "isPR": false, - "isAssigned": true, - "title": "Improve kafka adapter", - "author": "KhudaDad414", - "resourcePath": "/asyncapi/glee/issues/411", - "repo": "asyncapi/glee", + "isAssigned": false, + "title": "Start using a React framework", + "author": "fmvilas", + "resourcePath": "/asyncapi/studio/issues/661", + "repo": "asyncapi/studio", + "labels": [], + "score": 13.210031082465903 + }, + { + "id": "I_kwDOFLhIt85xI2wH", + "isPR": false, + "isAssigned": false, + "title": "Measure AsyncAPI Adoption", + "author": "fmvilas", + "resourcePath": "/asyncapi/community/issues/879", + "repo": "asyncapi/community", "labels": [ { - "name": "enhancement", - "color": "a2eeef" - }, - { - "name": "good first issue", - "color": "7057ff" - }, - { - "name": "area/typescript", - "color": "007acc" + "name": "stale", + "color": "ededed" } ], - "score": 13.78438025996442 + "score": 12.922856493716644 }, { - "id": "I_kwDODou01c5BZZv-", + "id": "I_kwDOBW5R_c5Pi3rO", "isPR": false, "isAssigned": false, - "title": "Open Graph link preview image according to the document to open", - "author": "smoya", - "resourcePath": "/asyncapi/studio/issues/224", - "repo": "asyncapi/studio", + "title": "Epic roadmap to the new AsyncAPI community section", + "author": "AceTheCreator", + "resourcePath": "/asyncapi/website/issues/903", + "repo": "asyncapi/website", "labels": [ { - "name": "enhancement", - "color": "a2eeef" + "name": "keep-open", + "color": "ffee84" }, { - "name": "keep-open", - "color": "f9dd4b" + "name": "🎨 design", + "color": "0D67D3" } ], - "score": 13.703040335770691 + "score": 11.073163907693488 }, { - "id": "I_kwDOFLhIt85bebeO", + "id": "I_kwDODwv8N86BkfYV", "isPR": false, "isAssigned": false, - "title": "Meeting Banners Storage", + "title": "Add Gallery Section to AACoT'24 Conference Website", + "author": "Mayaleeeee", + "resourcePath": "/asyncapi/conference-website/issues/264", + "repo": "asyncapi/conference-website", + "labels": [ + { + "name": "Hacktoberfest", + "color": "FF8AE2" + } + ], + "score": 10.912634372471834 + } + ], + "goodFirstIssues": [ + { + "id": "I_kwDODwv8N86bdV6Z", + "title": "Links in the Resources Hub Should Open in a New Window", + "isAssigned": false, + "resourcePath": "/asyncapi/conference-website/issues/434", + "repo": "asyncapi/conference-website", "author": "AceTheCreator", - "resourcePath": "/asyncapi/community/issues/568", + "area": "Unknown", + "labels": [ + { + "name": "Hacktoberfest", + "color": "FF8AE2" + } + ] + }, + { + "id": "I_kwDOFLhIt86bdQd-", + "title": "Add Proposed Project Ideas to Mentorship Directory", + "isAssigned": false, + "resourcePath": "/asyncapi/community/issues/1564", "repo": "asyncapi/community", - "labels": [], - "score": 13.497205671215161 + "author": "AceTheCreator", + "area": "Unknown", + "labels": [ + { + "name": "Hacktoberfest", + "color": "FF8AE2" + } + ] }, { - "id": "PR_kwDODou01c5r4UjU", - "isPR": true, + "id": "I_kwDOBW5R_c6aKzLD", + "title": "[FEATURE] Add coderabbit configuration to the repo", + "isAssigned": true, + "resourcePath": "/asyncapi/website/issues/3293", + "repo": "asyncapi/website", + "author": "akshatnema", + "area": "Unknown", + "labels": [ + { + "name": "enhancement", + "color": "84b6eb" + }, + { + "name": "Hacktoberfest", + "color": "FF8AE2" + } + ] + }, + { + "id": "I_kwDOCHlHJM6ZrKEr", + "title": "[📑 Docs]: Fix the relative paths of `index.md` & `migration.md` files.", "isAssigned": false, - "title": "fix: Enhancement of Visual Json Schema Editor", + "resourcePath": "/asyncapi/generator/issues/1294", + "repo": "asyncapi/generator", "author": "Gmin2", - "resourcePath": "/asyncapi/studio/pull/1065", - "repo": "asyncapi/studio", - "labels": [], - "score": 13.497205671215161 + "area": "Unknown", + "labels": [ + { + "name": "Hacktoberfest", + "color": "FF8AE2" + }, + { + "name": "📑 docs", + "color": "E50E99" + } + ] }, { - "id": "PR_kwDOFDnrNc5tl-_j", - "isPR": true, + "id": "I_kwDOCVQpZM6YZd4E", + "title": "A fragment with only one child is redundant.", "isAssigned": false, - "title": "test: replicate incorrect bundling and missing assertions part of #1323", - "author": "francocm", - "resourcePath": "/asyncapi/cli/pull/1389", - "repo": "asyncapi/cli", - "labels": [], - "score": 12.061332727468868 - } - ], - "goodFirstIssues": [ + "resourcePath": "/asyncapi/asyncapi-react/issues/1054", + "repo": "asyncapi/asyncapi-react", + "author": "AceTheCreator", + "area": "Unknown", + "labels": [ + { + "name": "Hacktoberfest", + "color": "FF8AE2" + } + ] + }, { - "id": "I_kwDOE8Qh386HJeIz", - "title": "[BUG] Implement avro schema data type ", + "id": "I_kwDOCVQpZM6YZc4E", + "title": "Remove this redundant \"undefined\"", "isAssigned": false, - "resourcePath": "/asyncapi/modelina/issues/1974", - "repo": "asyncapi/modelina", - "author": "akkshitgupta", - "area": "typescript", + "resourcePath": "/asyncapi/asyncapi-react/issues/1053", + "repo": "asyncapi/asyncapi-react", + "author": "AceTheCreator", + "area": "Unknown", "labels": [ { - "name": "avro", - "color": "EC3D91" + "name": "Hacktoberfest", + "color": "FF8AE2" } ] }, { - "id": "I_kwDODwv8N86CASyz", - "title": "Card text is unreadable ", + "id": "I_kwDOCVQpZM6YZbiE", + "title": "Remove this redundant \"undefined\"", "isAssigned": false, - "resourcePath": "/asyncapi/conference-website/issues/266", - "repo": "asyncapi/conference-website", + "resourcePath": "/asyncapi/asyncapi-react/issues/1052", + "repo": "asyncapi/asyncapi-react", "author": "AceTheCreator", "area": "Unknown", "labels": [ { - "name": "enhancement", - "color": "a2eeef" + "name": "Hacktoberfest", + "color": "FF8AE2" } ] }, { - "id": "I_kwDOCxglSM6Bxg4I", - "title": "Convert OpenAPI 3.0 to AsyncAPI 3.0", - "isAssigned": true, - "resourcePath": "/asyncapi/converter-js/issues/233", - "repo": "asyncapi/converter-js", - "author": "jonaslagoni", - "area": "typescript", + "id": "I_kwDODwv8N86YYYFf", + "title": "Fix the way the ticket section is being rendered", + "isAssigned": false, + "resourcePath": "/asyncapi/conference-website/issues/395", + "repo": "asyncapi/conference-website", + "author": "AceTheCreator", + "area": "Unknown", "labels": [ { "name": "enhancement", "color": "a2eeef" }, { - "name": "keep-open", - "color": "f4d473" - }, - { - "name": "bounty", - "color": "0E8A16" + "name": "Hacktoberfest", + "color": "FF8AE2" } ] }, { - "id": "I_kwDOE8Qh385-gvCP", - "title": "Add \"generated-code\" XmlDoc and `[GeneratedCode]` attribute to C# models.", + "id": "I_kwDODwv8N86Vde8t", + "title": "Sponsor announcement design for social media", "isAssigned": false, - "resourcePath": "/asyncapi/modelina/issues/1784", - "repo": "asyncapi/modelina", - "author": "RowlandBanks", - "area": "typescript", + "resourcePath": "/asyncapi/conference-website/issues/380", + "repo": "asyncapi/conference-website", + "author": "thulieblack", + "area": "Unknown", "labels": [ { - "name": "enhancement", - "color": "a2eeef" - }, + "name": "design", + "color": "5D0F46" + } + ] + }, + { + "id": "I_kwDODwv8N86VdePb", + "title": "The conference countdown banner", + "isAssigned": false, + "resourcePath": "/asyncapi/conference-website/issues/378", + "repo": "asyncapi/conference-website", + "author": "thulieblack", + "area": "Unknown", + "labels": [ { - "name": "C# generator", - "color": "c5def5" + "name": "design", + "color": "5D0F46" } ] }, { - "id": "I_kwDOCHlHJM58YMi8", - "title": "Improve arborist (npm installation) to have no hacks", + "id": "I_kwDOBW5R_c6VIyCf", + "title": "[Docs Bug 🐞 report]: Broken link to Generator Github Actions", "isAssigned": false, - "resourcePath": "/asyncapi/generator/issues/1102", - "repo": "asyncapi/generator", - "author": "derberg", - "area": "javascript", + "resourcePath": "/asyncapi/website/issues/3190", + "repo": "asyncapi/website", + "author": "chinma-yyy", + "area": "Unknown", "labels": [ { - "name": "enhancement", - "color": "a2eeef" - }, + "name": "🐞 docs bug", + "color": "FFD23F" + } + ] + }, + { + "id": "I_kwDOGQYLdM6VGsJA", + "title": "Design a Graphic for the Member Spotlight Post", + "isAssigned": false, + "resourcePath": "/asyncapi/brand/issues/108", + "repo": "asyncapi/brand", + "author": "Mayaleeeee", + "area": "Unknown", + "labels": [ { - "name": "stale", - "color": "ededed" + "name": ":art: design", + "color": "0D67D3" } ] }, { - "id": "I_kwDOE8Qh38572pxu", - "title": "Add runtime tests for Dart", + "id": "I_kwDOGQYLdM6VAt9d", + "title": "Create \"Did You Know?\" Social Media Posts (3-4 Graphics)", "isAssigned": false, - "resourcePath": "/asyncapi/modelina/issues/1744", - "repo": "asyncapi/modelina", - "author": "jonaslagoni", + "resourcePath": "/asyncapi/brand/issues/107", + "repo": "asyncapi/brand", + "author": "Mayaleeeee", "area": "Unknown", "labels": [ { - "name": "enhancement", - "color": "a2eeef" - }, + "name": "🎨 design", + "color": "0D67D3" + } + ] + }, + { + "id": "I_kwDOGQYLdM6VAsmz", + "title": "Create a Graphic for \"Ask Me Anything\" (AMA) Session Announcement", + "isAssigned": false, + "resourcePath": "/asyncapi/brand/issues/106", + "repo": "asyncapi/brand", + "author": "Mayaleeeee", + "area": "Unknown", + "labels": [ { - "name": "Dart generator", - "color": "296FBA" + "name": "🎨 design", + "color": "0D67D3" } ] }, { - "id": "I_kwDOE8Qh38572gDd", - "title": "Add XSD support ", + "id": "I_kwDOGQYLdM6VArWv", + "title": "Design a Graphic for Mentorship Program Announcement", "isAssigned": false, - "resourcePath": "/asyncapi/modelina/issues/1742", - "repo": "asyncapi/modelina", - "author": "jonaslagoni", - "area": "typescript", + "resourcePath": "/asyncapi/brand/issues/105", + "repo": "asyncapi/brand", + "author": "Mayaleeeee", + "area": "design", + "labels": [] + }, + { + "id": "I_kwDOGQYLdM6VApSN", + "title": "Design a Graphic for Newsletter Promo", + "isAssigned": false, + "resourcePath": "/asyncapi/brand/issues/104", + "repo": "asyncapi/brand", + "author": "Mayaleeeee", + "area": "design", + "labels": [] + }, + { + "id": "I_kwDOBW5R_c6U79Xr", + "title": "[Docs Bug 🐞 report]: Github handle link of alequetzalli is not working ", + "isAssigned": false, + "resourcePath": "/asyncapi/website/issues/3176", + "repo": "asyncapi/website", + "author": "NoIdea2001", + "area": "Unknown", "labels": [ { - "name": "enhancement", - "color": "a2eeef" - }, + "name": "🐞 docs bug", + "color": "FFD23F" + } + ] + }, + { + "id": "I_kwDOFLhIt86O7jFN", + "title": "[DESIGN] Holopin Design Tracking", + "isAssigned": true, + "resourcePath": "/asyncapi/community/issues/1306", + "repo": "asyncapi/community", + "author": "Mayaleeeee", + "area": "design", + "labels": [ { - "name": "stale", - "color": "ededed" + "name": "🎨 design", + "color": "0D67D3" } ] }, { - "id": "I_kwDOE8Qh38572bME", - "title": "Add JSON Type definition support ", + "id": "I_kwDOE8Qh386HJeIz", + "title": "[BUG] Implement avro schema data type ", "isAssigned": false, - "resourcePath": "/asyncapi/modelina/issues/1740", + "resourcePath": "/asyncapi/modelina/issues/1974", "repo": "asyncapi/modelina", - "author": "jonaslagoni", + "author": "akkshitgupta", "area": "typescript", "labels": [ { - "name": "enhancement", - "color": "a2eeef" + "name": "avro", + "color": "EC3D91" } ] }, { - "id": "I_kwDOE8Qh3857Kllp", - "title": "Add loading animation for when playground generate models ", + "id": "I_kwDOFDnrNc6Gp88n", + "title": " Implement new UI/UX improvements in start command", "isAssigned": false, - "resourcePath": "/asyncapi/modelina/issues/1725", - "repo": "asyncapi/modelina", - "author": "jonaslagoni", + "resourcePath": "/asyncapi/cli/issues/1384", + "repo": "asyncapi/cli", + "author": "Amzani", + "area": "typescript", + "labels": [] + }, + { + "id": "I_kwDOFDnrNc6Gp8Qd", + "title": " Implement new UI/UX improvements in config command", + "isAssigned": false, + "resourcePath": "/asyncapi/cli/issues/1380", + "repo": "asyncapi/cli", + "author": "Amzani", + "area": "typescript", + "labels": [] + }, + { + "id": "I_kwDOFDnrNc59gY4V", + "title": "Validate command output is polluted by noisy messages", + "isAssigned": false, + "resourcePath": "/asyncapi/cli/issues/1095", + "repo": "asyncapi/cli", + "author": "cykl", "area": "Unknown", "labels": [ { - "name": "enhancement", - "color": "a2eeef" + "name": "Hacktoberfest", + "color": "FF8AE2" }, { - "name": "website", - "color": "57A793" + "name": "bug", + "color": "d73a4a" } ] }, { - "id": "I_kwDOE8Qh3857KYj1", - "title": "Add input document for OpenAPI", + "id": "I_kwDOCHlHJM58YMi8", + "title": "Improve arborist (npm installation) to have no hacks", "isAssigned": false, - "resourcePath": "/asyncapi/modelina/issues/1723", - "repo": "asyncapi/modelina", - "author": "jonaslagoni", - "area": "Unknown", + "resourcePath": "/asyncapi/generator/issues/1102", + "repo": "asyncapi/generator", + "author": "derberg", + "area": "javascript", "labels": [ { "name": "enhancement", "color": "a2eeef" - }, - { - "name": "stale", - "color": "ededed" - }, - { - "name": "📑 docs", - "color": "E50E99" } ] }, { - "id": "I_kwDOE8Qh3857KYQc", - "title": "Add input document for AsyncAPI", - "isAssigned": false, - "resourcePath": "/asyncapi/modelina/issues/1722", + "id": "I_kwDOE8Qh3857Kllp", + "title": "Add loading animation for when playground generate models ", + "isAssigned": true, + "resourcePath": "/asyncapi/modelina/issues/1725", "repo": "asyncapi/modelina", "author": "jonaslagoni", "area": "Unknown", @@ -370,12 +522,8 @@ "color": "a2eeef" }, { - "name": "stale", - "color": "ededed" - }, - { - "name": "📑 docs", - "color": "E50E99" + "name": "website", + "color": "57A793" } ] }, @@ -406,6 +554,10 @@ { "name": "enhancement", "color": "a2eeef" + }, + { + "name": "stale", + "color": "ededed" } ] }, @@ -417,7 +569,27 @@ "repo": "asyncapi/studio", "author": "princerajpoot20", "area": "typescript", - "labels": [] + "labels": [ + { + "name": "stale", + "color": "ededed" + } + ] + }, + { + "id": "I_kwDOFDnrNc50wZMh", + "title": "Add support for proxy", + "isAssigned": false, + "resourcePath": "/asyncapi/cli/issues/862", + "repo": "asyncapi/cli", + "author": "mamyn0va", + "area": "typescript", + "labels": [ + { + "name": "enhancement", + "color": "a2eeef" + } + ] }, { "id": "I_kwDOCoBobc5zovn3", @@ -431,6 +603,10 @@ { "name": "bug", "color": "d73a4a" + }, + { + "name": "stale", + "color": "ededed" } ] }, @@ -454,21 +630,32 @@ ] }, { - "id": "I_kwDODwv8N85yh95N", - "title": "would be nice if venue from past events is grayed out", + "id": "I_kwDOFDnrNc5xaTa3", + "title": "Parallel execution command asyncapi generate got error", "isAssigned": false, - "resourcePath": "/asyncapi/conference-website/issues/208", - "repo": "asyncapi/conference-website", - "author": "derberg", - "area": "javascript", + "resourcePath": "/asyncapi/cli/issues/814", + "repo": "asyncapi/cli", + "author": "Zacama", + "area": "Unknown", + "labels": [ + { + "name": "bug", + "color": "d73a4a" + } + ] + }, + { + "id": "I_kwDOFDnrNc5wmQBl", + "title": "Need to Consider the Case Senstive feature in CLI while creating new file.", + "isAssigned": false, + "resourcePath": "/asyncapi/cli/issues/790", + "repo": "asyncapi/cli", + "author": "AayushSaini101", + "area": "typescript", "labels": [ { "name": "enhancement", "color": "a2eeef" - }, - { - "name": "Hacktoberfest", - "color": "FF8AE2" } ] }, @@ -484,6 +671,10 @@ { "name": "bug", "color": "d73a4a" + }, + { + "name": "stale", + "color": "ededed" } ] }, @@ -518,6 +709,10 @@ { "name": "bug", "color": "d73a4a" + }, + { + "name": "stale", + "color": "ededed" } ] }, @@ -586,13 +781,17 @@ { "name": "enhancement", "color": "a2eeef" + }, + { + "name": "stale", + "color": "ededed" } ] }, { "id": "I_kwDOBW5R_c5eFaBF", "title": "Add proper dropdowns to the Filters Select Menu", - "isAssigned": false, + "isAssigned": true, "resourcePath": "/asyncapi/website/issues/1318", "repo": "asyncapi/website", "author": "akshatnema", @@ -662,25 +861,10 @@ { "name": "enhancement", "color": "a2eeef" - } - ] - }, - { - "id": "I_kwDOBW5R_c5dfidP", - "title": "docs: new style guide - Glossary", - "isAssigned": true, - "resourcePath": "/asyncapi/website/issues/1294", - "repo": "asyncapi/website", - "author": "alequetzalli", - "area": "docs", - "labels": [ + }, { "name": "stale", "color": "ededed" - }, - { - "name": "📑 docs", - "color": "E50E99" } ] }, @@ -764,6 +948,25 @@ } ] }, + { + "id": "I_kwDOFiHaLM5DeQ4y", + "title": "Add support for HTML output", + "isAssigned": false, + "resourcePath": "/asyncapi/diff/issues/85", + "repo": "asyncapi/diff", + "author": "aayushmau5", + "area": "Unknown", + "labels": [ + { + "name": "enhancement", + "color": "a2eeef" + }, + { + "name": "stale", + "color": "ededed" + } + ] + }, { "id": "I_kwDOBW5R_c48lGJg", "title": "Add visual on the \"generator\" and maybe others....", @@ -771,7 +974,7 @@ "resourcePath": "/asyncapi/website/issues/403", "repo": "asyncapi/website", "author": "boyney123", - "area": "typescript", + "area": "design", "labels": [ { "name": "enhancement", From 10fab1c72b68e3a96ce6452e03323bfbbaa74ae1 Mon Sep 17 00:00:00 2001 From: Ansh Goyal Date: Wed, 23 Oct 2024 17:59:08 +0530 Subject: [PATCH 11/91] fix: fix testing workflow ref for branch pushes (#3320) --- .github/workflows/if-nodejs-pr-testing.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/if-nodejs-pr-testing.yml b/.github/workflows/if-nodejs-pr-testing.yml index a0fb664221c..d5489e7ab8f 100644 --- a/.github/workflows/if-nodejs-pr-testing.yml +++ b/.github/workflows/if-nodejs-pr-testing.yml @@ -43,7 +43,9 @@ jobs: name: Checkout repository uses: actions/checkout@v4 with: - ref: refs/pull/${{ github.event.pull_request.number }}/merge + # Checkout the merge commit instead of the pull request head commit for a pull request + # Fallback to the head commit if its not a pull request + ref: ${{ github.event.pull_request.number != '' && format('refs/pull/{0}/merge', github.event.pull_request.number) || github.ref }} - if: steps.should_run.outputs.shouldrun == 'true' name: Check if Node.js project and has package.json From 4f813d04eb7847eb06142b9bf1a049a270e51934 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Thu, 24 Oct 2024 08:03:26 +0200 Subject: [PATCH 12/91] docs(cli): update latest cli documentation (#3322) --- markdown/docs/tools/cli/usage.md | 52 ++++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/markdown/docs/tools/cli/usage.md b/markdown/docs/tools/cli/usage.md index d4cae23662b..8b0f4669705 100644 --- a/markdown/docs/tools/cli/usage.md +++ b/markdown/docs/tools/cli/usage.md @@ -27,7 +27,7 @@ $ npm install -g @asyncapi/cli $ asyncapi COMMAND running command... $ asyncapi (--version) -@asyncapi/cli/2.7.1 linux-x64 node-v18.20.4 +@asyncapi/cli/2.7.2 linux-x64 node-v18.20.4 $ asyncapi --help [COMMAND] USAGE $ asyncapi COMMAND @@ -99,7 +99,7 @@ EXAMPLES $ asyncapi bundle ./asyncapi.yaml -o final-asyncapi.yaml --base ../public-api/main.yaml --baseDir ./social-media/comments-service ``` -_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/bundle.ts)_ +_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/bundle.ts)_ ## `asyncapi config` @@ -113,7 +113,7 @@ DESCRIPTION CLI config settings ``` -_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/index.ts)_ +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/index.ts)_ ## `asyncapi config analytics` @@ -133,7 +133,7 @@ DESCRIPTION Enable or disable analytics for metrics collection ``` -_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/analytics.ts)_ +_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/analytics.ts)_ ## `asyncapi config context` @@ -147,7 +147,7 @@ DESCRIPTION Manage short aliases for full paths to AsyncAPI documents ``` -_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/index.ts)_ +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/index.ts)_ ## `asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH` @@ -169,7 +169,7 @@ DESCRIPTION Add a context to the store ``` -_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/add.ts)_ +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/add.ts)_ ## `asyncapi config context current` @@ -186,7 +186,7 @@ DESCRIPTION Shows the current context that is being used ``` -_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/current.ts)_ +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/current.ts)_ ## `asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` @@ -207,7 +207,7 @@ DESCRIPTION Edit a context in the store ``` -_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/edit.ts)_ +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/edit.ts)_ ## `asyncapi config context init [CONTEXT-FILE-PATH]` @@ -230,7 +230,7 @@ DESCRIPTION Initialize context ``` -_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/init.ts)_ +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/init.ts)_ ## `asyncapi config context list` @@ -247,7 +247,7 @@ DESCRIPTION List all the stored contexts in the store ``` -_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/list.ts)_ +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/list.ts)_ ## `asyncapi config context remove CONTEXT-NAME` @@ -267,7 +267,7 @@ DESCRIPTION Delete a context from the store ``` -_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/remove.ts)_ +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/remove.ts)_ ## `asyncapi config context use CONTEXT-NAME` @@ -287,7 +287,7 @@ DESCRIPTION Set a context as current ``` -_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/context/use.ts)_ +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/use.ts)_ ## `asyncapi config versions` @@ -304,7 +304,7 @@ DESCRIPTION Show versions of AsyncAPI tools used ``` -_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/config/versions.ts)_ +_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/versions.ts)_ ## `asyncapi convert [SPEC-FILE]` @@ -332,7 +332,7 @@ DESCRIPTION Convert asyncapi documents older to newer versions or OpenAPI/postman-collection documents to AsyncAPI ``` -_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/convert.ts)_ +_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/convert.ts)_ ## `asyncapi diff OLD NEW` @@ -372,7 +372,7 @@ DESCRIPTION Find diff between two asyncapi files ``` -_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/diff.ts)_ +_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/diff.ts)_ ## `asyncapi generate` @@ -386,7 +386,7 @@ DESCRIPTION Generate typed models or other things like clients, applications or docs using AsyncAPI Generator templates. ``` -_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/generate/index.ts)_ +_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/generate/index.ts)_ ## `asyncapi generate fromTemplate ASYNCAPI TEMPLATE` @@ -431,7 +431,7 @@ EXAMPLES $ asyncapi generate fromTemplate asyncapi.yaml @asyncapi/html-template --param version=1.0.0 singleFile=true --output ./docs --force-write ``` -_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/generate/fromTemplate.ts)_ +_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/generate/fromTemplate.ts)_ ## `asyncapi generate models LANGUAGE FILE` @@ -502,7 +502,7 @@ DESCRIPTION Generates typed models ``` -_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/generate/models.ts)_ +_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/generate/models.ts)_ ## `asyncapi new` @@ -560,7 +560,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/new/index.ts)_ +_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/new/index.ts)_ ## `asyncapi new file` @@ -618,7 +618,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/new/file.ts)_ +_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/new/file.ts)_ ## `asyncapi new glee` @@ -640,7 +640,7 @@ DESCRIPTION Creates a new Glee project ``` -_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/new/glee.ts)_ +_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/new/glee.ts)_ ## `asyncapi new template` @@ -664,7 +664,7 @@ DESCRIPTION Creates a new template ``` -_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/new/template.ts)_ +_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/new/template.ts)_ ## `asyncapi optimize [SPEC-FILE]` @@ -706,7 +706,7 @@ EXAMPLES $ asyncapi optimize ./asyncapi.yaml --ignore=schema ``` -_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/optimize.ts)_ +_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/optimize.ts)_ ## `asyncapi start` @@ -720,7 +720,7 @@ DESCRIPTION Starts AsyncAPI-related services. Currently, it supports launching the AsyncAPI Studio ``` -_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/start/index.ts)_ +_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/start/index.ts)_ ## `asyncapi start studio` @@ -739,7 +739,7 @@ DESCRIPTION starts a new local instance of Studio ``` -_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/start/studio.ts)_ +_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/start/studio.ts)_ ## `asyncapi validate [SPEC-FILE]` @@ -769,5 +769,5 @@ DESCRIPTION validate asyncapi file ``` -_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.7.1/src/commands/validate.ts)_ +_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/validate.ts)_ From 1a1d9402a546c75a74080c21b077126fd0d01ede Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Thu, 24 Oct 2024 15:11:39 +0200 Subject: [PATCH 13/91] docs(cli): update latest cli documentation (#3324) --- markdown/docs/tools/cli/usage.md | 52 ++++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/markdown/docs/tools/cli/usage.md b/markdown/docs/tools/cli/usage.md index 8b0f4669705..a8d86b446bc 100644 --- a/markdown/docs/tools/cli/usage.md +++ b/markdown/docs/tools/cli/usage.md @@ -27,7 +27,7 @@ $ npm install -g @asyncapi/cli $ asyncapi COMMAND running command... $ asyncapi (--version) -@asyncapi/cli/2.7.2 linux-x64 node-v18.20.4 +@asyncapi/cli/2.7.3 linux-x64 node-v18.20.4 $ asyncapi --help [COMMAND] USAGE $ asyncapi COMMAND @@ -99,7 +99,7 @@ EXAMPLES $ asyncapi bundle ./asyncapi.yaml -o final-asyncapi.yaml --base ../public-api/main.yaml --baseDir ./social-media/comments-service ``` -_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/bundle.ts)_ +_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/bundle.ts)_ ## `asyncapi config` @@ -113,7 +113,7 @@ DESCRIPTION CLI config settings ``` -_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/index.ts)_ +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/index.ts)_ ## `asyncapi config analytics` @@ -133,7 +133,7 @@ DESCRIPTION Enable or disable analytics for metrics collection ``` -_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/analytics.ts)_ +_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/analytics.ts)_ ## `asyncapi config context` @@ -147,7 +147,7 @@ DESCRIPTION Manage short aliases for full paths to AsyncAPI documents ``` -_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/index.ts)_ +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/index.ts)_ ## `asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH` @@ -169,7 +169,7 @@ DESCRIPTION Add a context to the store ``` -_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/add.ts)_ +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/add.ts)_ ## `asyncapi config context current` @@ -186,7 +186,7 @@ DESCRIPTION Shows the current context that is being used ``` -_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/current.ts)_ +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/current.ts)_ ## `asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` @@ -207,7 +207,7 @@ DESCRIPTION Edit a context in the store ``` -_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/edit.ts)_ +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/edit.ts)_ ## `asyncapi config context init [CONTEXT-FILE-PATH]` @@ -230,7 +230,7 @@ DESCRIPTION Initialize context ``` -_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/init.ts)_ +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/init.ts)_ ## `asyncapi config context list` @@ -247,7 +247,7 @@ DESCRIPTION List all the stored contexts in the store ``` -_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/list.ts)_ +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/list.ts)_ ## `asyncapi config context remove CONTEXT-NAME` @@ -267,7 +267,7 @@ DESCRIPTION Delete a context from the store ``` -_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/remove.ts)_ +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/remove.ts)_ ## `asyncapi config context use CONTEXT-NAME` @@ -287,7 +287,7 @@ DESCRIPTION Set a context as current ``` -_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/context/use.ts)_ +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/use.ts)_ ## `asyncapi config versions` @@ -304,7 +304,7 @@ DESCRIPTION Show versions of AsyncAPI tools used ``` -_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/config/versions.ts)_ +_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/versions.ts)_ ## `asyncapi convert [SPEC-FILE]` @@ -332,7 +332,7 @@ DESCRIPTION Convert asyncapi documents older to newer versions or OpenAPI/postman-collection documents to AsyncAPI ``` -_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/convert.ts)_ +_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/convert.ts)_ ## `asyncapi diff OLD NEW` @@ -372,7 +372,7 @@ DESCRIPTION Find diff between two asyncapi files ``` -_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/diff.ts)_ +_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/diff.ts)_ ## `asyncapi generate` @@ -386,7 +386,7 @@ DESCRIPTION Generate typed models or other things like clients, applications or docs using AsyncAPI Generator templates. ``` -_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/generate/index.ts)_ +_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/generate/index.ts)_ ## `asyncapi generate fromTemplate ASYNCAPI TEMPLATE` @@ -431,7 +431,7 @@ EXAMPLES $ asyncapi generate fromTemplate asyncapi.yaml @asyncapi/html-template --param version=1.0.0 singleFile=true --output ./docs --force-write ``` -_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/generate/fromTemplate.ts)_ +_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/generate/fromTemplate.ts)_ ## `asyncapi generate models LANGUAGE FILE` @@ -502,7 +502,7 @@ DESCRIPTION Generates typed models ``` -_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/generate/models.ts)_ +_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/generate/models.ts)_ ## `asyncapi new` @@ -560,7 +560,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/new/index.ts)_ +_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/new/index.ts)_ ## `asyncapi new file` @@ -618,7 +618,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/new/file.ts)_ +_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/new/file.ts)_ ## `asyncapi new glee` @@ -640,7 +640,7 @@ DESCRIPTION Creates a new Glee project ``` -_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/new/glee.ts)_ +_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/new/glee.ts)_ ## `asyncapi new template` @@ -664,7 +664,7 @@ DESCRIPTION Creates a new template ``` -_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/new/template.ts)_ +_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/new/template.ts)_ ## `asyncapi optimize [SPEC-FILE]` @@ -706,7 +706,7 @@ EXAMPLES $ asyncapi optimize ./asyncapi.yaml --ignore=schema ``` -_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/optimize.ts)_ +_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/optimize.ts)_ ## `asyncapi start` @@ -720,7 +720,7 @@ DESCRIPTION Starts AsyncAPI-related services. Currently, it supports launching the AsyncAPI Studio ``` -_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/start/index.ts)_ +_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/start/index.ts)_ ## `asyncapi start studio` @@ -739,7 +739,7 @@ DESCRIPTION starts a new local instance of Studio ``` -_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/start/studio.ts)_ +_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/start/studio.ts)_ ## `asyncapi validate [SPEC-FILE]` @@ -769,5 +769,5 @@ DESCRIPTION validate asyncapi file ``` -_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.7.2/src/commands/validate.ts)_ +_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/validate.ts)_ From bb69a47b082597f06180f7714c315c52dcdbdae9 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Fri, 25 Oct 2024 02:36:55 +0200 Subject: [PATCH 14/91] chore: update meetings.json and newsrooom_videos.json (#3326) --- config/meetings.json | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/config/meetings.json b/config/meetings.json index 4fbe2b0b8e2..850bac956a6 100644 --- a/config/meetings.json +++ b/config/meetings.json @@ -1,11 +1,4 @@ [ - { - "title": "Essential Building Blocks Working Group", - "calLink": "https://www.google.com/calendar/event?eid=M2pxNGNwZnRqNGpjcDg2cXVnc3VqZ2wwMHMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1294", - "banner": "", - "date": "2024-07-16T18:00:00.000Z" - }, { "title": "Community Meeting", "calLink": "https://www.google.com/calendar/event?eid=am5kcG50YW9obGUzcmVucWZqMTQ4NDlsbjQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", @@ -13,13 +6,6 @@ "banner": "https://github.com/asyncapi/community/assets/40604284/65376079-c5e8-467d-b513-21dfaba4570f", "date": "2024-07-23T16:00:00.000Z" }, - { - "title": "Marketing WG Meeting", - "calLink": "https://www.google.com/calendar/event?eid=Z3NzN2JvcjdnY2diMnJpczA4dWMxMGh2ZGcgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1309", - "banner": "", - "date": "2024-07-16T14:00:00.000Z" - }, { "title": "Marketing WG Meeting", "calLink": "https://www.google.com/calendar/event?eid=b2twOWkyZ3ExcGxnYnAxbzBobzA1MWxvcW8gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", @@ -159,5 +145,12 @@ "url": "https://github.com/asyncapi/community/issues/1562", "banner": "", "date": "2024-10-30T10:00:00.000Z" + }, + { + "title": "Conference Dry Run", + "calLink": "https://www.google.com/calendar/event?eid=ZmR1c25lZG1wc2swOWloNDd2c2VudWc5OTggY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1566", + "banner": "", + "date": "2024-10-28T16:00:00.000Z" } ] \ No newline at end of file From 67aafb6fd59030cf57e3b43da4d047c1ff3323ea Mon Sep 17 00:00:00 2001 From: Varun Kolanu Date: Fri, 25 Oct 2024 22:31:59 +0530 Subject: [PATCH 15/91] fix: make the edit page on github point to correct resource (#3327) --- config/edit-page-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/edit-page-config.json b/config/edit-page-config.json index dbd5fa50b9e..32921f145d4 100644 --- a/config/edit-page-config.json +++ b/config/edit-page-config.json @@ -13,7 +13,7 @@ }, { "value": "", - "href": "https://github.com/asyncapi/website/blob/master/pages" + "href": "https://github.com/asyncapi/website/blob/master/markdown" }, { "value": "reference/extensions/", From 6ae313db852ec1aaf4c5a42810d904f9a4438534 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Sat, 26 Oct 2024 02:39:51 +0200 Subject: [PATCH 16/91] chore: update meetings.json and newsrooom_videos.json (#3329) --- dashboard.json | 55 +++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/dashboard.json b/dashboard.json index 1b19808d255..2c675544b9a 100644 --- a/dashboard.json +++ b/dashboard.json @@ -27,6 +27,17 @@ "labels": [], "score": 19.527872034949596 }, + { + "id": "PR_kwDOBW5R_c52BRgf", + "isPR": true, + "isAssigned": false, + "title": "feat: added test for build-rss.js", + "author": "vishvamsinh28", + "resourcePath": "/asyncapi/website/pull/3101", + "repo": "asyncapi/website", + "labels": [], + "score": 19.240697446200336 + }, { "id": "PR_kwDOFLhIt85oVQqh", "isPR": true, @@ -38,17 +49,6 @@ "labels": [], "score": 18.37917367995256 }, - { - "id": "PR_kwDOBW5R_c52BRgf", - "isPR": true, - "isAssigned": false, - "title": "feat: added test for build-rss.js", - "author": "vishvamsinh28", - "resourcePath": "/asyncapi/website/pull/3101", - "repo": "asyncapi/website", - "labels": [], - "score": 17.517649913704783 - }, { "id": "I_kwDOGQYLdM5AX1lK", "isPR": false, @@ -67,7 +67,7 @@ "color": "0E8A16" } ], - "score": 15.794602381209232 + "score": 16.08177696995849 }, { "id": "PR_kwDOFLhIt853IEwA", @@ -129,26 +129,6 @@ ], "score": 12.922856493716644 }, - { - "id": "I_kwDOBW5R_c5Pi3rO", - "isPR": false, - "isAssigned": false, - "title": "Epic roadmap to the new AsyncAPI community section", - "author": "AceTheCreator", - "resourcePath": "/asyncapi/website/issues/903", - "repo": "asyncapi/website", - "labels": [ - { - "name": "keep-open", - "color": "ffee84" - }, - { - "name": "🎨 design", - "color": "0D67D3" - } - ], - "score": 11.073163907693488 - }, { "id": "I_kwDODwv8N86BkfYV", "isPR": false, @@ -164,6 +144,17 @@ } ], "score": 10.912634372471834 + }, + { + "id": "PR_kwDOFLhIt85bqKL8", + "isPR": true, + "isAssigned": false, + "title": "docs: add Bounty Program Rules", + "author": "aeworxet", + "resourcePath": "/asyncapi/community/pull/897", + "repo": "asyncapi/community", + "labels": [], + "score": 10.657920261154981 } ], "goodFirstIssues": [ From 0cc300d86580643bc4c4087cc4fa543898b2d2cb Mon Sep 17 00:00:00 2001 From: Vishvamsinh Vaghela <90895835+vishvamsinh28@users.noreply.github.com> Date: Sat, 26 Oct 2024 23:57:16 +0530 Subject: [PATCH 17/91] fix: file write errors for tools and newsroom video (#3297) Co-authored-by: Ansh Goyal --- package-lock.json | 124 ++++++++-------------------- package.json | 1 + scripts/build-newsroom-videos.js | 4 +- scripts/build-tools.js | 7 +- tests/build-newsroom-videos.test.js | 14 ++-- tests/build-tools.test.js | 18 ++-- 6 files changed, 59 insertions(+), 109 deletions(-) diff --git a/package-lock.json b/package-lock.json index bea2b1cc43e..3e06c5cffdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "clsx": "^2.1.0", "cssnano": "^6.0.3", "dotenv": "^16.4.4", + "fs-extra": "^11.2.0", "fuse.js": "^7.0.0", "googleapis": "^133.0.0", "gray-matter": "^4.0.3", @@ -4697,20 +4698,6 @@ "unstorage": "1.9.0" } }, - "node_modules/@netlify/ipx/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/@netlify/ipx/node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -4787,6 +4774,21 @@ "node": ">=14.0.0" } }, + "node_modules/@netlify/plugin-nextjs/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@netlify/plugin-nextjs/node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -6253,20 +6255,6 @@ "storybook": "^8.2.9" } }, - "node_modules/@storybook/addon-docs/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/@storybook/addon-essentials": { "version": "8.2.9", "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.2.9.tgz", @@ -6526,20 +6514,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/builder-webpack5/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/@storybook/codemod": { "version": "8.2.9", "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.2.9.tgz", @@ -6829,20 +6803,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/nextjs/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/@storybook/preset-react-webpack": { "version": "8.2.9", "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.2.9.tgz", @@ -6890,20 +6850,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/preset-react-webpack/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/@storybook/preview-api": { "version": "8.2.9", "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-8.2.9.tgz", @@ -14227,6 +14173,21 @@ "concat-map": "0.0.1" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -14339,17 +14300,17 @@ "dev": true }, "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=14.14" } }, "node_modules/fs-minipass": { @@ -27097,19 +27058,6 @@ "node": ">= 6" } }, - "node_modules/storybook/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/storybook/node_modules/globby": { "version": "14.0.2", "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", diff --git a/package.json b/package.json index 29269ed3e1d..3885874ae36 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "clsx": "^2.1.0", "cssnano": "^6.0.3", "dotenv": "^16.4.4", + "fs-extra": "^11.2.0", "fuse.js": "^7.0.0", "googleapis": "^133.0.0", "gray-matter": "^4.0.3", diff --git a/scripts/build-newsroom-videos.js b/scripts/build-newsroom-videos.js index b67ee0378cf..383927765d3 100644 --- a/scripts/build-newsroom-videos.js +++ b/scripts/build-newsroom-videos.js @@ -1,4 +1,4 @@ -const { writeFileSync } = require('fs'); +const { writeFileSync } = require('fs-extra'); const { resolve } = require('path'); const fetch = require('node-fetch-2'); @@ -19,7 +19,7 @@ async function buildNewsroomVideos(writePath) { } const data = await response.json(); - console.log(data) + console.log(data); if (!data.items || !Array.isArray(data.items)) { throw new Error('Invalid data structure received from YouTube API'); diff --git a/scripts/build-tools.js b/scripts/build-tools.js index 84965815dcc..c5cce74a7cb 100644 --- a/scripts/build-tools.js +++ b/scripts/build-tools.js @@ -1,7 +1,7 @@ const { getData } = require('./tools/extract-tools-github'); const { convertTools } = require('./tools/tools-object'); const { combineTools } = require('./tools/combine-tools'); -const fs = require('fs'); +const fs = require('fs-extra'); const { resolve } = require('path'); const buildTools = async (automatedToolsPath, manualToolsPath, toolsPath, tagsPath) => { @@ -9,10 +9,7 @@ const buildTools = async (automatedToolsPath, manualToolsPath, toolsPath, tagsPa let githubExtractData = await getData(); let automatedTools = await convertTools(githubExtractData); - fs.writeFileSync( - automatedToolsPath, - JSON.stringify(automatedTools, null, ' ') - ); + await fs.writeFile(automatedToolsPath, JSON.stringify(automatedTools, null, ' ')); await combineTools(automatedTools, require(manualToolsPath), toolsPath, tagsPath); } catch (err) { diff --git a/tests/build-newsroom-videos.test.js b/tests/build-newsroom-videos.test.js index 63f57146694..494f91f2734 100644 --- a/tests/build-newsroom-videos.test.js +++ b/tests/build-newsroom-videos.test.js @@ -1,22 +1,23 @@ -const { readFileSync, rmSync, mkdirSync } = require('fs'); -const { resolve } = require('path'); +const { readFileSync, removeSync, mkdirpSync } = require('fs-extra'); +const { resolve, join } = require('path'); const { buildNewsroomVideos } = require('../scripts/build-newsroom-videos'); const { mockApiResponse, expectedResult } = require('./fixtures/newsroomData'); const fetch = require('node-fetch-2'); +const os = require('os'); jest.mock('node-fetch-2', () => jest.fn()); describe('buildNewsroomVideos', () => { - const testDir = resolve(__dirname, 'test_config'); + const testDir = join(os.tmpdir(), 'test_config'); const testFilePath = resolve(testDir, 'newsroom_videos.json'); beforeAll(() => { - mkdirSync(testDir, { recursive: true }); + mkdirpSync(testDir); process.env.YOUTUBE_TOKEN = 'testkey'; }); afterAll(() => { - rmSync(testDir, { recursive: true, force: true }); + removeSync(testDir); }); beforeEach(() => { @@ -89,7 +90,7 @@ describe('buildNewsroomVideos', () => { json: jest.fn().mockResolvedValue(mockApiResponse), }); - const invalidPath = '/invalid_dir/newsroom_videos.json'; + const invalidPath = resolve(os.tmpdir(), 'invalid_dir', 'newsroom_videos.json'); try { await buildNewsroomVideos(invalidPath); @@ -97,5 +98,4 @@ describe('buildNewsroomVideos', () => { expect(err.message).toMatch(/ENOENT|EACCES/); } }); - }); diff --git a/tests/build-tools.test.js b/tests/build-tools.test.js index 2bc4592e8e1..74524ddb977 100644 --- a/tests/build-tools.test.js +++ b/tests/build-tools.test.js @@ -2,7 +2,9 @@ const axios = require('axios'); const { resolve } = require('path'); const { buildTools } = require('../scripts/build-tools'); const { tagsData, manualTools, mockConvertedData, mockExtractData } = require('../tests/fixtures/buildToolsData'); -const fs = require('fs'); +const fs = require('fs-extra'); +const os = require('os'); +const path = require('path'); jest.mock('axios'); jest.mock('../scripts/tools/categorylist', () => ({ @@ -24,19 +26,22 @@ jest.mock('../scripts/tools/tags-color', () => ({ })); describe('buildTools', () => { - const testDir = resolve(__dirname, 'test_config'); + const testDir = path.join(os.tmpdir(), 'test_config'); const toolsPath = resolve(testDir, 'tools.json'); const tagsPath = resolve(testDir, 'all-tags.json'); const automatedToolsPath = resolve(testDir, 'tools-automated.json'); const manualToolsPath = resolve(testDir, 'tools-manual.json'); + let consoleErrorMock; beforeAll(() => { - fs.mkdirSync(testDir, { recursive: true }); - fs.writeFileSync(manualToolsPath, JSON.stringify(manualTools)); + consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(() => {}); + fs.ensureDirSync(testDir); + fs.outputFileSync(manualToolsPath, JSON.stringify(manualTools)); }); afterAll(() => { - fs.rmSync(testDir, { recursive: true, force: true }); + fs.removeSync(testDir); + consoleErrorMock.mockRestore(); }); beforeEach(() => { @@ -62,7 +67,6 @@ describe('buildTools', () => { expect(combinedToolsContent["Category2"].description).toEqual(mockConvertedData["Category2"].description); expect(tagsContent).toEqual(tagsData); - }); it('should handle getData error', async () => { @@ -78,7 +82,7 @@ describe('buildTools', () => { it('should handle file write errors', async () => { axios.get.mockResolvedValue({ data: mockExtractData }); - const invalidPath = '/invalid_dir/tools.json'; + const invalidPath = path.resolve(os.tmpdir(), 'invalid_dir', 'tools.json'); try { await buildTools(invalidPath, manualToolsPath, toolsPath, tagsPath); From 90caba9e955b96cdd2f599a347fd37b19b1f7c25 Mon Sep 17 00:00:00 2001 From: Vishvamsinh Vaghela <90895835+vishvamsinh28@users.noreply.github.com> Date: Sun, 27 Oct 2024 00:07:56 +0530 Subject: [PATCH 18/91] feat: exclude scripts with import errors (#3285) Co-authored-by: Ansh Goyal --- jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest.config.js b/jest.config.js index 9d370a6bb76..39211f19dc4 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,6 +4,7 @@ module.exports = { coverageReporters: ['text', 'lcov', 'json-summary'], coverageDirectory: 'coverage', collectCoverageFrom: ['scripts/**/*.js'], + coveragePathIgnorePatterns: ['scripts/compose.js'], // To disallow netlify edge function tests from running testMatch: ['**/tests/**/*.test.*', '!**/netlify/**/*.test.*'], }; \ No newline at end of file From c9ef36daa9e8ec2dc058746f3ce6eee52c0d7cba Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Sun, 27 Oct 2024 02:40:21 +0200 Subject: [PATCH 19/91] chore: update meetings.json and newsrooom_videos.json (#3332) --- config/meetings.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/meetings.json b/config/meetings.json index 850bac956a6..06ad36dae20 100644 --- a/config/meetings.json +++ b/config/meetings.json @@ -152,5 +152,12 @@ "url": "https://github.com/asyncapi/community/issues/1566", "banner": "", "date": "2024-10-28T16:00:00.000Z" + }, + { + "title": "AsyncAPI + WebSocket: The Collaborative Combo ", + "calLink": "https://www.google.com/calendar/event?eid=bGo4aXNjNzg3Ym5tbWRtb2wxZ2ZuMmtxN2sgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1569", + "banner": "https://github.com/user-attachments/assets/0cdfc741-e61d-4710-bb0a-af9f7485ff9a", + "date": "2024-11-01T13:00:00.000Z" } ] \ No newline at end of file From 5c11eb089d9fb4e82156adb08754443da5a039b2 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Sun, 27 Oct 2024 12:29:40 +0100 Subject: [PATCH 20/91] docs(cli): update latest cli documentation (#3333) --- markdown/docs/tools/cli/usage.md | 52 ++++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/markdown/docs/tools/cli/usage.md b/markdown/docs/tools/cli/usage.md index a8d86b446bc..98ccd5e79dd 100644 --- a/markdown/docs/tools/cli/usage.md +++ b/markdown/docs/tools/cli/usage.md @@ -27,7 +27,7 @@ $ npm install -g @asyncapi/cli $ asyncapi COMMAND running command... $ asyncapi (--version) -@asyncapi/cli/2.7.3 linux-x64 node-v18.20.4 +@asyncapi/cli/2.7.4 linux-x64 node-v18.20.4 $ asyncapi --help [COMMAND] USAGE $ asyncapi COMMAND @@ -99,7 +99,7 @@ EXAMPLES $ asyncapi bundle ./asyncapi.yaml -o final-asyncapi.yaml --base ../public-api/main.yaml --baseDir ./social-media/comments-service ``` -_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/bundle.ts)_ +_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/bundle.ts)_ ## `asyncapi config` @@ -113,7 +113,7 @@ DESCRIPTION CLI config settings ``` -_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/index.ts)_ +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/index.ts)_ ## `asyncapi config analytics` @@ -133,7 +133,7 @@ DESCRIPTION Enable or disable analytics for metrics collection ``` -_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/analytics.ts)_ +_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/analytics.ts)_ ## `asyncapi config context` @@ -147,7 +147,7 @@ DESCRIPTION Manage short aliases for full paths to AsyncAPI documents ``` -_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/index.ts)_ +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/index.ts)_ ## `asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH` @@ -169,7 +169,7 @@ DESCRIPTION Add a context to the store ``` -_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/add.ts)_ +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/add.ts)_ ## `asyncapi config context current` @@ -186,7 +186,7 @@ DESCRIPTION Shows the current context that is being used ``` -_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/current.ts)_ +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/current.ts)_ ## `asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` @@ -207,7 +207,7 @@ DESCRIPTION Edit a context in the store ``` -_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/edit.ts)_ +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/edit.ts)_ ## `asyncapi config context init [CONTEXT-FILE-PATH]` @@ -230,7 +230,7 @@ DESCRIPTION Initialize context ``` -_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/init.ts)_ +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/init.ts)_ ## `asyncapi config context list` @@ -247,7 +247,7 @@ DESCRIPTION List all the stored contexts in the store ``` -_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/list.ts)_ +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/list.ts)_ ## `asyncapi config context remove CONTEXT-NAME` @@ -267,7 +267,7 @@ DESCRIPTION Delete a context from the store ``` -_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/remove.ts)_ +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/remove.ts)_ ## `asyncapi config context use CONTEXT-NAME` @@ -287,7 +287,7 @@ DESCRIPTION Set a context as current ``` -_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/context/use.ts)_ +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/use.ts)_ ## `asyncapi config versions` @@ -304,7 +304,7 @@ DESCRIPTION Show versions of AsyncAPI tools used ``` -_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/config/versions.ts)_ +_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/versions.ts)_ ## `asyncapi convert [SPEC-FILE]` @@ -332,7 +332,7 @@ DESCRIPTION Convert asyncapi documents older to newer versions or OpenAPI/postman-collection documents to AsyncAPI ``` -_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/convert.ts)_ +_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/convert.ts)_ ## `asyncapi diff OLD NEW` @@ -372,7 +372,7 @@ DESCRIPTION Find diff between two asyncapi files ``` -_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/diff.ts)_ +_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/diff.ts)_ ## `asyncapi generate` @@ -386,7 +386,7 @@ DESCRIPTION Generate typed models or other things like clients, applications or docs using AsyncAPI Generator templates. ``` -_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/generate/index.ts)_ +_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/generate/index.ts)_ ## `asyncapi generate fromTemplate ASYNCAPI TEMPLATE` @@ -431,7 +431,7 @@ EXAMPLES $ asyncapi generate fromTemplate asyncapi.yaml @asyncapi/html-template --param version=1.0.0 singleFile=true --output ./docs --force-write ``` -_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/generate/fromTemplate.ts)_ +_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/generate/fromTemplate.ts)_ ## `asyncapi generate models LANGUAGE FILE` @@ -502,7 +502,7 @@ DESCRIPTION Generates typed models ``` -_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/generate/models.ts)_ +_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/generate/models.ts)_ ## `asyncapi new` @@ -560,7 +560,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/new/index.ts)_ +_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/new/index.ts)_ ## `asyncapi new file` @@ -618,7 +618,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/new/file.ts)_ +_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/new/file.ts)_ ## `asyncapi new glee` @@ -640,7 +640,7 @@ DESCRIPTION Creates a new Glee project ``` -_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/new/glee.ts)_ +_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/new/glee.ts)_ ## `asyncapi new template` @@ -664,7 +664,7 @@ DESCRIPTION Creates a new template ``` -_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/new/template.ts)_ +_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/new/template.ts)_ ## `asyncapi optimize [SPEC-FILE]` @@ -706,7 +706,7 @@ EXAMPLES $ asyncapi optimize ./asyncapi.yaml --ignore=schema ``` -_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/optimize.ts)_ +_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/optimize.ts)_ ## `asyncapi start` @@ -720,7 +720,7 @@ DESCRIPTION Starts AsyncAPI-related services. Currently, it supports launching the AsyncAPI Studio ``` -_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/start/index.ts)_ +_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/start/index.ts)_ ## `asyncapi start studio` @@ -739,7 +739,7 @@ DESCRIPTION starts a new local instance of Studio ``` -_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/start/studio.ts)_ +_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/start/studio.ts)_ ## `asyncapi validate [SPEC-FILE]` @@ -769,5 +769,5 @@ DESCRIPTION validate asyncapi file ``` -_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.7.3/src/commands/validate.ts)_ +_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/validate.ts)_ From fd48c6a6489f74345ebbd7a27a23da1ec11012e2 Mon Sep 17 00:00:00 2001 From: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> Date: Sun, 27 Oct 2024 19:27:35 +0200 Subject: [PATCH 21/91] feat: create banner for online conf (#3312) Co-authored-by: Akshat Nema <76521428+akshatnema@users.noreply.github.com>%0ACo-authored-by: akshatnema %0ACo-authored-by: Ansh Goyal --- components/campaigns/AnnouncementHero.tsx | 49 +++++++++++------------ components/campaigns/banners.ts | 20 ++++----- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/components/campaigns/AnnouncementHero.tsx b/components/campaigns/AnnouncementHero.tsx index 61ffb47b85e..bee864e495c 100644 --- a/components/campaigns/AnnouncementHero.tsx +++ b/components/campaigns/AnnouncementHero.tsx @@ -1,10 +1,10 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import ArrowLeft from '../icons/ArrowLeft'; import ArrowRight from '../icons/ArrowRight'; import Container from '../layout/Container'; import Banner from './AnnouncementBanner'; -import { banners } from './banners'; +import { banners, shouldShowBanner } from './banners'; interface IAnnouncementHeroProps { className?: string; @@ -21,15 +21,15 @@ interface IAnnouncementHeroProps { export default function AnnouncementHero({ className = '', small = false }: IAnnouncementHeroProps) { const [activeIndex, setActiveIndex] = useState(0); - const len = banners.length; - const numberOfVisibleBanners = banners.filter((banner) => banner.show).length; + const visibleBanners = useMemo(() => banners.filter((banner) => shouldShowBanner(banner.cfpDeadline)), [banners]); + const numberOfVisibleBanners = visibleBanners.length; const goToPrevious = () => { - setActiveIndex((prevIndex) => (prevIndex === 0 ? len - 1 : prevIndex - 1)); + setActiveIndex((prevIndex) => (prevIndex === 0 ? numberOfVisibleBanners - 1 : prevIndex - 1)); }; const goToNext = () => { - setActiveIndex((prevIndex) => (prevIndex === len - 1 ? 0 : prevIndex + 1)); + setActiveIndex((prevIndex) => (prevIndex === numberOfVisibleBanners - 1 ? 0 : prevIndex + 1)); }; const goToIndex = (index: number) => { @@ -62,31 +62,28 @@ export default function AnnouncementHero({ className = '', small = false }: IAnn )}
- {banners.map( - (banner, index) => - banner.show && ( - - ) - )} + {visibleBanners.map((banner, index) => ( + + ))}
- {banners.map((banner, index) => ( + {visibleBanners.map((banner, index) => (
goToIndex(index)} /> diff --git a/components/campaigns/banners.ts b/components/campaigns/banners.ts index b6472dbf4a2..0620e6bdde9 100644 --- a/components/campaigns/banners.ts +++ b/components/campaigns/banners.ts @@ -3,7 +3,7 @@ * @returns Whether the banner should be shown * @description Check if the current date is after the deadline */ -function shouldShowBanner(cfpDeadline: string) { +export function shouldShowBanner(cfpDeadline: string) { const currentDate = new Date(); // G et the current date const deadline = new Date(cfpDeadline); // Convert the cfpDeadline string to a Date object @@ -15,18 +15,14 @@ function shouldShowBanner(cfpDeadline: string) { return true; } -const cfpDeadlineParis = '2024-10-12T06:00:00Z'; -const showBannerParis = shouldShowBanner(cfpDeadlineParis); - export const banners = [ { - title: "AsyncAPI Conf on Tour'24", - city: 'Paris', - dateLocation: '3rd - 5th of December, 2024 | France, Paris', - cfaText: 'Apply To Speak', - eventName: 'the end of Call for Speakers', - cfpDeadline: cfpDeadlineParis, - link: 'https://conference.asyncapi.com/venue/Paris', - show: showBannerParis + title: "AsyncAPI Online Conference'24", + city: 'YouTube', + dateLocation: '30th of October, 2024 | YouTube & LinkedIn', + cfaText: 'Join us Live', + eventName: 'the AsyncAPI Online Conference', + cfpDeadline: '2024-10-30T06:00:00Z', + link: 'https://www.youtube.com/live/F9wHxd-v2f0?si=kPCqgUzqAKC0FaqJ' } ]; From 7c27ab646f9bebf4a2acf0add21cde0bc8fd2f34 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Mon, 28 Oct 2024 01:39:10 +0100 Subject: [PATCH 22/91] chore: update tools.json (#3336) --- config/all-tags.json | 2 +- config/tools-automated.json | 161 ++++++++++++++++++------------------ config/tools.json | 2 +- 3 files changed, 82 insertions(+), 83 deletions(-) diff --git a/config/all-tags.json b/config/all-tags.json index bcbe78efc37..b2a1c6f3c3a 100644 --- a/config/all-tags.json +++ b/config/all-tags.json @@ -1 +1 @@ -{"languages":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"},{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"},{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"},{"name":"HTML","color":"bg-[#E2A291]","borderColor":"border-[#E44D26]"},{"name":"C/C++","color":"bg-[#93CDEF]","borderColor":"border-[#0080CC]"},{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"},{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"},{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"},{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"},{"name":"Scala","color":"bg-[#FFA299]","borderColor":"border-[#DF301F]"},{"name":"Markdown","color":"bg-[#BABEBF]","borderColor":"border-[#445B64]"},{"name":"YAML","color":"bg-[#FFB764]","borderColor":"border-[#F1901F]"},{"name":"R","color":"bg-[#84B5ED]","borderColor":"border-[#246BBE]"},{"name":"Ruby","color":"bg-[#FF8289]","borderColor":"border-[#FF000F]"},{"name":"Rust","color":"bg-[#FFB8AA]","borderColor":"border-[#E43716]"},{"name":"Shell","color":"bg-[#87D4FF]","borderColor":"border-[#389ED7]"},{"name":"Groovy","color":"bg-[#B6D5E5]","borderColor":"border-[#609DBC]"}],"technologies":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Hermes","color":"bg-[#8AEEBD]","borderColor":"border-[#2AB672]"},{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"},{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"AWS","color":"bg-[#FF9F59]","borderColor":"border-[#EF6703]"},{"name":"Docker","color":"bg-[#B8E0FF]","borderColor":"border-[#2596ED]"},{"name":"Node-RED","color":"bg-[#FF7474]","borderColor":"border-[#8F0101]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Saas","color":"bg-[#6AB8EC]","borderColor":"border-[#2275AD]"},{"name":"Kubernetes-native","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Scala","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Azure","color":"bg-[#4B93FF]","borderColor":"border-[#015ADF]"},{"name":"Jenkins","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Nest Js","color":"bg-[#E1224E]","borderColor":"border-[#B9012b]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Socket.IO","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Kotlin","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Groovy","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Markdown","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Shell","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"WebComponents","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Babel","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Storybook","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"VSCode","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"SmartPaste","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JetBrains","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"IntelliJ IDEA","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Java","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"HTML","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}]} \ No newline at end of file +{"languages":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"},{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"},{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"},{"name":"HTML","color":"bg-[#E2A291]","borderColor":"border-[#E44D26]"},{"name":"C/C++","color":"bg-[#93CDEF]","borderColor":"border-[#0080CC]"},{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"},{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"},{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"},{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"},{"name":"Scala","color":"bg-[#FFA299]","borderColor":"border-[#DF301F]"},{"name":"Markdown","color":"bg-[#BABEBF]","borderColor":"border-[#445B64]"},{"name":"YAML","color":"bg-[#FFB764]","borderColor":"border-[#F1901F]"},{"name":"R","color":"bg-[#84B5ED]","borderColor":"border-[#246BBE]"},{"name":"Ruby","color":"bg-[#FF8289]","borderColor":"border-[#FF000F]"},{"name":"Rust","color":"bg-[#FFB8AA]","borderColor":"border-[#E43716]"},{"name":"Shell","color":"bg-[#87D4FF]","borderColor":"border-[#389ED7]"},{"name":"Groovy","color":"bg-[#B6D5E5]","borderColor":"border-[#609DBC]"}],"technologies":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Hermes","color":"bg-[#8AEEBD]","borderColor":"border-[#2AB672]"},{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"},{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"AWS","color":"bg-[#FF9F59]","borderColor":"border-[#EF6703]"},{"name":"Docker","color":"bg-[#B8E0FF]","borderColor":"border-[#2596ED]"},{"name":"Node-RED","color":"bg-[#FF7474]","borderColor":"border-[#8F0101]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Saas","color":"bg-[#6AB8EC]","borderColor":"border-[#2275AD]"},{"name":"Kubernetes-native","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Scala","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Azure","color":"bg-[#4B93FF]","borderColor":"border-[#015ADF]"},{"name":"Jenkins","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Nest Js","color":"bg-[#E1224E]","borderColor":"border-[#B9012b]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Socket.IO","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Kotlin","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Groovy","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Markdown","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Shell","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"WebComponents","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Babel","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Storybook","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"VSCode","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"SmartPaste","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JetBrains","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"IntelliJ IDEA","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"HTML","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Java","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}]} \ No newline at end of file diff --git a/config/tools-automated.json b/config/tools-automated.json index a48496cf7dd..6378b0db96c 100644 --- a/config/tools-automated.json +++ b/config/tools-automated.json @@ -94,41 +94,41 @@ } }, { - "title": "SIO-AsyncAPI", - "description": "This is code-first approach to generate AsyncAPI specification from Socket.IO server.", + "title": "nestjs-asyncapi", + "description": "Utilize decorators to generate AsyncAPI document utilizing DTOs (similar to @nestjs/swagger) and a web UI.", "links": { - "websiteUrl": "https://github.com/daler-rahimov/sio-asyncapi", - "docsUrl": "https://github.com/daler-rahimov/sio-asyncapi", - "repoUrl": "https://github.com/daler-rahimov/sio-asyncapi" + "repoUrl": "https://github.com/flamewow/nestjs-asyncapi" }, "filters": { - "language": "Python", + "language": "Typescript", "technology": [ - "Socket.IO", - "Flask" + "Node.js", + "NestJS" ], "categories": [ - "code-first", - "api" + "code-first" ], "hasCommercial": false, "isAsyncAPIOwner": false } }, { - "title": "nestjs-asyncapi", - "description": "Utilize decorators to generate AsyncAPI document utilizing DTOs (similar to @nestjs/swagger) and a web UI.", + "title": "SIO-AsyncAPI", + "description": "This is code-first approach to generate AsyncAPI specification from Socket.IO server.", "links": { - "repoUrl": "https://github.com/flamewow/nestjs-asyncapi" + "websiteUrl": "https://github.com/daler-rahimov/sio-asyncapi", + "docsUrl": "https://github.com/daler-rahimov/sio-asyncapi", + "repoUrl": "https://github.com/daler-rahimov/sio-asyncapi" }, "filters": { - "language": "Typescript", + "language": "Python", "technology": [ - "Node.js", - "NestJS" + "Socket.IO", + "Flask" ], "categories": [ - "code-first" + "code-first", + "api" ], "hasCommercial": false, "isAsyncAPIOwner": false @@ -154,27 +154,6 @@ "isAsyncAPIOwner": false } }, - { - "title": "AsyncAPI Modelina", - "description": "Generate payload models into Java, TypeScript, Go, etc, you name it, from AsyncAPI documents. This tool gives you full control over the models through high customization", - "links": { - "websiteUrl": "https://modelina.org", - "docsUrl": "https://github.com/asyncapi/modelina/tree/master/docs", - "repoUrl": "https://github.com/asyncapi/modelina" - }, - "filters": { - "language": "TypeScript", - "technology": [ - "React JS", - "Docker" - ], - "categories": [ - "code-generator" - ], - "hasCommercial": false, - "isAsyncAPIOwner": true - } - }, { "title": "ZenWave SDK", "description": "DDD and API-First for Event-Driven Microservices", @@ -200,6 +179,27 @@ "hasCommercial": false, "isAsyncAPIOwner": false } + }, + { + "title": "AsyncAPI Modelina", + "description": "Generate payload models into Java, TypeScript, Go, etc, you name it, from AsyncAPI documents. This tool gives you full control over the models through high customization", + "links": { + "websiteUrl": "https://modelina.org", + "docsUrl": "https://github.com/asyncapi/modelina/tree/master/docs", + "repoUrl": "https://github.com/asyncapi/modelina" + }, + "filters": { + "language": "TypeScript", + "technology": [ + "React JS", + "Docker" + ], + "categories": [ + "code-generator" + ], + "hasCommercial": false, + "isAsyncAPIOwner": true + } } ] }, @@ -342,6 +342,23 @@ "Frameworks": { "description": "The following is a list of API/application frameworks that make use of AsyncAPI.", "toolsList": [ + { + "title": "Glee", + "description": "Glee — The AsyncAPI framework that will make you smile again :)", + "links": { + "repoUrl": "https://github.com/asyncapi/glee" + }, + "filters": { + "technology": [ + "TypeScript" + ], + "categories": [ + "framework" + ], + "hasCommercial": false, + "isAsyncAPIOwner": true + } + }, { "title": "Zod Sockets", "description": "Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.", @@ -694,24 +711,6 @@ "hasCommercial": false, "isAsyncAPIOwner": true } - }, - { - "title": "asyncapi-preview", - "description": "VSCode extension that enables you to:\n - Preview documentation generated using you AsyncAPI document. It uses AsyncAPI React component under the hood,\n - Create AsyncAPI documents faster using SmartPaste functionality\n", - "links": { - "repoUrl": "https://github.com/Savio629/testing2" - }, - "filters": { - "technology": [ - "VSCode", - "SmartPaste" - ], - "categories": [ - "ide-extension" - ], - "hasCommercial": false, - "isAsyncAPIOwner": false - } } ] }, @@ -719,18 +718,15 @@ "description": "The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents.", "toolsList": [ { - "title": "Java Spring Cloud Stream Template", - "description": "Java Spring Cloud Stream template for the AsyncAPI Generator", + "title": "Node.js Websockets Template", + "description": "Node.js WebSockets template for the AsyncAPI Generator. It showcases how from a single AsyncAPI document you can generate a server and a client at the same time.", "links": { - "repoUrl": "https://github.com/asyncapi/java-spring-cloud-stream-template" + "repoUrl": "https://github.com/asyncapi/nodejs-ws-template" }, "filters": { - "language": [ - "javascript" - ], + "language": "javascript", "technology": [ - "Spring Cloud Streams", - "Maven" + "Node.js" ], "categories": [ "generator-template" @@ -740,15 +736,15 @@ } }, { - "title": "Node.js Multiprotocol Template", - "description": "This template generates a server using your AsyncAPI document. It supports multiple different protocols, like Kafka or MQTT. It is designed in the way that generated code is a library and with it's API you can start the server, send messages or register a middleware for listening incoming messages. Runtime message validation included.", + "title": "HTML Template", + "description": "HTML template for AsyncAPI Generator. Use it to generate a static docs. It is using AsyncAPI React component under the hood.", "links": { - "repoUrl": "https://github.com/asyncapi/nodejs-template" + "repoUrl": "https://github.com/asyncapi/html-template" }, "filters": { "language": "javascript", "technology": [ - "Node.js" + "HTML" ], "categories": [ "generator-template" @@ -758,17 +754,18 @@ } }, { - "title": "Java Template", - "description": "Java template for the AsyncAPI Generator", + "title": "Java Spring Cloud Stream Template", + "description": "Java Spring Cloud Stream template for the AsyncAPI Generator", "links": { - "repoUrl": "https://github.com/asyncapi/java-template" + "repoUrl": "https://github.com/asyncapi/java-spring-cloud-stream-template" }, "filters": { "language": [ "javascript" ], "technology": [ - "Java" + "Spring Cloud Streams", + "Maven" ], "categories": [ "generator-template" @@ -778,15 +775,17 @@ } }, { - "title": "Node.js Websockets Template", - "description": "Node.js WebSockets template for the AsyncAPI Generator. It showcases how from a single AsyncAPI document you can generate a server and a client at the same time.", + "title": "Java Template", + "description": "Java template for the AsyncAPI Generator", "links": { - "repoUrl": "https://github.com/asyncapi/nodejs-ws-template" + "repoUrl": "https://github.com/asyncapi/java-template" }, "filters": { - "language": "javascript", + "language": [ + "javascript" + ], "technology": [ - "Node.js" + "Java" ], "categories": [ "generator-template" @@ -796,15 +795,15 @@ } }, { - "title": "HTML Template", - "description": "HTML template for AsyncAPI Generator. Use it to generate a static docs. It is using AsyncAPI React component under the hood.", + "title": "Node.js Multiprotocol Template", + "description": "This template generates a server using your AsyncAPI document. It supports multiple different protocols, like Kafka or MQTT. It is designed in the way that generated code is a library and with it's API you can start the server, send messages or register a middleware for listening incoming messages. Runtime message validation included.", "links": { - "repoUrl": "https://github.com/asyncapi/html-template" + "repoUrl": "https://github.com/asyncapi/nodejs-template" }, "filters": { "language": "javascript", "technology": [ - "HTML" + "Node.js" ], "categories": [ "generator-template" diff --git a/config/tools.json b/config/tools.json index ccb2d7a5f45..0265d466afd 100644 --- a/config/tools.json +++ b/config/tools.json @@ -1 +1 @@ -{"APIs":{"description":"The following is a list of APIs that expose functionality related to AsyncAPI.","toolsList":[{"title":"API Tracker - AsyncAPI specs","description":"Explore APIs and companies with public AsyncAPI specifications.","links":{"websiteUrl":"https://apitracker.io/specifications/asyncapi","repoUrl":""},"filters":{"categories":["api","directory"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI Server API","description":"Server API providing official AsyncAPI tools","links":{"websiteUrl":"https://api.asyncapi.com/v1","docsUrl":"https://api.asyncapi.com/v1/docs","repoUrl":"https://github.com/asyncapi/server-api"},"filters":{"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["api"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI-Directory by APIs.guru","description":"Directory of asynchronous API specifications in AsyncAPI format.","links":{"websiteUrl":"https://apis.guru/asyncapi-directory/","repoUrl":"https://github.com/APIs-guru/asyncapi-directory"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["api","directory"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"SIO-AsyncAPI","description":"This is code-first approach to generate AsyncAPI specification from Socket.IO server.","links":{"websiteUrl":"https://github.com/daler-rahimov/sio-asyncapi","docsUrl":"https://github.com/daler-rahimov/sio-asyncapi","repoUrl":"https://github.com/daler-rahimov/sio-asyncapi"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"technology":[{"name":"Socket.IO","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"}],"categories":["code-first","api"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Code-first tools":{"description":"The following is a list of tools that generate AsyncAPI documents from your code.","toolsList":[{"title":"AsyncAPI.Net","description":"The AsyncAPI.NET SDK contains a useful object model for AsyncAPI documents in .NET along with common serializers to extract raw OpenAPI JSON and YAML documents from the model.","links":{"websiteUrl":"https://github.com/LEGO/AsyncAPI.NET/","repoUrl":"https://github.com/LEGO/AsyncAPI.NET"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["converters","code-first","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncApi.Net.Generator","description":"Code-first AsyncAPI documentation generator and ui","links":{"repoUrl":"https://github.com/yurvon-screamo/asyncapi.net"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"EventBridge Atlas","description":"Tool that translates your AWS EventBridge Schemas into an AsyncAPI document and a web UI.","links":{"websiteUrl":"https://eventbridge-atlas.netlify.app/","repoUrl":"https://github.com/boyney123/eventbridge-atlas"},"filters":{"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"FastStream","description":"A powerful and easy-to-use Python framework for building asynchronous services interacting with event streams such as Apache Kafka, RabbitMQ and NATS.","links":{"websiteUrl":"https://faststream.airt.ai","repoUrl":"https://github.com/airtai/FastStream"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"categories":["code-first","framework"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Go AsyncAPI","description":"This library helps to create AsyncAPI spec from your Go message structures. It uses reflection to translate Go structures in JSON Schema definitions and arrange them in AsyncAPI schema.","links":{"repoUrl":"https://github.com/swaggest/go-asyncapi"},"filters":{"language":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Java AsyncAPI","description":"This tool stores modules, which simplifies interacting with AsyncAPI in jvm ecosystem.","links":{"repoUrl":"https://github.com/asyncapi/jasyncapi"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Kotlin","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"KnstEventBus","description":"AsyncApi code-first tools for c#. Generates document and view.","links":{"repoUrl":"https://github.com/d0972058277/KnstEventBus"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"},{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"}],"categories":["code-first","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Kotlin AsyncAPI","description":"The Kotlin AsyncAPI project aims to provide convenience tools for generating and serving AsyncAPI documentation. The core of this project is a Kotlin DSL for building the specification in a typesafe way.","links":{"repoUrl":"https://github.com/OpenFolder/kotlin-asyncapi"},"filters":{"language":[{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"nestjs-asyncapi","description":"Utilize decorators to generate AsyncAPI document utilizing DTOs (similar to @nestjs/swagger) and a web UI.","links":{"repoUrl":"https://github.com/flamewow/nestjs-asyncapi"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Nest Js","color":"bg-[#E1224E]","borderColor":"border-[#B9012b]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Neuroglia AsyncAPI","description":"A .NET SDK for the Async API specification. Automatically generates and serves AsyncAPI documents based on your code. Includes fluent-builders to create AsyncAPI documents from scratch, and provides a web-based GUI to browse generated documents.","links":{"repoUrl":"https://github.com/neuroglia-io/AsyncApi"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Saunter","description":"Saunter is an AsyncAPI documentation generator for dotnet. Generates (and hosts) an AsyncAPI schema document from your code.","links":{"repoUrl":"https://github.com/tehmantra/saunter"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"SIO-AsyncAPI","description":"This is code-first approach to generate AsyncAPI specification from Socket.IO server.","links":{"websiteUrl":"https://github.com/daler-rahimov/sio-asyncapi","docsUrl":"https://github.com/daler-rahimov/sio-asyncapi","repoUrl":"https://github.com/daler-rahimov/sio-asyncapi"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"technology":[{"name":"Socket.IO","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"}],"categories":["code-first","api"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Springwolf","description":"Automated documentation for async APIs built with Spring Boot. Like Springfox for AsyncAPI. Auto-generates an AsyncAPI document and a web UI.","links":{"websiteUrl":"https://www.springwolf.dev","repoUrl":"https://github.com/springwolf/springwolf-core"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"sttp tapir","description":"Library for describing HTTP endpoints, and then interpreting them as a server, client, or documentation","links":{"websiteUrl":"https://tapir.softwaremill.com/","repoUrl":"https://github.com/softwaremill/tapir"},"filters":{"language":[{"name":"Scala","color":"bg-[#FFA299]","borderColor":"border-[#DF301F]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Zod Sockets","description":"Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.","links":{"websiteUrl":"https://www.npmjs.com/package/zod-sockets","repoUrl":"https://github.com/RobinTail/zod-sockets"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","dsl","framework"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Code Generators":{"description":"The following is a list of tools that generate code from an AsyncAPI document; not the other way around.","toolsList":[{"title":"AsyncAPI Generator","description":"Generator is a tool that you can use to generate whatever you want basing on the AsyncAPI specification file as an input.","links":{"docsUrl":"https://www.asyncapi.com/docs/tools/generator","repoUrl":"https://github.com/asyncapi/generator"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["code-generator","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI Modelina","description":"Generate payload models into Java, TypeScript, Go, etc, you name it, from AsyncAPI documents. This tool gives you full control over the models through high customization","links":{"websiteUrl":"https://modelina.org","docsUrl":"https://github.com/asyncapi/modelina/tree/master/docs","repoUrl":"https://github.com/asyncapi/modelina"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":"Docker","color":"bg-[#B8E0FF]","borderColor":"border-[#2596ED]"}],"categories":["code-generator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Golang AsyncAPI Code Generator","description":"Generate Go user and application boilerplate from AsyncAPI specifications. Can be called from `go generate` without requirements.\n","links":{"repoUrl":"https://github.com/lerenn/asyncapi-codegen"},"filters":{"language":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"}],"categories":["code-generator"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"MultiAPI Generator","description":"This is a plugin designed to help developers automatizing the creation of code classes from YML files based on AsyncApi and OpenAPI. It is presented in 2 flavours Maven and Gradle","links":{"repoUrl":"https://github.com/sngular/scs-multiapi-plugin"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Groovy","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["code-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Node-RED AsyncAPI plugin","description":"A plugin for generating and configuring nodes for Kafka, MQTT, AMQP, etc. automatically from an AsyncAPI specification.","links":{"repoUrl":"https://github.com/dalelane/node-red-contrib-plugin-asyncapi"},"filters":{"technology":[{"name":"Node-RED","color":"bg-[#FF7474]","borderColor":"border-[#8F0101]"}],"categories":["code-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"ZenWave SDK","description":"DDD and API-First for Event-Driven Microservices","links":{"websiteUrl":"https://zenwave360.github.io/","docsUrl":"https://zenwave360.github.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/","repoUrl":"https://github.com/zenwave360/zenwave-sdk"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","dsl","mocking-and-testing","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Converters":{"description":"The following is a list of tools that do not yet belong to any specific category but are also useful for the community.","toolsList":[{"title":"AsyncAPI-format","description":"Format an AsyncAPI document by ordering, casing, formatting, and filtering fields.","links":{"repoUrl":"https://github.com/thim81/asyncapi-format"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["converter","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI.Net","description":"The AsyncAPI.NET SDK contains a useful object model for AsyncAPI documents in .NET along with common serializers to extract raw OpenAPI JSON and YAML documents from the model.","links":{"websiteUrl":"https://github.com/LEGO/AsyncAPI.NET/","repoUrl":"https://github.com/LEGO/AsyncAPI.NET"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["converters","code-first","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Converter","description":"Converts old versions of AsyncAPI files into the latest version.","links":{"repoUrl":"https://github.com/asyncapi/converter-js"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["converter"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Converter-Go","description":"The AsyncAPI Converter converts AsyncAPI documents from versions 1.0.0, 1.1.0 and 1.2.0 to version 2.0.0. It supports both json and yaml formats on input and output. By default, the AsyncAPI Converter converts a document into the json format.","links":{"repoUrl":"https://github.com/asyncapi/converter-go"},"filters":{"language":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"}],"categories":["converter"],"hasCommercial":false,"isAsyncAPIOwner":true,"technology":[]}}]},"Directories":{"description":"The following is a list of directories that index public AsyncAPI documents.","toolsList":[{"title":"API Tracker - AsyncAPI specs","description":"Explore APIs and companies with public AsyncAPI specifications.","links":{"websiteUrl":"https://apitracker.io/specifications/asyncapi","repoUrl":""},"filters":{"categories":["api","directory"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI-Directory by APIs.guru","description":"Directory of asynchronous API specifications in AsyncAPI format.","links":{"websiteUrl":"https://apis.guru/asyncapi-directory/","repoUrl":"https://github.com/APIs-guru/asyncapi-directory"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["api","directory"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Documentation Generators":{"description":"The following is a list of tools that generate human-readable documentation from an AsyncAPI document.","toolsList":[{"title":"AsyncAPI Generator","description":"Generator is a tool that you can use to generate whatever you want basing on the AsyncAPI specification file as an input.","links":{"docsUrl":"https://www.asyncapi.com/docs/tools/generator","repoUrl":"https://github.com/asyncapi/generator"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Markdown","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"asyncapi-asciidoc-template","description":"Asciidoc template for the asyncapi generator","links":{"repoUrl":"https://gitlab.com/djencks/asyncapi-asciidoc-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"}],"categories":["documentation-generator","generator-template"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Bump.sh","description":"OpenAPI 2 & 3 / AsyncAPI 2 documentation generator, with automatic changelog and visual diff.","links":{"websiteUrl":"https://bump.sh/","docsUrl":"https://docs.bump.sh/help/","repoUrl":""},"filters":{"categories":["documentation-generator"],"hasCommercial":true,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Cupid","description":"A library that focuses on finding and analyzing the relationships between AsyncAPI documents. It outputs a map of the system architecture.","links":{"repoUrl":"https://github.com/asyncapi/cupid"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"KnstEventBus","description":"AsyncApi code-first tools for c#. Generates document and view.","links":{"repoUrl":"https://github.com/d0972058277/KnstEventBus"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"},{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"}],"categories":["code-first","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Springwolf","description":"Automated documentation for async APIs built with Spring Boot. Like Springfox for AsyncAPI. Auto-generates an AsyncAPI document and a web UI.","links":{"websiteUrl":"https://www.springwolf.dev","repoUrl":"https://github.com/springwolf/springwolf-core"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Widdershins","description":"OpenAPI 3.0 / Swagger 2.0 / AsyncAPI 1.0 definition to Slate / Shins compatible markdown.","links":{"websiteUrl":"https://mermade.github.io/reslate/","repoUrl":"https://github.com/Mermade/widdershins"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Shell","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Editors":{"description":"The following is a list of editors or related tools that allow editing of AsyncAPI document.","toolsList":[{"title":"AsyncAPI Studio","description":"Visually design your AsyncAPI files and event-driven architecture.","links":{"websiteUrl":"https://studio.asyncapi.com","repoUrl":"https://github.com/asyncapi/studio"},"filters":{"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["editor"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"UI components":{"description":"The following is a list of UI components to view AsyncAPI documents.","toolsList":[{"title":"Api-Diff-Viewer","description":"React component to view the difference between two Json based API documents. Supported specifications: JsonSchema, OpenAPI 3.x, AsyncAPI 2.x.","links":{"repoUrl":"https://github.com/udamir/api-diff-viewer","websiteUrl":"https://api-diff-viewer.vercel.app/"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":"Babel","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Storybook","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ui-component"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI React component","description":"React component for rendering documentation from your specification in real-time in the browser. It also provides a WebComponent and bundle for Angular and Vue","links":{"repoUrl":"https://github.com/asyncapi/asyncapi-react"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":"WebComponents","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ui-component"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"DSL":{"description":"Writing YAML by hand is no fun, and maybe you don't want a GUI, so use a Domain Specific Language to write AsyncAPI in your language of choice.","toolsList":[{"title":"BOATS","description":"Compile your single AsyncAPI file from multiple YAML files with BOATS and with the help of the template engine Nunjucks, plus a many extra helpers to automate much of the donkey work.","links":{"repoUrl":"https://github.com/j-d-carmichael/boats"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["dsl"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"ZenWave SDK","description":"DDD and API-First for Event-Driven Microservices","links":{"websiteUrl":"https://zenwave360.github.io/","docsUrl":"https://zenwave360.github.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/","repoUrl":"https://github.com/zenwave360/zenwave-sdk"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","dsl","mocking-and-testing","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Zod Sockets","description":"Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.","links":{"websiteUrl":"https://www.npmjs.com/package/zod-sockets","repoUrl":"https://github.com/RobinTail/zod-sockets"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","dsl","framework"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Frameworks":{"description":"The following is a list of API/application frameworks that make use of AsyncAPI.","toolsList":[{"title":"Asynction","description":"SocketIO server framework driven by the AsyncAPI specification. Asynction guarantees that your API will work in accordance with its AsyncAPI documentation. Built on top of Flask-SocketIO.","links":{"websiteUrl":"https://pypi.org/project/asynction/","repoUrl":"https://github.com/dedoussis/asynction"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"technology":[{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"}],"categories":["framework"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"FastStream","description":"A powerful and easy-to-use Python framework for building asynchronous services interacting with event streams such as Apache Kafka, RabbitMQ and NATS.","links":{"websiteUrl":"https://faststream.airt.ai","repoUrl":"https://github.com/airtai/FastStream"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"categories":["code-first","framework"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Zod Sockets","description":"Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.","links":{"websiteUrl":"https://www.npmjs.com/package/zod-sockets","repoUrl":"https://github.com/RobinTail/zod-sockets"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","dsl","framework"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"GitHub Actions":{"description":"The following is a list of GitHub Actions that you can use in your workflows","toolsList":[{"title":"API documentation generation on Bump.sh","description":"With this GitHub Action you can automatically generate your API reference (with the changelog and diff) on Bump.sh from any AsyncAPI file.","links":{"websiteUrl":"https://github.com/marketplace/actions/api-documentation-on-bump","repoUrl":"https://github.com/bump-sh/github-action"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"categories":["github-action"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI GitHub Action","description":"This action validates if the AsyncAPI schema file is valid or not.","links":{"websiteUrl":"https://github.com/marketplace/actions/asyncapi-github-action","repoUrl":"https://github.com/WaleedAshraf/asyncapi-github-action"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["github-action","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Automated version bump for AsyncAPI documents","description":"With this GitHub Action, you can automatically bump the version based on commit messages, which is similar to what semantic-release is for NPM.","links":{"websiteUrl":"https://github.com/marketplace/actions/automated-version-bump-for-asyncapi","repoUrl":"https://github.com/bump-sh/github-action"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["github-action"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"GitHub Action for CLI","description":"GitHub Action with generator, validator, converter and others - all in one for your AsyncAPI documents with AsyncAPI CLI as backbone","links":{"repoUrl":"https://github.com/asyncapi/github-action-for-cli"},"filters":{"technology":[{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["github-action"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"GitHub Action for Generator","description":null,"links":{"repoUrl":"https://github.com/actions-marketplace-validations/asyncapi_github-action-for-generator"},"filters":{"technology":[{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["github-action"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"GitHub Action for Generator","description":"CLI to work with your AsyncAPI files. You can validate them and in the future use a generator and even bootstrap a new file. Contributions are welcomed!","links":{"repoUrl":"https://github.com/asyncapi/cli"},"filters":{"technology":[{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["github-actions"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"Mocking and Testing":{"description":"The tools below take specification documents as input, then publish fake messages to broker destinations for simulation purposes. They may also check that publisher messages are compliant with schemas.","toolsList":[{"title":"Microcks","description":"Mocking and testing platform for API and microservices. Turn your AsyncAPI, OpenAPI contract examples, or Postman collections into ready-to-use mocks. Use examples to simulate and validate received messages according to schema elements.","links":{"websiteUrl":"https://microcks.io/","repoUrl":"https://github.com/microcks/microcks"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Kubernetes-native","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Saas","color":"bg-[#6AB8EC]","borderColor":"border-[#2275AD]"}],"categories":["mocking-and-testing"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"MultiAPI Converter","description":"Use AsyncAPI definition, to generate Spring Cloud Contract producer validation or consumer stubs, using maven.","links":{"repoUrl":"https://github.com/sngular/scc-multiapi-converter"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"}],"categories":["mocking-and-testing"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Specmatic","description":"An API contract testing tool that helps ensure the correctness APIs by automatically generating test cases and verifying them against the API spec. It simplifies the process of testing APIs and reduces the likelihood of bugs and compatibility issues.","links":{"websiteUrl":"https://specmatic.io","docsUrl":"https://specmatic.io/documentation/","repoUrl":"https://github.com/znsio/specmatic"},"filters":{"language":[{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["mocking-and-testing"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Virtualan","description":"Mocking and testing platform for API and microservices. Allows you to create and setup mocks for OpenAPI and AsyncAPI contracts. Shows how to setup and create AsyncAPI GitHub Reference Examples and OpenAPI GitHub Reference Examples.","links":{"websiteUrl":"https://www.virtualan.io/index.html","repoUrl":"https://github.com/virtualansoftware"},"filters":{"technology":[{"name":"Kubernetes-native","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"}],"categories":["mocking-and-testing"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"ZenWave SDK","description":"DDD and API-First for Event-Driven Microservices","links":{"websiteUrl":"https://zenwave360.github.io/","docsUrl":"https://zenwave360.github.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/","repoUrl":"https://github.com/zenwave360/zenwave-sdk"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","dsl","mocking-and-testing","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Validators":{"description":"The following is a list of tools that validate AsyncAPI documents.","toolsList":[{"title":"AMF","description":"AMF (AML Modeling Framework) is an open-source library capable of parsing and validating AML metadata documents.","links":{"docsUrl":"https://a.ml/docs/","repoUrl":"https://github.com/aml-org/amf"},"filters":{"language":[{"name":"Scala","color":"bg-[#FFA299]","borderColor":"border-[#DF301F]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI GitHub Action","description":"This action validates if the AsyncAPI schema file is valid or not.","links":{"websiteUrl":"https://github.com/marketplace/actions/asyncapi-github-action","repoUrl":"https://github.com/WaleedAshraf/asyncapi-github-action"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["github-action","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI Parser","description":"Use this package to parse and validate AsyncAPI documents —either YAML or JSON— in your Node.js or browser application. Updated bundle for the browser is always attached to the GitHub Release.","links":{"repoUrl":"https://github.com/asyncapi/parser-js"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI Parser","description":"The AsyncAPI Parser validates AsyncAPI documents according to dedicated schemas.","links":{"repoUrl":"https://github.com/asyncapi/parser-go"},"filters":{"language":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":true,"technology":[]}},{"title":"AsyncAPI Parser Wrapper","description":"Use this library to parse and validate AsyncAPI documents — either YAML or JSON — in your Java application. It is a Java wrapper over JavaScript Parser implemented using J2V8.","links":{"repoUrl":"https://github.com/AsyncAPITools/parser-java-wrapper"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI Validation","description":"Message validation package for YAML and JSON AsyncAPI documents.","links":{"repoUrl":"https://github.com/Elhebert/asyncapi-validation"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"asyncapi-validator","description":"It allows you to validate the schema of your messages against your AsyncAPI schema definition. You can use it with Kafka, RabbitMQ or any other messaging/queue.","links":{"repoUrl":"https://github.com/WaleedAshraf/asyncapi-validator"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI.Net","description":"The AsyncAPI.NET SDK contains a useful object model for AsyncAPI documents in .NET along with common serializers to extract raw OpenAPI JSON and YAML documents from the model.","links":{"websiteUrl":"https://github.com/LEGO/AsyncAPI.NET/","repoUrl":"https://github.com/LEGO/AsyncAPI.NET"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["converters","code-first","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Spectral","description":"A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI v3.1, v3.0, and v2.0 as well as AsyncAPI v2.x.","links":{"repoUrl":"https://github.com/stoplightio/spectral"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Compare tools":{"description":"The following is a list of tools that compare AsyncAPI documents.","toolsList":[{"title":"Api-Smart-Diff","description":"It allows you to compare two API documents and classify changes. Supported API specifications: OpenAPI, AsyncAPI, JsonSchema.","links":{"repoUrl":"https://github.com/udamir/api-smart-diff"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"categories":["compare-tool"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI Diff","description":"Diff is a library that compares two AsyncAPI Documents and provides information about the differences by pointing out explicitly information like breaking changes.","links":{"repoUrl":"https://github.com/asyncapi/diff"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["compare-tool"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"jasyncapicmp","description":"Tool for comparing two AsyncAPI versions and evaluating compatibility.","links":{"websiteUrl":"https://siom79.github.io/jasyncapicmp/","docsUrl":"https://github.com/siom79/jasyncapicmp","repoUrl":"https://github.com/siom79/jasyncapicmp"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["compare-tool"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"jasyncapicmp","description":"Tool/library/maven-plugin for comparing two AsyncAPI versions and evaluating compatibility.","links":{"websiteUrl":"https://siom79.github.io/jasyncapicmp/","repoUrl":"https://github.com/siom79/jasyncapicmp"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["compare-tool"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"CLIs":{"description":"The following is a list of tools that you can work with in terminal or do some CI/CD automation.","toolsList":[{"title":"AsyncAPI CLI","description":"One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n","links":{"websiteUrl":"https://www.asyncapi.com/tools/cli","repoUrl":"https://github.com/asyncapi/cli"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["others","cli"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI CLI","description":"One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n","links":{"websiteUrl":"https://www.asyncapi.com/tools/cli","repoUrl":"https://github.com/hkirat/asyncapi-fork"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["others","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI-format","description":"Format an AsyncAPI document by ordering, casing, formatting, and filtering fields.","links":{"repoUrl":"https://github.com/asyncapi/converter-go"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["converter","cli"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"ZenWave SDK","description":"DDD and API-First for Event-Driven Microservices","links":{"websiteUrl":"https://zenwave360.github.io/","docsUrl":"https://zenwave360.github.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/","repoUrl":"https://github.com/zenwave360/zenwave-sdk"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","dsl","mocking-and-testing","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Bundlers":{"description":"The following is a list of tools that you can work with to bundle AsyncAPI documents.","toolsList":[{"title":"Api-ref-bundler","description":"It allows you bundle/dereference external/internal $refs in Json based API document. Supported specifications: OpenAPI, AsyncAPI, JsonSchema.","links":{"repoUrl":"https://github.com/udamir/api-ref-bundler"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["bundler"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI Bundler","description":"Combine multiple AsyncAPI specification files into one.","links":{"repoUrl":"https://github.com/asyncapi/bundler"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["bundler"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"IDE Extensions":{"description":"The following is a list of extensions for different IDEs like VSCode, IntelliJ IDEA and others","toolsList":[{"title":"asyncapi-preview","description":"VSCode extension that enables you to:\n - Preview documentation generated using you AsyncAPI document. It uses AsyncAPI React component under the hood,\n - Create AsyncAPI documents faster using SmartPaste functionality\n","links":{"repoUrl":"https://github.com/asyncapi/vs-asyncapi-preview"},"filters":{"technology":[{"name":"VSCode","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"SmartPaste","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ide-extension"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"asyncapi-preview","description":"VSCode extension that enables you to:\n - Preview documentation generated using you AsyncAPI document. It uses AsyncAPI React component under the hood,\n - Create AsyncAPI documents faster using SmartPaste functionality\n","links":{"repoUrl":"https://github.com/Savio629/testing2"},"filters":{"technology":[{"name":"VSCode","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"SmartPaste","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ide-extension"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"jAsyncAPI - IDEA plugin","description":"Idea plugin for the java-asyncapi - Helps to edit and validate AsyncAPI schemas.","links":{"websiteUrl":"https://plugins.jetbrains.com/plugin/15673-asyncapi","docsUrl":"https://github.com/asyncapi/jasyncapi-idea-plugin#usage","repoUrl":"https://github.com/asyncapi/jasyncapi-idea-plugin"},"filters":{"language":[{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"}],"technology":[{"name":"JetBrains","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"IntelliJ IDEA","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ide-extension"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"AsyncAPI Generator Templates":{"description":"The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents.","toolsList":[{"title":"HTML Template","description":"HTML template for AsyncAPI Generator. Use it to generate a static docs. It is using AsyncAPI React component under the hood.","links":{"repoUrl":"https://github.com/asyncapi/html-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"HTML","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Java Spring Cloud Stream Template","description":"Java Spring Cloud Stream template for the AsyncAPI Generator","links":{"repoUrl":"https://github.com/asyncapi/java-spring-cloud-stream-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Java Spring Template","description":"Java Spring template for the AsyncAPI Generator","links":{"repoUrl":"https://github.com/asyncapi/java-spring-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Java Template","description":"Java template for the AsyncAPI Generator","links":{"repoUrl":"https://github.com/asyncapi/java-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Java","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Node.js Multiprotocol Template","description":"This template generates a server using your AsyncAPI document. It supports multiple different protocols, like Kafka or MQTT. It is designed in the way that generated code is a library and with it's API you can start the server, send messages or register a middleware for listening incoming messages. Runtime message validation included.","links":{"repoUrl":"https://github.com/asyncapi/nodejs-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Node.js Websockets Template","description":"Node.js WebSockets template for the AsyncAPI Generator. It showcases how from a single AsyncAPI document you can generate a server and a client at the same time.","links":{"repoUrl":"https://github.com/asyncapi/nodejs-ws-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"Others":{"description":"The following is a list of tools that comes under Other category.","toolsList":[{"title":"AsyncAPI CLI","description":"One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n","links":{"websiteUrl":"https://www.asyncapi.com/tools/cli","repoUrl":"https://github.com/asyncapi/cli"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["others","cli"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI CLI","description":"One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n","links":{"websiteUrl":"https://www.asyncapi.com/tools/cli","repoUrl":"https://github.com/hkirat/asyncapi-fork"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["others","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}}]}} \ No newline at end of file +{"APIs":{"description":"The following is a list of APIs that expose functionality related to AsyncAPI.","toolsList":[{"title":"API Tracker - AsyncAPI specs","description":"Explore APIs and companies with public AsyncAPI specifications.","links":{"websiteUrl":"https://apitracker.io/specifications/asyncapi","repoUrl":""},"filters":{"categories":["api","directory"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI Server API","description":"Server API providing official AsyncAPI tools","links":{"websiteUrl":"https://api.asyncapi.com/v1","docsUrl":"https://api.asyncapi.com/v1/docs","repoUrl":"https://github.com/asyncapi/server-api"},"filters":{"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["api"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI-Directory by APIs.guru","description":"Directory of asynchronous API specifications in AsyncAPI format.","links":{"websiteUrl":"https://apis.guru/asyncapi-directory/","repoUrl":"https://github.com/APIs-guru/asyncapi-directory"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["api","directory"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"SIO-AsyncAPI","description":"This is code-first approach to generate AsyncAPI specification from Socket.IO server.","links":{"websiteUrl":"https://github.com/daler-rahimov/sio-asyncapi","docsUrl":"https://github.com/daler-rahimov/sio-asyncapi","repoUrl":"https://github.com/daler-rahimov/sio-asyncapi"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"technology":[{"name":"Socket.IO","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"}],"categories":["code-first","api"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Code-first tools":{"description":"The following is a list of tools that generate AsyncAPI documents from your code.","toolsList":[{"title":"AsyncAPI.Net","description":"The AsyncAPI.NET SDK contains a useful object model for AsyncAPI documents in .NET along with common serializers to extract raw OpenAPI JSON and YAML documents from the model.","links":{"websiteUrl":"https://github.com/LEGO/AsyncAPI.NET/","repoUrl":"https://github.com/LEGO/AsyncAPI.NET"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["converters","code-first","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncApi.Net.Generator","description":"Code-first AsyncAPI documentation generator and ui","links":{"repoUrl":"https://github.com/yurvon-screamo/asyncapi.net"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"EventBridge Atlas","description":"Tool that translates your AWS EventBridge Schemas into an AsyncAPI document and a web UI.","links":{"websiteUrl":"https://eventbridge-atlas.netlify.app/","repoUrl":"https://github.com/boyney123/eventbridge-atlas"},"filters":{"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"FastStream","description":"A powerful and easy-to-use Python framework for building asynchronous services interacting with event streams such as Apache Kafka, RabbitMQ and NATS.","links":{"websiteUrl":"https://faststream.airt.ai","repoUrl":"https://github.com/airtai/FastStream"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"categories":["code-first","framework"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Go AsyncAPI","description":"This library helps to create AsyncAPI spec from your Go message structures. It uses reflection to translate Go structures in JSON Schema definitions and arrange them in AsyncAPI schema.","links":{"repoUrl":"https://github.com/swaggest/go-asyncapi"},"filters":{"language":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Java AsyncAPI","description":"This tool stores modules, which simplifies interacting with AsyncAPI in jvm ecosystem.","links":{"repoUrl":"https://github.com/asyncapi/jasyncapi"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Kotlin","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"KnstEventBus","description":"AsyncApi code-first tools for c#. Generates document and view.","links":{"repoUrl":"https://github.com/d0972058277/KnstEventBus"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"},{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"}],"categories":["code-first","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Kotlin AsyncAPI","description":"The Kotlin AsyncAPI project aims to provide convenience tools for generating and serving AsyncAPI documentation. The core of this project is a Kotlin DSL for building the specification in a typesafe way.","links":{"repoUrl":"https://github.com/OpenFolder/kotlin-asyncapi"},"filters":{"language":[{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"nestjs-asyncapi","description":"Utilize decorators to generate AsyncAPI document utilizing DTOs (similar to @nestjs/swagger) and a web UI.","links":{"repoUrl":"https://github.com/flamewow/nestjs-asyncapi"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Nest Js","color":"bg-[#E1224E]","borderColor":"border-[#B9012b]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Neuroglia AsyncAPI","description":"A .NET SDK for the Async API specification. Automatically generates and serves AsyncAPI documents based on your code. Includes fluent-builders to create AsyncAPI documents from scratch, and provides a web-based GUI to browse generated documents.","links":{"repoUrl":"https://github.com/neuroglia-io/AsyncApi"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Saunter","description":"Saunter is an AsyncAPI documentation generator for dotnet. Generates (and hosts) an AsyncAPI schema document from your code.","links":{"repoUrl":"https://github.com/tehmantra/saunter"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"SIO-AsyncAPI","description":"This is code-first approach to generate AsyncAPI specification from Socket.IO server.","links":{"websiteUrl":"https://github.com/daler-rahimov/sio-asyncapi","docsUrl":"https://github.com/daler-rahimov/sio-asyncapi","repoUrl":"https://github.com/daler-rahimov/sio-asyncapi"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"technology":[{"name":"Socket.IO","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"}],"categories":["code-first","api"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Springwolf","description":"Automated documentation for async APIs built with Spring Boot. Like Springfox for AsyncAPI. Auto-generates an AsyncAPI document and a web UI.","links":{"websiteUrl":"https://www.springwolf.dev","repoUrl":"https://github.com/springwolf/springwolf-core"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"sttp tapir","description":"Library for describing HTTP endpoints, and then interpreting them as a server, client, or documentation","links":{"websiteUrl":"https://tapir.softwaremill.com/","repoUrl":"https://github.com/softwaremill/tapir"},"filters":{"language":[{"name":"Scala","color":"bg-[#FFA299]","borderColor":"border-[#DF301F]"}],"categories":["code-first"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Zod Sockets","description":"Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.","links":{"websiteUrl":"https://www.npmjs.com/package/zod-sockets","repoUrl":"https://github.com/RobinTail/zod-sockets"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","dsl","framework"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Code Generators":{"description":"The following is a list of tools that generate code from an AsyncAPI document; not the other way around.","toolsList":[{"title":"AsyncAPI Generator","description":"Generator is a tool that you can use to generate whatever you want basing on the AsyncAPI specification file as an input.","links":{"docsUrl":"https://www.asyncapi.com/docs/tools/generator","repoUrl":"https://github.com/asyncapi/generator"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["code-generator","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI Modelina","description":"Generate payload models into Java, TypeScript, Go, etc, you name it, from AsyncAPI documents. This tool gives you full control over the models through high customization","links":{"websiteUrl":"https://modelina.org","docsUrl":"https://github.com/asyncapi/modelina/tree/master/docs","repoUrl":"https://github.com/asyncapi/modelina"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":"Docker","color":"bg-[#B8E0FF]","borderColor":"border-[#2596ED]"}],"categories":["code-generator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Golang AsyncAPI Code Generator","description":"Generate Go user and application boilerplate from AsyncAPI specifications. Can be called from `go generate` without requirements.\n","links":{"repoUrl":"https://github.com/lerenn/asyncapi-codegen"},"filters":{"language":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"}],"categories":["code-generator"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"MultiAPI Generator","description":"This is a plugin designed to help developers automatizing the creation of code classes from YML files based on AsyncApi and OpenAPI. It is presented in 2 flavours Maven and Gradle","links":{"repoUrl":"https://github.com/sngular/scs-multiapi-plugin"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Groovy","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["code-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Node-RED AsyncAPI plugin","description":"A plugin for generating and configuring nodes for Kafka, MQTT, AMQP, etc. automatically from an AsyncAPI specification.","links":{"repoUrl":"https://github.com/dalelane/node-red-contrib-plugin-asyncapi"},"filters":{"technology":[{"name":"Node-RED","color":"bg-[#FF7474]","borderColor":"border-[#8F0101]"}],"categories":["code-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"ZenWave SDK","description":"DDD and API-First for Event-Driven Microservices","links":{"websiteUrl":"https://zenwave360.github.io/","docsUrl":"https://zenwave360.github.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/","repoUrl":"https://github.com/zenwave360/zenwave-sdk"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","dsl","mocking-and-testing","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Converters":{"description":"The following is a list of tools that do not yet belong to any specific category but are also useful for the community.","toolsList":[{"title":"AsyncAPI-format","description":"Format an AsyncAPI document by ordering, casing, formatting, and filtering fields.","links":{"repoUrl":"https://github.com/thim81/asyncapi-format"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["converter","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI.Net","description":"The AsyncAPI.NET SDK contains a useful object model for AsyncAPI documents in .NET along with common serializers to extract raw OpenAPI JSON and YAML documents from the model.","links":{"websiteUrl":"https://github.com/LEGO/AsyncAPI.NET/","repoUrl":"https://github.com/LEGO/AsyncAPI.NET"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["converters","code-first","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Converter","description":"Converts old versions of AsyncAPI files into the latest version.","links":{"repoUrl":"https://github.com/asyncapi/converter-js"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["converter"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Converter-Go","description":"The AsyncAPI Converter converts AsyncAPI documents from versions 1.0.0, 1.1.0 and 1.2.0 to version 2.0.0. It supports both json and yaml formats on input and output. By default, the AsyncAPI Converter converts a document into the json format.","links":{"repoUrl":"https://github.com/asyncapi/converter-go"},"filters":{"language":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"}],"categories":["converter"],"hasCommercial":false,"isAsyncAPIOwner":true,"technology":[]}}]},"Directories":{"description":"The following is a list of directories that index public AsyncAPI documents.","toolsList":[{"title":"API Tracker - AsyncAPI specs","description":"Explore APIs and companies with public AsyncAPI specifications.","links":{"websiteUrl":"https://apitracker.io/specifications/asyncapi","repoUrl":""},"filters":{"categories":["api","directory"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI-Directory by APIs.guru","description":"Directory of asynchronous API specifications in AsyncAPI format.","links":{"websiteUrl":"https://apis.guru/asyncapi-directory/","repoUrl":"https://github.com/APIs-guru/asyncapi-directory"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["api","directory"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Documentation Generators":{"description":"The following is a list of tools that generate human-readable documentation from an AsyncAPI document.","toolsList":[{"title":"AsyncAPI Generator","description":"Generator is a tool that you can use to generate whatever you want basing on the AsyncAPI specification file as an input.","links":{"docsUrl":"https://www.asyncapi.com/docs/tools/generator","repoUrl":"https://github.com/asyncapi/generator"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Markdown","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"asyncapi-asciidoc-template","description":"Asciidoc template for the asyncapi generator","links":{"repoUrl":"https://gitlab.com/djencks/asyncapi-asciidoc-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"}],"categories":["documentation-generator","generator-template"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Bump.sh","description":"OpenAPI 2 & 3 / AsyncAPI 2 documentation generator, with automatic changelog and visual diff.","links":{"websiteUrl":"https://bump.sh/","docsUrl":"https://docs.bump.sh/help/","repoUrl":""},"filters":{"categories":["documentation-generator"],"hasCommercial":true,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Cupid","description":"A library that focuses on finding and analyzing the relationships between AsyncAPI documents. It outputs a map of the system architecture.","links":{"repoUrl":"https://github.com/asyncapi/cupid"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"KnstEventBus","description":"AsyncApi code-first tools for c#. Generates document and view.","links":{"repoUrl":"https://github.com/d0972058277/KnstEventBus"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"},{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"}],"categories":["code-first","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Springwolf","description":"Automated documentation for async APIs built with Spring Boot. Like Springfox for AsyncAPI. Auto-generates an AsyncAPI document and a web UI.","links":{"websiteUrl":"https://www.springwolf.dev","repoUrl":"https://github.com/springwolf/springwolf-core"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Widdershins","description":"OpenAPI 3.0 / Swagger 2.0 / AsyncAPI 1.0 definition to Slate / Shins compatible markdown.","links":{"websiteUrl":"https://mermade.github.io/reslate/","repoUrl":"https://github.com/Mermade/widdershins"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Shell","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["documentation-generator"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Editors":{"description":"The following is a list of editors or related tools that allow editing of AsyncAPI document.","toolsList":[{"title":"AsyncAPI Studio","description":"Visually design your AsyncAPI files and event-driven architecture.","links":{"websiteUrl":"https://studio.asyncapi.com","repoUrl":"https://github.com/asyncapi/studio"},"filters":{"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["editor"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"UI components":{"description":"The following is a list of UI components to view AsyncAPI documents.","toolsList":[{"title":"Api-Diff-Viewer","description":"React component to view the difference between two Json based API documents. Supported specifications: JsonSchema, OpenAPI 3.x, AsyncAPI 2.x.","links":{"repoUrl":"https://github.com/udamir/api-diff-viewer","websiteUrl":"https://api-diff-viewer.vercel.app/"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":"Babel","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Storybook","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ui-component"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI React component","description":"React component for rendering documentation from your specification in real-time in the browser. It also provides a WebComponent and bundle for Angular and Vue","links":{"repoUrl":"https://github.com/asyncapi/asyncapi-react"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":"WebComponents","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ui-component"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"DSL":{"description":"Writing YAML by hand is no fun, and maybe you don't want a GUI, so use a Domain Specific Language to write AsyncAPI in your language of choice.","toolsList":[{"title":"BOATS","description":"Compile your single AsyncAPI file from multiple YAML files with BOATS and with the help of the template engine Nunjucks, plus a many extra helpers to automate much of the donkey work.","links":{"repoUrl":"https://github.com/j-d-carmichael/boats"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["dsl"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"ZenWave SDK","description":"DDD and API-First for Event-Driven Microservices","links":{"websiteUrl":"https://zenwave360.github.io/","docsUrl":"https://zenwave360.github.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/","repoUrl":"https://github.com/zenwave360/zenwave-sdk"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","dsl","mocking-and-testing","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Zod Sockets","description":"Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.","links":{"websiteUrl":"https://www.npmjs.com/package/zod-sockets","repoUrl":"https://github.com/RobinTail/zod-sockets"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","dsl","framework"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Frameworks":{"description":"The following is a list of API/application frameworks that make use of AsyncAPI.","toolsList":[{"title":"Asynction","description":"SocketIO server framework driven by the AsyncAPI specification. Asynction guarantees that your API will work in accordance with its AsyncAPI documentation. Built on top of Flask-SocketIO.","links":{"websiteUrl":"https://pypi.org/project/asynction/","repoUrl":"https://github.com/dedoussis/asynction"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"technology":[{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"}],"categories":["framework"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"FastStream","description":"A powerful and easy-to-use Python framework for building asynchronous services interacting with event streams such as Apache Kafka, RabbitMQ and NATS.","links":{"websiteUrl":"https://faststream.airt.ai","repoUrl":"https://github.com/airtai/FastStream"},"filters":{"language":[{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"}],"categories":["code-first","framework"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"Glee","description":"Glee — The AsyncAPI framework that will make you smile again :)","links":{"repoUrl":"https://github.com/asyncapi/glee"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["framework"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Zod Sockets","description":"Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.","links":{"websiteUrl":"https://www.npmjs.com/package/zod-sockets","repoUrl":"https://github.com/RobinTail/zod-sockets"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-first","dsl","framework"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"GitHub Actions":{"description":"The following is a list of GitHub Actions that you can use in your workflows","toolsList":[{"title":"API documentation generation on Bump.sh","description":"With this GitHub Action you can automatically generate your API reference (with the changelog and diff) on Bump.sh from any AsyncAPI file.","links":{"websiteUrl":"https://github.com/marketplace/actions/api-documentation-on-bump","repoUrl":"https://github.com/bump-sh/github-action"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"categories":["github-action"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI GitHub Action","description":"This action validates if the AsyncAPI schema file is valid or not.","links":{"websiteUrl":"https://github.com/marketplace/actions/asyncapi-github-action","repoUrl":"https://github.com/WaleedAshraf/asyncapi-github-action"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["github-action","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Automated version bump for AsyncAPI documents","description":"With this GitHub Action, you can automatically bump the version based on commit messages, which is similar to what semantic-release is for NPM.","links":{"websiteUrl":"https://github.com/marketplace/actions/automated-version-bump-for-asyncapi","repoUrl":"https://github.com/bump-sh/github-action"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["github-action"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"GitHub Action for CLI","description":"GitHub Action with generator, validator, converter and others - all in one for your AsyncAPI documents with AsyncAPI CLI as backbone","links":{"repoUrl":"https://github.com/asyncapi/github-action-for-cli"},"filters":{"technology":[{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["github-action"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"GitHub Action for Generator","description":null,"links":{"repoUrl":"https://github.com/actions-marketplace-validations/asyncapi_github-action-for-generator"},"filters":{"technology":[{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["github-action"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"GitHub Action for Generator","description":"CLI to work with your AsyncAPI files. You can validate them and in the future use a generator and even bootstrap a new file. Contributions are welcomed!","links":{"repoUrl":"https://github.com/asyncapi/cli"},"filters":{"technology":[{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["github-actions"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"Mocking and Testing":{"description":"The tools below take specification documents as input, then publish fake messages to broker destinations for simulation purposes. They may also check that publisher messages are compliant with schemas.","toolsList":[{"title":"Microcks","description":"Mocking and testing platform for API and microservices. Turn your AsyncAPI, OpenAPI contract examples, or Postman collections into ready-to-use mocks. Use examples to simulate and validate received messages according to schema elements.","links":{"websiteUrl":"https://microcks.io/","repoUrl":"https://github.com/microcks/microcks"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Kubernetes-native","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Saas","color":"bg-[#6AB8EC]","borderColor":"border-[#2275AD]"}],"categories":["mocking-and-testing"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"MultiAPI Converter","description":"Use AsyncAPI definition, to generate Spring Cloud Contract producer validation or consumer stubs, using maven.","links":{"repoUrl":"https://github.com/sngular/scc-multiapi-converter"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"}],"categories":["mocking-and-testing"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Specmatic","description":"An API contract testing tool that helps ensure the correctness APIs by automatically generating test cases and verifying them against the API spec. It simplifies the process of testing APIs and reduces the likelihood of bugs and compatibility issues.","links":{"websiteUrl":"https://specmatic.io","docsUrl":"https://specmatic.io/documentation/","repoUrl":"https://github.com/znsio/specmatic"},"filters":{"language":[{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["mocking-and-testing"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Virtualan","description":"Mocking and testing platform for API and microservices. Allows you to create and setup mocks for OpenAPI and AsyncAPI contracts. Shows how to setup and create AsyncAPI GitHub Reference Examples and OpenAPI GitHub Reference Examples.","links":{"websiteUrl":"https://www.virtualan.io/index.html","repoUrl":"https://github.com/virtualansoftware"},"filters":{"technology":[{"name":"Kubernetes-native","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"}],"categories":["mocking-and-testing"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"ZenWave SDK","description":"DDD and API-First for Event-Driven Microservices","links":{"websiteUrl":"https://zenwave360.github.io/","docsUrl":"https://zenwave360.github.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/","repoUrl":"https://github.com/zenwave360/zenwave-sdk"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","dsl","mocking-and-testing","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Validators":{"description":"The following is a list of tools that validate AsyncAPI documents.","toolsList":[{"title":"AMF","description":"AMF (AML Modeling Framework) is an open-source library capable of parsing and validating AML metadata documents.","links":{"docsUrl":"https://a.ml/docs/","repoUrl":"https://github.com/aml-org/amf"},"filters":{"language":[{"name":"Scala","color":"bg-[#FFA299]","borderColor":"border-[#DF301F]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI GitHub Action","description":"This action validates if the AsyncAPI schema file is valid or not.","links":{"websiteUrl":"https://github.com/marketplace/actions/asyncapi-github-action","repoUrl":"https://github.com/WaleedAshraf/asyncapi-github-action"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["github-action","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI Parser","description":"Use this package to parse and validate AsyncAPI documents —either YAML or JSON— in your Node.js or browser application. Updated bundle for the browser is always attached to the GitHub Release.","links":{"repoUrl":"https://github.com/asyncapi/parser-js"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI Parser","description":"The AsyncAPI Parser validates AsyncAPI documents according to dedicated schemas.","links":{"repoUrl":"https://github.com/asyncapi/parser-go"},"filters":{"language":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":true,"technology":[]}},{"title":"AsyncAPI Parser Wrapper","description":"Use this library to parse and validate AsyncAPI documents — either YAML or JSON — in your Java application. It is a Java wrapper over JavaScript Parser implemented using J2V8.","links":{"repoUrl":"https://github.com/AsyncAPITools/parser-java-wrapper"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI Validation","description":"Message validation package for YAML and JSON AsyncAPI documents.","links":{"repoUrl":"https://github.com/Elhebert/asyncapi-validation"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"asyncapi-validator","description":"It allows you to validate the schema of your messages against your AsyncAPI schema definition. You can use it with Kafka, RabbitMQ or any other messaging/queue.","links":{"repoUrl":"https://github.com/WaleedAshraf/asyncapi-validator"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI.Net","description":"The AsyncAPI.NET SDK contains a useful object model for AsyncAPI documents in .NET along with common serializers to extract raw OpenAPI JSON and YAML documents from the model.","links":{"websiteUrl":"https://github.com/LEGO/AsyncAPI.NET/","repoUrl":"https://github.com/LEGO/AsyncAPI.NET"},"filters":{"language":[{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"}],"technology":[{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"}],"categories":["converters","code-first","validator"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"Spectral","description":"A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI v3.1, v3.0, and v2.0 as well as AsyncAPI v2.x.","links":{"repoUrl":"https://github.com/stoplightio/spectral"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["validator"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Compare tools":{"description":"The following is a list of tools that compare AsyncAPI documents.","toolsList":[{"title":"Api-Smart-Diff","description":"It allows you to compare two API documents and classify changes. Supported API specifications: OpenAPI, AsyncAPI, JsonSchema.","links":{"repoUrl":"https://github.com/udamir/api-smart-diff"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"categories":["compare-tool"],"hasCommercial":false,"isAsyncAPIOwner":false,"technology":[]}},{"title":"AsyncAPI Diff","description":"Diff is a library that compares two AsyncAPI Documents and provides information about the differences by pointing out explicitly information like breaking changes.","links":{"repoUrl":"https://github.com/asyncapi/diff"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["compare-tool"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"jasyncapicmp","description":"Tool for comparing two AsyncAPI versions and evaluating compatibility.","links":{"websiteUrl":"https://siom79.github.io/jasyncapicmp/","docsUrl":"https://github.com/siom79/jasyncapicmp","repoUrl":"https://github.com/siom79/jasyncapicmp"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["compare-tool"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"jasyncapicmp","description":"Tool/library/maven-plugin for comparing two AsyncAPI versions and evaluating compatibility.","links":{"websiteUrl":"https://siom79.github.io/jasyncapicmp/","repoUrl":"https://github.com/siom79/jasyncapicmp"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["compare-tool"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"CLIs":{"description":"The following is a list of tools that you can work with in terminal or do some CI/CD automation.","toolsList":[{"title":"AsyncAPI CLI","description":"One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n","links":{"websiteUrl":"https://www.asyncapi.com/tools/cli","repoUrl":"https://github.com/asyncapi/cli"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["others","cli"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI CLI","description":"One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n","links":{"websiteUrl":"https://www.asyncapi.com/tools/cli","repoUrl":"https://github.com/hkirat/asyncapi-fork"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["others","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI-format","description":"Format an AsyncAPI document by ordering, casing, formatting, and filtering fields.","links":{"repoUrl":"https://github.com/asyncapi/converter-go"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["converter","cli"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"ZenWave SDK","description":"DDD and API-First for Event-Driven Microservices","links":{"websiteUrl":"https://zenwave360.github.io/","docsUrl":"https://zenwave360.github.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/","repoUrl":"https://github.com/zenwave360/zenwave-sdk"},"filters":{"language":[{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"}],"technology":[{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["code-generator","dsl","mocking-and-testing","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}}]},"Bundlers":{"description":"The following is a list of tools that you can work with to bundle AsyncAPI documents.","toolsList":[{"title":"Api-ref-bundler","description":"It allows you bundle/dereference external/internal $refs in Json based API document. Supported specifications: OpenAPI, AsyncAPI, JsonSchema.","links":{"repoUrl":"https://github.com/udamir/api-ref-bundler"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["bundler"],"hasCommercial":false,"isAsyncAPIOwner":false}},{"title":"AsyncAPI Bundler","description":"Combine multiple AsyncAPI specification files into one.","links":{"repoUrl":"https://github.com/asyncapi/bundler"},"filters":{"language":[{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"}],"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["bundler"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"IDE Extensions":{"description":"The following is a list of extensions for different IDEs like VSCode, IntelliJ IDEA and others","toolsList":[{"title":"asyncapi-preview","description":"VSCode extension that enables you to:\n - Preview documentation generated using you AsyncAPI document. It uses AsyncAPI React component under the hood,\n - Create AsyncAPI documents faster using SmartPaste functionality\n","links":{"repoUrl":"https://github.com/asyncapi/vs-asyncapi-preview"},"filters":{"technology":[{"name":"VSCode","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"SmartPaste","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ide-extension"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"jAsyncAPI - IDEA plugin","description":"Idea plugin for the java-asyncapi - Helps to edit and validate AsyncAPI schemas.","links":{"websiteUrl":"https://plugins.jetbrains.com/plugin/15673-asyncapi","docsUrl":"https://github.com/asyncapi/jasyncapi-idea-plugin#usage","repoUrl":"https://github.com/asyncapi/jasyncapi-idea-plugin"},"filters":{"language":[{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"}],"technology":[{"name":"JetBrains","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"IntelliJ IDEA","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["ide-extension"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"AsyncAPI Generator Templates":{"description":"The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents.","toolsList":[{"title":"HTML Template","description":"HTML template for AsyncAPI Generator. Use it to generate a static docs. It is using AsyncAPI React component under the hood.","links":{"repoUrl":"https://github.com/asyncapi/html-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"HTML","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Java Spring Cloud Stream Template","description":"Java Spring Cloud Stream template for the AsyncAPI Generator","links":{"repoUrl":"https://github.com/asyncapi/java-spring-cloud-stream-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Java Spring Template","description":"Java Spring template for the AsyncAPI Generator","links":{"repoUrl":"https://github.com/asyncapi/java-spring-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Java Template","description":"Java template for the AsyncAPI Generator","links":{"repoUrl":"https://github.com/asyncapi/java-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Java","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Node.js Multiprotocol Template","description":"This template generates a server using your AsyncAPI document. It supports multiple different protocols, like Kafka or MQTT. It is designed in the way that generated code is a library and with it's API you can start the server, send messages or register a middleware for listening incoming messages. Runtime message validation included.","links":{"repoUrl":"https://github.com/asyncapi/nodejs-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"Node.js Websockets Template","description":"Node.js WebSockets template for the AsyncAPI Generator. It showcases how from a single AsyncAPI document you can generate a server and a client at the same time.","links":{"repoUrl":"https://github.com/asyncapi/nodejs-ws-template"},"filters":{"language":[{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"}],"technology":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"}],"categories":["generator-template"],"hasCommercial":false,"isAsyncAPIOwner":true}}]},"Others":{"description":"The following is a list of tools that comes under Other category.","toolsList":[{"title":"AsyncAPI CLI","description":"One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n","links":{"websiteUrl":"https://www.asyncapi.com/tools/cli","repoUrl":"https://github.com/asyncapi/cli"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["others","cli"],"hasCommercial":false,"isAsyncAPIOwner":true}},{"title":"AsyncAPI CLI","description":"One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n","links":{"websiteUrl":"https://www.asyncapi.com/tools/cli","repoUrl":"https://github.com/hkirat/asyncapi-fork"},"filters":{"technology":[{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}],"categories":["others","cli"],"hasCommercial":false,"isAsyncAPIOwner":false}}]}} \ No newline at end of file From d7ee919f951be00c431cbcadab92ca4ba79b3c11 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Mon, 28 Oct 2024 15:46:11 +0100 Subject: [PATCH 23/91] docs(generator): update latest generator documentation (#3339) --- markdown/docs/tools/generator/asyncapi-document.md | 2 +- markdown/docs/tools/generator/hooks.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/markdown/docs/tools/generator/asyncapi-document.md b/markdown/docs/tools/generator/asyncapi-document.md index b6a3607b066..dfd2db6e854 100644 --- a/markdown/docs/tools/generator/asyncapi-document.md +++ b/markdown/docs/tools/generator/asyncapi-document.md @@ -41,7 +41,7 @@ graph LR The AsyncAPI document's content is accessible to you while writing your template in two distinct ways: - The `originalAsyncAPI`, which is a stringified version of the AsyncAPI document provided as input, without any modifications. -- The `asyncapi` (`AsyncAPIDocument`) which is an object with a set of helper functions, that comes as a result of the `Parser` manipulating the `originalAsyncAPI` .The `asyncapi` functions make it easier to access the contents of AsyncAPI documents in your templates. +- The `asyncapi` (`AsyncAPIDocument`) which is an object with a set of helper functions, that comes as a result of the `Parser` manipulating the `originalAyncAPI` .The `asyncapi` functions make it easier to access the contents of AsyncAPI documents in your templates. In the following sections, you will learn how to use either the **originalAsyncAPI** or the **asyncapi** in your template. diff --git a/markdown/docs/tools/generator/hooks.md b/markdown/docs/tools/generator/hooks.md index d2c06ddc0c4..cf1cb1dbc20 100644 --- a/markdown/docs/tools/generator/hooks.md +++ b/markdown/docs/tools/generator/hooks.md @@ -8,9 +8,9 @@ The following types of hooks are currently supported: |Hook type|Description| Return type | Arguments |---|---|---|---| -| `generate:before` | Called after registration of all filters and before the generator starts processing of the template. | void : Nothing is expected to be returned. | [The generator instance](https://github.com/asyncapi/generator/blob/master/docs/api.md) -| `generate:after` | Called at the very end of the generation. | void : Nothing is expected to be returned. | [The generator instance](https://github.com/asyncapi/generator/blob/master/docs/api.md) -| `setFileTemplateName ` | Called right before saving a new file generated by [file template](./file-templates.md). | string : a new filename for the generator to use for the file template. | [The generator instance](https://github.com/asyncapi/generator/blob/master/docs/api.md) and object in the form of `{ "originalFilename" : string }` +| `generate:before` | Called after registration of all filters and before the generator starts processing of the template. | void : Nothing is expected to be returned. | [The generator instance](/api) +| `generate:after` | Called at the very end of the generation. | void : Nothing is expected to be returned. | [The generator instance](/api) +| `setFileTemplateName ` | Called right before saving a new file generated by [file template](./file-templates.md). | string : a new filename for the generator to use for the file template. | [The generator instance](/api) and object in the form of `{ "originalFilename" : string }` The generator parses: - All the files in the `.hooks` directory inside the template. From 7753444299abdb99797fe6097a5683b0d6c13f2a Mon Sep 17 00:00:00 2001 From: Lukasz Gornicki Date: Mon, 28 Oct 2024 18:15:10 +0100 Subject: [PATCH 24/91] chore: add Adidas and Morgan Stanley to list of adopters (#3338) --- components/sponsors/SilverSponsorsList.ts | 2 +- config/adopters.yml | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/components/sponsors/SilverSponsorsList.ts b/components/sponsors/SilverSponsorsList.ts index 6c86f88eaa8..e49c6667d88 100644 --- a/components/sponsors/SilverSponsorsList.ts +++ b/components/sponsors/SilverSponsorsList.ts @@ -4,7 +4,7 @@ export const Silversponsors: SponsorType[] = [ { name: 'Bump.sh', website: 'https://bump.sh/asyncapi?utm_source=asyncapi&utm_medium=referral&utm_campaign=sponsor', - altText: 'Bump', + altText: 'OpenAPI & AsyncAPI API docs - Bump.sh', imageSrc: '/img/sponsors/bumpsh.svg', imageClass: 'inline-block sm:h-9' }, diff --git a/config/adopters.yml b/config/adopters.yml index 0ffaba4966c..456ac537a4f 100644 --- a/config/adopters.yml +++ b/config/adopters.yml @@ -80,4 +80,16 @@ useCase: Implementing a GitOps-based pipeline to enable self-service management of Kafka infrastructure, including access control management. Automation of AsyncAPI document governance ensures consistency in the infrastructure at the pull request level. resources: - title: "Slides: AsyncAPI For Platform Self-Service: A GitOps Tale" - link: https://drive.google.com/file/d/1y67PI8NaITPPwZAiDF2Zs7ISfcIpqMV8/view?usp=sharing \ No newline at end of file + link: https://drive.google.com/file/d/1y67PI8NaITPPwZAiDF2Zs7ISfcIpqMV8/view?usp=sharing + +- companyName: Adidas + useCase: AsyncAPI is a standard for defining asynchronous APIs using Apache Kafka. AsyncAPI governed under official guidelines. AsyncAPI is promoted to be used for documentation and code generation. + resources: + - title: "Docs: AsyncAPI and Kafka Guidelines" + link: https://adidas.gitbook.io/api-guidelines/asynchronous-api-guidelines/kafka-asynchronous-guidelines/a_introduction/why-asyncapi + +- companyName: Morgan Stanley + useCase: AsyncAPI is promoted not only inside the company but also as a standard for FinOS Foundation for managing architecture as code. + resources: + - title: "Slides: Deploying WebSockets with AsyncAPI and Architecture as Code" + link: https://drive.google.com/file/d/1YzLwQZsMUXGwj_Lsqv-ZnvV2knuowWrS/view?usp=drive_link From 85c9a356377b3bd044f1c78251ae850e3b286505 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Tue, 29 Oct 2024 01:41:36 +0100 Subject: [PATCH 25/91] chore: update meetings.json and newsrooom_videos.json (#3341) --- config/newsroom_videos.json | 12 ++++++------ dashboard.json | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/config/newsroom_videos.json b/config/newsroom_videos.json index 6a3893e2316..cf77baeb7b3 100644 --- a/config/newsroom_videos.json +++ b/config/newsroom_videos.json @@ -1,4 +1,10 @@ [ + { + "image_url": "https://i.ytimg.com/vi/Hy3-C6V2ir8/hqdefault.jpg", + "title": "AsyncAPI Conference Dry Run", + "description": "Setup and conference prep.", + "videoId": "Hy3-C6V2ir8" + }, { "image_url": "https://i.ytimg.com/vi/2WUchTKDPfs/hqdefault.jpg", "title": "Marketing WG Meeting, 14:00 UTC Tuesday October 22nd 2024", @@ -22,11 +28,5 @@ "title": "AsyncAPI Mentorship Program FAQ, 11:00 UTC Thursday October 10th 2024", "description": "https://github.com/asyncapi/community/issues/1550.", "videoId": "P1ZqaVBb6XM" - }, - { - "image_url": "https://i.ytimg.com/vi/4jaACa7geT0/hqdefault.jpg", - "title": "Design Onboarding Call, 10:00 UTC Thursday September 12th 2024", - "description": "https://github.com/asyncapi/community/issues/1372.", - "videoId": "4jaACa7geT0" } ] \ No newline at end of file diff --git a/dashboard.json b/dashboard.json index 2c675544b9a..8bd59dd608c 100644 --- a/dashboard.json +++ b/dashboard.json @@ -36,7 +36,7 @@ "resourcePath": "/asyncapi/website/pull/3101", "repo": "asyncapi/website", "labels": [], - "score": 19.240697446200336 + "score": 19.527872034949596 }, { "id": "PR_kwDOFLhIt85oVQqh", @@ -47,7 +47,7 @@ "resourcePath": "/asyncapi/community/pull/1082", "repo": "asyncapi/community", "labels": [], - "score": 18.37917367995256 + "score": 18.666348268701817 }, { "id": "I_kwDOGQYLdM5AX1lK", @@ -67,7 +67,7 @@ "color": "0E8A16" } ], - "score": 16.08177696995849 + "score": 16.36895155870775 }, { "id": "PR_kwDOFLhIt853IEwA", @@ -78,7 +78,7 @@ "resourcePath": "/asyncapi/community/pull/1333", "repo": "asyncapi/community", "labels": [], - "score": 15.220253203710714 + "score": 15.507427792459973 }, { "id": "I_kwDOFLhIt85bebeO", @@ -89,7 +89,7 @@ "resourcePath": "/asyncapi/community/issues/568", "repo": "asyncapi/community", "labels": [], - "score": 14.933078614961456 + "score": 15.220253203710714 }, { "id": "PR_kwDOCHlHJM54CmhW", @@ -129,6 +129,17 @@ ], "score": 12.922856493716644 }, + { + "id": "PR_kwDOBW5R_c59wJxU", + "isPR": true, + "isAssigned": false, + "title": "fix: css alignment of calendar component on the home page", + "author": "dishafaujdar", + "resourcePath": "/asyncapi/website/pull/3276", + "repo": "asyncapi/website", + "labels": [], + "score": 11.199808961221091 + }, { "id": "I_kwDODwv8N86BkfYV", "isPR": false, @@ -144,17 +155,6 @@ } ], "score": 10.912634372471834 - }, - { - "id": "PR_kwDOFLhIt85bqKL8", - "isPR": true, - "isAssigned": false, - "title": "docs: add Bounty Program Rules", - "author": "aeworxet", - "resourcePath": "/asyncapi/community/pull/897", - "repo": "asyncapi/community", - "labels": [], - "score": 10.657920261154981 } ], "goodFirstIssues": [ From cd837b4becbce3bbbb738064fe39113663f2ba7f Mon Sep 17 00:00:00 2001 From: Zeel Rajodiya Date: Tue, 29 Oct 2024 22:37:39 +0530 Subject: [PATCH 26/91] fix: wrong value of the enum in the tools-schema.json (#3283) --- scripts/tools/tools-schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tools/tools-schema.json b/scripts/tools/tools-schema.json index f8d848fcca1..e11968a1b2e 100644 --- a/scripts/tools/tools-schema.json +++ b/scripts/tools/tools-schema.json @@ -70,7 +70,7 @@ "Markdown", "YAML", "R", - "Rubby", + "Ruby", "Rust", "Shell", "Groovy" @@ -102,7 +102,7 @@ "Markdown", "YAML", "R", - "Rubby", + "Ruby", "Rust", "Shell", "Groovy" From baa5f90bd6fb302d9a1eb46c352cf0a50a4c7ba0 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Wed, 30 Oct 2024 01:40:59 +0100 Subject: [PATCH 27/91] chore: update meetings.json and newsrooom_videos.json (#3347) --- config/meetings.json | 7 ------- dashboard.json | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/config/meetings.json b/config/meetings.json index 06ad36dae20..428ed945506 100644 --- a/config/meetings.json +++ b/config/meetings.json @@ -90,13 +90,6 @@ "banner": "https://github.com/user-attachments/assets/91fca5af-ae9a-46be-aa44-0f2ef20ce34e", "date": "2024-10-15T08:00:00.000Z" }, - { - "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=amw3ZTBwZWllOTViYmMzMGFpNDhtdW9pZDggY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1546", - "banner": "https://github.com/user-attachments/assets/123ebfbe-6662-47ae-b36c-c2ba2e5d40f9", - "date": "2024-10-29T16:00:00.000Z" - }, { "title": "Let's talk about contributing Hacktoberfest Edition", "calLink": "https://www.google.com/calendar/event?eid=Zm9lMzRvM2F2MGljbWplZDJnNWYwczIwMzQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", diff --git a/dashboard.json b/dashboard.json index 8bd59dd608c..d4ecb4b72ce 100644 --- a/dashboard.json +++ b/dashboard.json @@ -67,7 +67,7 @@ "color": "0E8A16" } ], - "score": 16.36895155870775 + "score": 17.230475324955524 }, { "id": "PR_kwDOFLhIt853IEwA", From 35fed2fbeda0a6cac2a81d416eabd10e6ae0ed38 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Wed, 30 Oct 2024 10:20:58 +0100 Subject: [PATCH 28/91] docs(generator): update latest generator documentation (#3350) --- markdown/docs/tools/generator/api.md | 9 ++++ .../tools/generator/configuration-file.md | 5 ++- markdown/docs/tools/generator/hooks.md | 43 +++++++++++++++++-- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/markdown/docs/tools/generator/api.md b/markdown/docs/tools/generator/api.md index b59a87e33b0..42d7309e5fa 100644 --- a/markdown/docs/tools/generator/api.md +++ b/markdown/docs/tools/generator/api.md @@ -13,6 +13,7 @@ Reference API documentation for AsyncAPI Generator library. * [Generator](#Generator) * [new Generator(templateName, targetDir, options)](#new_Generator_new) * _instance_ + * [.compile](#Generator+compile) : `Boolean` * [.registry](#Generator+registry) : `Object` * [.templateName](#Generator+templateName) : `String` * [.targetDir](#Generator+targetDir) : `String` @@ -64,6 +65,7 @@ Instantiates a new Generator object. - [.forceWrite] `Boolean` ` = false` - Force writing of the generated files to given directory even if it is a git repo with unstaged files or not empty dir. Default is set to false. - [.install] `Boolean` ` = false` - Install the template and its dependencies, even when the template has already been installed. - [.debug] `Boolean` ` = false` - Enable more specific errors in the console. At the moment it only shows specific errors about filters. Keep in mind that as a result errors about template are less descriptive. + - [.compile] `Boolean` ` = true` - Whether to compile the template or use the cached transpiled version provided by template in '__transpiled' folder - [.mapBaseUrlToFolder] `Object.` - Optional parameter to map schema references from a base url to a local base folder e.g. url=https://schema.example.com/crm/ folder=./test/docs/ . - [.registry] `Object` - Optional parameter with private registry configuration - [.url] `String` - Parameter to pass npm registry url @@ -85,6 +87,13 @@ const generator = new Generator('@asyncapi/html-template', path.resolve(__dirnam }); ``` + + +* generator.compile : `Boolean`** : +Whether to compile the template or use the cached transpiled version provided by template in '__transpiled' folder. + +**Kind**: instance property of [`Generator`](#Generator) + * generator.registry : `Object`** : diff --git a/markdown/docs/tools/generator/configuration-file.md b/markdown/docs/tools/generator/configuration-file.md index c11cfd00e19..dda21e9830d 100644 --- a/markdown/docs/tools/generator/configuration-file.md +++ b/markdown/docs/tools/generator/configuration-file.md @@ -20,7 +20,7 @@ The `generator` property from `package.json` file must contain a JSON object tha |`nonRenderableFiles`| [String] | A list of file paths or [globs](https://en.wikipedia.org/wiki/Glob_(programming)) that must be copied "as-is" to the target directory, i.e., without performing any rendering process. This is useful when you want to copy binary files. |`generator`| [String] | A string representing the generator version-range the template is compatible with. This value must follow the [semver](https://nodejs.dev/learn/semantic-versioning-using-npm) syntax. E.g., `>=1.0.0`, `>=1.0.0 <=2.0.0`, `~1.0.0`, `^1.0.0`, `1.0.0`, etc. [Read more about semver](https://docs.npmjs.com/about-semantic-versioning). |`filters`| [String] | A list of modules containing functions that can be used as Nunjucks filters. In case of external modules, remember they need to be added as a dependency in `package.json` of your template. -|`hooks`| Object[String, String] or Object[String, Array[String]] | A list of modules containing hooks, except for the ones you keep locally in your template in default location. For each module you must specify the exact name of the hook that should be used in the template. For a single hook you can specify it as a string, for more you must pass an array of strings. In case of external modules, remember they need to be added as a dependency in `package.json` of your template. +|`hooks`| Object[String, String] or Object[String, Array[String]] | A list of modules containing hooks, except for the ones you keep locally in your template in the default location. For each module you must specify the exact name of the hook that should be used in the template. For a single hook, you can specify it as a string; for more hooks, you must pass an array of strings. In the case of external modules, remember they need to be added as a dependency in `package.json` of your template. There is also [an official hooks library](hooks#official-library) always included in the generator. As this is a library of multiple hooks, you still need to explicitly specify in the configuration which one you want to use. Use `@asyncapi/generator-hooks` as the library name. ### Example @@ -64,7 +64,8 @@ The `generator` property from `package.json` file must contain a JSON object tha "my-package-with-filters" ], "hooks": { - "@asyncapi/generator-hooks": "hookFunctionName" + "@asyncapi/generator-hooks": "hookFunctionName", + "my-custom-hooks-package": ["myHook", "andAnotherOne"] } } ``` diff --git a/markdown/docs/tools/generator/hooks.md b/markdown/docs/tools/generator/hooks.md index cf1cb1dbc20..422ff219130 100644 --- a/markdown/docs/tools/generator/hooks.md +++ b/markdown/docs/tools/generator/hooks.md @@ -4,6 +4,9 @@ weight: 130 --- Hooks are functions called by the generator on a specific moment in the generation process. Hooks can be anonymous functions but you can also add function names. These hooks can have arguments provided to them or being expected to return a value. + +## Types + The following types of hooks are currently supported: |Hook type|Description| Return type | Arguments @@ -12,13 +15,15 @@ The following types of hooks are currently supported: | `generate:after` | Called at the very end of the generation. | void : Nothing is expected to be returned. | [The generator instance](/api) | `setFileTemplateName ` | Called right before saving a new file generated by [file template](./file-templates.md). | string : a new filename for the generator to use for the file template. | [The generator instance](/api) and object in the form of `{ "originalFilename" : string }` +## Location + The generator parses: - All the files in the `.hooks` directory inside the template. -- All modules listed in the template configuration and triggers only hooks that names were added to the config. You can use the official AsyncAPI [hooks library](https://github.com/asyncapi/generator-hooks). To learn how to add hooks to configuration [read more about the configuration file](https://www.asyncapi.com/docs/tools/generator/configuration-file). +- All modules listed in the template configuration and triggers only hooks whose names were added to the config. You can use an [official hooks library](#official-library) that is bundled together with the generator. To learn how to add hooks to configuration [read more about the configuration file](configuration-file). -### Examples +## Examples -> Some of the examples have names of hook functions provided and some not. Keep in mind that hook functions kept in template in default location do not require a name. Name is required only if you keep hooks in non default location or in a separate library, because such hooks need to be explicitly configured in the configuration file. For more details on hooks configuration [read more about the configuration file](https://www.asyncapi.com/docs/tools/generator/configuration-file). +> Some of the examples have names of hook functions provided and some not. Keep in mind that hook functions kept in template in default location do not require a name. Name is required only if you keep hooks in non default location or in a separate library, because such hooks need to be explicitly configured in the configuration file. For more details on hooks configuration [read more about the configuration file](configuration-file). Most basic modules with hooks look like this: ```js @@ -79,3 +84,35 @@ module.exports = { }; }; ``` + +## Official library + +It is a library of reusable hooks that you can use in your templates. You only have to add its name to the configuration: `@asyncapi/generator-hooks` and specify which hook you want to enable. + +This library consists of the following hooks: +|Hook name|Hook type|Description| +|---|---|---| +| `createAsyncapiFile` | `generate:after` | It creates an AsyncAPI file with the content of the spec file passed to the generator. By default, it creates the file in the root of the generation output directory. This hook also supports custom parameters that the user can pass to template generation. The parameter called `asyncapiFileDir` allows the user to specify the location where the spec file should be created. To make your template users use this parameter, you need to add it to the configuration of your template like other parameters | + +1. In your template configuration in `package.json` specify you want to use this library and what hook exactly: + ```json + { + "generator": { + "hooks": { + "@asyncapi/generator-hooks": "createAsyncapiFile" + } + } + } + ``` +1. Some hooks support custom parameters that template's user can use to specify different behaviour of the hook. To enable these, you need to also add them to the list of your template's parameters: + ```json + { + "generator": { + "parameters": { + "asyncapiFileDir": { + "description": "This template by default also outputs the AsyncAPI document that was passed as input. You can specify with this parameter what should be the location of this AsyncAPI document, relative to specified template output." + } + } + } + } + ``` \ No newline at end of file From 2148afb41020842eddd62bed5ec6237544b432e2 Mon Sep 17 00:00:00 2001 From: Lukasz Gornicki Date: Wed, 30 Oct 2024 15:00:25 +0100 Subject: [PATCH 29/91] chore: add licence for docs (#3343) Co-authored-by: Akshat Nema <76521428+akshatnema@users.noreply.github.com> --- LICENSE-docs | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 9 ++ 2 files changed, 404 insertions(+) create mode 100644 LICENSE-docs diff --git a/LICENSE-docs b/LICENSE-docs new file mode 100644 index 00000000000..102013379aa --- /dev/null +++ b/LICENSE-docs @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. \ No newline at end of file diff --git a/README.md b/README.md index 2422bd1b2ae..5d6eab484fe 100644 --- a/README.md +++ b/README.md @@ -314,6 +314,15 @@ This repository has the following structure:

+## License + +This project's source code is licensed under the Apache License, Version 2.0. A copy of the +license is available in LICENSE file. + +This project's documentation is licensed under the Creative Commons Attribution +4.0 International License (CC-BY-4.0). A copy of the license is available in +LICENSE-docs. + ## AsyncAPI Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): From b1a5e143329410e1f08bedb717c81bf99dddad7e Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Thu, 31 Oct 2024 01:37:38 +0100 Subject: [PATCH 30/91] chore: update meetings.json and newsrooom_videos.json (#3352) --- config/newsroom_videos.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/newsroom_videos.json b/config/newsroom_videos.json index cf77baeb7b3..b44a007a437 100644 --- a/config/newsroom_videos.json +++ b/config/newsroom_videos.json @@ -1,4 +1,10 @@ [ + { + "image_url": "https://i.ytimg.com/vi/XGn8v0yBfOI/hqdefault.jpg", + "title": "AsyncAPI Online Conference 2024💜", + "description": "AsyncAPI Online Conference 2024 Welcome to the AsyncAPI Online Conference 2024 Edition.", + "videoId": "XGn8v0yBfOI" + }, { "image_url": "https://i.ytimg.com/vi/Hy3-C6V2ir8/hqdefault.jpg", "title": "AsyncAPI Conference Dry Run", @@ -22,11 +28,5 @@ "title": "Community Meeting, 8:00 UTC Tuesday October 15th 2024", "description": "https://github.com/asyncapi/community/issues/1545.", "videoId": "maMQC97q_6E" - }, - { - "image_url": "https://i.ytimg.com/vi/P1ZqaVBb6XM/hqdefault.jpg", - "title": "AsyncAPI Mentorship Program FAQ, 11:00 UTC Thursday October 10th 2024", - "description": "https://github.com/asyncapi/community/issues/1550.", - "videoId": "P1ZqaVBb6XM" } ] \ No newline at end of file From 983c80e1d11aefba8d99e25ae9da0419b3b478e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 03:18:23 +0100 Subject: [PATCH 31/91] chore(deps-dev): bump elliptic from 6.5.7 to 6.6.0 (#3353) --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3e06c5cffdb..837177c7acf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12002,9 +12002,9 @@ "integrity": "sha512-OvpTT2ItpOXJL7IGcYakRjHCt8L5GrrN/wHCQsRB4PQa1X9fe+X9oen245mIId7s14xvArCGSTIq644yPUKKLg==" }, "node_modules/elliptic": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", - "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", + "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", "dev": true, "dependencies": { "bn.js": "^4.11.9", From 1f974ecd14db90941667e259afb18a301ebce68d Mon Sep 17 00:00:00 2001 From: Manikanta Mandala <77623256+ManikantaMandala@users.noreply.github.com> Date: Fri, 1 Nov 2024 13:54:58 +0530 Subject: [PATCH 32/91] fix: inconsistent padding in the accordion in responsive conditions (#3280) Co-authored-by: Ansh Goyal %0ACo-authored-by: asyncapi-bot --- components/navigation/MenuBlocks.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/navigation/MenuBlocks.tsx b/components/navigation/MenuBlocks.tsx index 81548f97ec0..b13543685bf 100644 --- a/components/navigation/MenuBlocks.tsx +++ b/components/navigation/MenuBlocks.tsx @@ -42,7 +42,7 @@ export default function MenuBlocks({ items = [] }: MenuBlocksProps) { > From 29c76f7796ebb2ea85daabda8f5a92ffbbaabf97 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Fri, 1 Nov 2024 09:34:41 +0100 Subject: [PATCH 33/91] chore: update meetings.json and newsrooom_videos.json (#3355) Co-authored-by: asyncapi-bot-eve %0ACo-authored-by: asyncapi-bot --- config/meetings.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/config/meetings.json b/config/meetings.json index 428ed945506..9a21a9d36ff 100644 --- a/config/meetings.json +++ b/config/meetings.json @@ -1,11 +1,4 @@ [ - { - "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=am5kcG50YW9obGUzcmVucWZqMTQ4NDlsbjQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1305", - "banner": "https://github.com/asyncapi/community/assets/40604284/65376079-c5e8-467d-b513-21dfaba4570f", - "date": "2024-07-23T16:00:00.000Z" - }, { "title": "Marketing WG Meeting", "calLink": "https://www.google.com/calendar/event?eid=b2twOWkyZ3ExcGxnYnAxbzBobzA1MWxvcW8gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", From 2e33ac3111f0a60e43ebf22045a8eaca8cedc7e0 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Fri, 1 Nov 2024 10:17:30 +0100 Subject: [PATCH 34/91] docs(generator): update latest generator documentation (#3349) Co-authored-by: asyncapi-bot-eve %0ACo-authored-by: asyncapi-bot From 551c47ae0d390395cb0dcfc6779fd03ea65f6bea Mon Sep 17 00:00:00 2001 From: tanmay kumar chaurasia <130184741+TanmayChaurasia24@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:52:26 +0530 Subject: [PATCH 35/91] docs: broken link to Generator Github Actions(#3190) (#3299) Co-authored-by: tanmay Co-authored-by: Akshat Nema <76521428+akshatnema@users.noreply.github.com> --- markdown/docs/tools/generator/installation-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markdown/docs/tools/generator/installation-guide.md b/markdown/docs/tools/generator/installation-guide.md index 302be049751..958d1c5a92d 100644 --- a/markdown/docs/tools/generator/installation-guide.md +++ b/markdown/docs/tools/generator/installation-guide.md @@ -73,7 +73,7 @@ To uninstall the generator, use the following command: npm uninstall @asyncapi/cli -g ``` -> :memo: **Note:** To use the generator in your CI/CD pipeline to automate whatever you generate for your event-driven architecture apps, install the AsyncAPI CLI in your pipeline. If you are using GitHub Actions, use [Github Actions for Generator](https://github.com/marketplace/actions/generator-for-asyncapi-documents). +> :memo: **Note:** To use the generator in your CI/CD pipeline to automate whatever you generate for your event-driven architecture apps, install the AsyncAPI CLI in your pipeline. If you are using GitHub Actions, use [Github Actions for Generator](https://github.com/marketplace/actions/generator-validator-converter-and-others-all-in-one-for-your-asyncapi-docs). ## Generator library in Node.js apps Use the generator library in your Node.js projects by installing it via the following command: `npm install @asyncapi/generator`. From 33ce665ed8fdd4eb329f495ba6fc0a649a7fb585 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Sun, 3 Nov 2024 01:39:34 +0100 Subject: [PATCH 36/91] chore: update meetings.json and newsrooom_videos.json (#3360) --- config/newsroom_videos.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/newsroom_videos.json b/config/newsroom_videos.json index b44a007a437..486ce2a52da 100644 --- a/config/newsroom_videos.json +++ b/config/newsroom_videos.json @@ -1,4 +1,10 @@ [ + { + "image_url": "https://i.ytimg.com/vi/22LFOLeF9Lk/hqdefault.jpg", + "title": "AsyncAPI + WebSocket: The Collaborative Combo", + "description": "Build a real-time collaborative drawing app from scratch using WebSocket & AsyncAPI, where users can draw together and chat in ...", + "videoId": "22LFOLeF9Lk" + }, { "image_url": "https://i.ytimg.com/vi/XGn8v0yBfOI/hqdefault.jpg", "title": "AsyncAPI Online Conference 2024💜", @@ -22,11 +28,5 @@ "title": "Design Meeting, 12:00 UTC Thursday October 17th 2024", "description": "https://github.com/asyncapi/community/issues/1558.", "videoId": "FzRxTpOeIDA" - }, - { - "image_url": "https://i.ytimg.com/vi/maMQC97q_6E/hqdefault.jpg", - "title": "Community Meeting, 8:00 UTC Tuesday October 15th 2024", - "description": "https://github.com/asyncapi/community/issues/1545.", - "videoId": "maMQC97q_6E" } ] \ No newline at end of file From 5ea47bb3e786a509dcac0f1c7f3804469a791b0a Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Sun, 3 Nov 2024 11:10:59 +0100 Subject: [PATCH 37/91] docs(community): update latest maintainers list (#3361) --- config/MAINTAINERS.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/MAINTAINERS.json b/config/MAINTAINERS.json index d5914331c17..60932854b74 100644 --- a/config/MAINTAINERS.json +++ b/config/MAINTAINERS.json @@ -158,7 +158,7 @@ "html-template", "markdown-template", "nodejs-ws-template", - "generator-hooks", + "glee", "brand" ], "githubID": 242119 @@ -269,7 +269,6 @@ "github-action-for-cli", ".github", "jasyncapi", - "generator-hooks", "vs-asyncapi-preview", "template-for-generator-templates", "community", From dfd08dd72953642c3a02f81098a7125ce52904f5 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Wed, 6 Nov 2024 01:36:16 +0100 Subject: [PATCH 38/91] chore: update meetings.json and newsrooom_videos.json (#3364) --- config/newsroom_videos.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/newsroom_videos.json b/config/newsroom_videos.json index 486ce2a52da..2f999644269 100644 --- a/config/newsroom_videos.json +++ b/config/newsroom_videos.json @@ -1,4 +1,10 @@ [ + { + "image_url": "https://i.ytimg.com/vi/wiM20HTCerM/hqdefault.jpg", + "title": "Using API spec as an Executable Contract To Mock and Test Mic - Hari Krishnanroservices", + "description": "AsyncAPI allows us to articulate communication channels between services clearly. What if I told you that this AsyncAPI ...", + "videoId": "wiM20HTCerM" + }, { "image_url": "https://i.ytimg.com/vi/22LFOLeF9Lk/hqdefault.jpg", "title": "AsyncAPI + WebSocket: The Collaborative Combo", @@ -22,11 +28,5 @@ "title": "Marketing WG Meeting, 14:00 UTC Tuesday October 22nd 2024", "description": "https://github.com/asyncapi/community/issues/1553.", "videoId": "2WUchTKDPfs" - }, - { - "image_url": "https://i.ytimg.com/vi/FzRxTpOeIDA/hqdefault.jpg", - "title": "Design Meeting, 12:00 UTC Thursday October 17th 2024", - "description": "https://github.com/asyncapi/community/issues/1558.", - "videoId": "FzRxTpOeIDA" } ] \ No newline at end of file From 68a1ee6d5b712c3a8bc112750474adec45f353de Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Wed, 6 Nov 2024 14:34:37 +0100 Subject: [PATCH 39/91] docs(cli): update latest cli documentation (#3366) --- markdown/docs/tools/cli/usage.md | 52 ++++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/markdown/docs/tools/cli/usage.md b/markdown/docs/tools/cli/usage.md index 98ccd5e79dd..d10e249f190 100644 --- a/markdown/docs/tools/cli/usage.md +++ b/markdown/docs/tools/cli/usage.md @@ -27,7 +27,7 @@ $ npm install -g @asyncapi/cli $ asyncapi COMMAND running command... $ asyncapi (--version) -@asyncapi/cli/2.7.4 linux-x64 node-v18.20.4 +@asyncapi/cli/2.8.0 linux-x64 node-v18.20.4 $ asyncapi --help [COMMAND] USAGE $ asyncapi COMMAND @@ -99,7 +99,7 @@ EXAMPLES $ asyncapi bundle ./asyncapi.yaml -o final-asyncapi.yaml --base ../public-api/main.yaml --baseDir ./social-media/comments-service ``` -_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/bundle.ts)_ +_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/bundle.ts)_ ## `asyncapi config` @@ -113,7 +113,7 @@ DESCRIPTION CLI config settings ``` -_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/index.ts)_ +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/index.ts)_ ## `asyncapi config analytics` @@ -133,7 +133,7 @@ DESCRIPTION Enable or disable analytics for metrics collection ``` -_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/analytics.ts)_ +_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/analytics.ts)_ ## `asyncapi config context` @@ -147,7 +147,7 @@ DESCRIPTION Manage short aliases for full paths to AsyncAPI documents ``` -_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/index.ts)_ +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/index.ts)_ ## `asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH` @@ -169,7 +169,7 @@ DESCRIPTION Add a context to the store ``` -_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/add.ts)_ +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/add.ts)_ ## `asyncapi config context current` @@ -186,7 +186,7 @@ DESCRIPTION Shows the current context that is being used ``` -_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/current.ts)_ +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/current.ts)_ ## `asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` @@ -207,7 +207,7 @@ DESCRIPTION Edit a context in the store ``` -_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/edit.ts)_ +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/edit.ts)_ ## `asyncapi config context init [CONTEXT-FILE-PATH]` @@ -230,7 +230,7 @@ DESCRIPTION Initialize context ``` -_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/init.ts)_ +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/init.ts)_ ## `asyncapi config context list` @@ -247,7 +247,7 @@ DESCRIPTION List all the stored contexts in the store ``` -_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/list.ts)_ +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/list.ts)_ ## `asyncapi config context remove CONTEXT-NAME` @@ -267,7 +267,7 @@ DESCRIPTION Delete a context from the store ``` -_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/remove.ts)_ +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/remove.ts)_ ## `asyncapi config context use CONTEXT-NAME` @@ -287,7 +287,7 @@ DESCRIPTION Set a context as current ``` -_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/context/use.ts)_ +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/use.ts)_ ## `asyncapi config versions` @@ -304,7 +304,7 @@ DESCRIPTION Show versions of AsyncAPI tools used ``` -_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/config/versions.ts)_ +_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/versions.ts)_ ## `asyncapi convert [SPEC-FILE]` @@ -332,7 +332,7 @@ DESCRIPTION Convert asyncapi documents older to newer versions or OpenAPI/postman-collection documents to AsyncAPI ``` -_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/convert.ts)_ +_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/convert.ts)_ ## `asyncapi diff OLD NEW` @@ -372,7 +372,7 @@ DESCRIPTION Find diff between two asyncapi files ``` -_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/diff.ts)_ +_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/diff.ts)_ ## `asyncapi generate` @@ -386,7 +386,7 @@ DESCRIPTION Generate typed models or other things like clients, applications or docs using AsyncAPI Generator templates. ``` -_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/generate/index.ts)_ +_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/generate/index.ts)_ ## `asyncapi generate fromTemplate ASYNCAPI TEMPLATE` @@ -431,7 +431,7 @@ EXAMPLES $ asyncapi generate fromTemplate asyncapi.yaml @asyncapi/html-template --param version=1.0.0 singleFile=true --output ./docs --force-write ``` -_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/generate/fromTemplate.ts)_ +_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/generate/fromTemplate.ts)_ ## `asyncapi generate models LANGUAGE FILE` @@ -502,7 +502,7 @@ DESCRIPTION Generates typed models ``` -_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/generate/models.ts)_ +_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/generate/models.ts)_ ## `asyncapi new` @@ -560,7 +560,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/new/index.ts)_ +_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/new/index.ts)_ ## `asyncapi new file` @@ -618,7 +618,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/new/file.ts)_ +_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/new/file.ts)_ ## `asyncapi new glee` @@ -640,7 +640,7 @@ DESCRIPTION Creates a new Glee project ``` -_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/new/glee.ts)_ +_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/new/glee.ts)_ ## `asyncapi new template` @@ -664,7 +664,7 @@ DESCRIPTION Creates a new template ``` -_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/new/template.ts)_ +_See code: [src/commands/new/template.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/new/template.ts)_ ## `asyncapi optimize [SPEC-FILE]` @@ -706,7 +706,7 @@ EXAMPLES $ asyncapi optimize ./asyncapi.yaml --ignore=schema ``` -_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/optimize.ts)_ +_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/optimize.ts)_ ## `asyncapi start` @@ -720,7 +720,7 @@ DESCRIPTION Starts AsyncAPI-related services. Currently, it supports launching the AsyncAPI Studio ``` -_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/start/index.ts)_ +_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/start/index.ts)_ ## `asyncapi start studio` @@ -739,7 +739,7 @@ DESCRIPTION starts a new local instance of Studio ``` -_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/start/studio.ts)_ +_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/start/studio.ts)_ ## `asyncapi validate [SPEC-FILE]` @@ -769,5 +769,5 @@ DESCRIPTION validate asyncapi file ``` -_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.7.4/src/commands/validate.ts)_ +_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/validate.ts)_ From 2fb1634e978c88f6b1cab907d0083a8f1e6dae5a Mon Sep 17 00:00:00 2001 From: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:49:01 +0200 Subject: [PATCH 40/91] chore(blog): add october summary (#3362) Co-authored-by: Quetzalli --- markdown/blog/2024-october-summary.md | 155 ++++++++++++++++++ .../blog/2024-september-summary-and-london.md | 1 - markdown/blog/asyncapi-bounty-program-2024.md | 1 - markdown/blog/helsinki-and-community.md | 1 - .../2024-blog-banner/blog-banner-october.webp | Bin 0 -> 135028 bytes .../img/posts/2024-blog-banner/mascots.webp | Bin 0 -> 29518 bytes 6 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 markdown/blog/2024-october-summary.md create mode 100644 public/img/posts/2024-blog-banner/blog-banner-october.webp create mode 100644 public/img/posts/2024-blog-banner/mascots.webp diff --git a/markdown/blog/2024-october-summary.md b/markdown/blog/2024-october-summary.md new file mode 100644 index 00000000000..88d9e7b9e36 --- /dev/null +++ b/markdown/blog/2024-october-summary.md @@ -0,0 +1,155 @@ +--- +title: "October Community Update And AsyncAPI Online Conference 2024" +date: 2024-11-07T06:00:00+01:00 +type: Communication +tags: + - Project Status +cover: /img/posts/2024-blog-banner/blog-banner-october.webp +authors: + - name: Thulisile Sibanda + photo: /img/avatars/thulieblack.webp + link: https://www.linkedin.com/in/v-thulisile-sibanda/ + byline: AsyncAPI Community Manager +excerpt: 'October Community Update And Online Conference Summary' +featured: true +--- + +October marked the third AsyncAPI Conference, this time an online edition. As someone fortunate enough to be extensively involved in organizing the conferences, I saw the challenges that came with in-person events. +It gave me the idea to propose bringing back the online edition as part of the AsyncAPI Conference brand. We're glad and excited that we received positive results, with over **360 views** from attendees who watched and engaged with us. + +I want to express my gratitude to our financial sponsors, [Gravitee.io](https://www.gravitee.io/) and [Postman](https://www.postman.com/), as well as to the speakers for their engaging talks and the conference volunteers (*be sure to check out the [Hall of Fame](#asyncapi-conference-hall-of-fame) section*). [I encourage you to watch the recorded sessions if you missed the event](https://www.youtube.com/watch?v=XGn8v0yBfOI&t=1895s). A playlist of the individual talks and slides will also be available on the [conference website](https://conference.asyncapi.com/). + + +## AsyncAPI Community Building and Maintenance Goals Proposal 2025 +As we approach the end of 2024, we have a proposal outlining the community building and maintenance goals we should prioritize in 2025. Please note that the AsyncAPI community manager will manage and oversee these goals. The goals are poised to address some of the challenges our community is facing, such as the limited number of maintainers and the lack of onboarding materials, and pave the way for a more vibrant and thriving community. + +I encourage everyone to participate in the open discussion and share your thoughts and solutions. [Please take a moment to review the open PR related to the AsyncAPI Community Building Goals for 2025](https://github.com/asyncapi/community/pull/1575). + +## AsyncAPI Conferences + +### AsyncAPI Conf in Paris 2024 +We are excited to announce that the final AsyncAPI Conference will be held on December 5th in Paris, thanks to the amazing team at APIdays. [The draft agenda is now available on our conference website](https://conference.asyncapi.com/venue/Paris), and the lineup of speakers looks fantastic. + +Additionally, we have a limited number of free community tickets available. To register, please visit the [AsyncAPI Conference website](https://conference.asyncapi.com/). + +**Note**: *When getting your tickets, please choose quantity one (1) of the Regular ticket and click the blue continue button to get your free ticket.* + +### AsyncAPI Conf 2025 Venues +The discussion for potential venues for the AsyncAPI Conference 2025 is underway, and we invite everyone to participate. Please share your thoughts and suggestions for locations for the upcoming year in the [AsyncAPI Conference 2025 open discussion](https://github.com/asyncapi/community/issues/1571). Your input is valuable to us! + +### AsyncAPI Conference Rebranding +In 2023, we successfully launched the AsyncAPI Conf on Tour (AACoT). We followed our vision to host events in various locations, allowing us to connect with the community in multiple cities. As we expand our reach and grow as a brand, we believe it is necessary to drop "on Tour" and simply refer to our events as the AsyncAPI Conf/Conference moving forward. +Although we are simplifying the name, we remain committed to hosting conferences worldwide and enhancing our conference brand's visibility. [We welcome your thoughts on this rebranding in the AsyncAPI Conf rebranding discussion](https://github.com/orgs/asyncapi/discussions/1578). + +### AsyncAPI at FOSDEM 2025 + +Are you attending FOSDEM and interested in speaking? AsyncAPI will participate in the FOSDEM conference as part of the `APIs: GraphQL, OpenAPI, AsyncAPI, and Friends` track. +[The Call for Participation is now open](https://pretalx.fosdem.org/fosdem-2025/cfp), and we encourage everyone in the community to apply. Deadline for talk submissions is December 15, 2024. This is another great opportunity to meet fellow community members! + +## Should AsyncAPI Initiative Endorse The United Nations Global Digital Compact? +The United Nations General Assembly has approved the Global Digital Compact, a commitment to ensure digital technologies support sustainable development and human rights. +AsyncAPI is one of the key standards for event-driven architectures, and our Executive Director, [Lukasz Gornicki](https://www.linkedin.com/in/lukasz-gornicki-a621914), [has called for a vote](https://github.com/asyncapi/community/issues/1577) to determine whether we, as the AsyncAPI Initiative, should endorse the Compact which aligns with our values of open-source software and collaboration. [We encourage all community members to participate in the vote and share their thoughts on this important decision](https://github.com/asyncapi/community/issues/1577). + +## Spec x Tooling +We're thrilled to announce that Glee has been migrated to a monorepo structure and is moving its core functionality to a new package called Gleequore, inspired by the Italian word "cuore," which means "heart." +This change will allow developers to leverage Glee's features without using the full framework, facilitating integration with platforms like Remix and Next.js. +We're also working on creating a "Glee for the browser" by extracting protocol adapters to support HTTP and WebSocket clients, overcoming current limitations. Kudos to [Fran Mendez](https://www.linkedin.com/in/fmvilas) and all the Glee maintainers for their amazing work! + +[The packages are now available on the Glee repo](https://github.com/asyncapi/glee/tree/master/packages); be sure to try it out. + +## AsyncAPI Mascot Brand Refresh + +As part of the AsyncAPI Bounty Program, we have a task to rebrand the Eve and Chan mascots. The designs look amazing so far! + +
+ +[Please join the discussion and share your thoughts on the progress made on the brand refresh mascot issue](https://github.com/asyncapi/brand/issues/12). + +## AsyncAPI Conference Hall of Fame +I want to extend a heartfelt thank you to the incredible volunteers who generously dedicated their skills and time to ensure the success of the Online Conference. From developers and designers to those working both on-stage and off-stage, their efforts made the planning and execution of the event seamless. + + + +## Coming in November +- **AsyncAPI Community Updates Newsletter** - The November Edition issue will arrive in your inbox on the 8th. [Ensure you subscribe to the AsyncAPI Newsletter](https://www.asyncapi.com/newsletter); you don't want to miss out. diff --git a/markdown/blog/2024-september-summary-and-london.md b/markdown/blog/2024-september-summary-and-london.md index cbac4f5563e..0e965cefe35 100644 --- a/markdown/blog/2024-september-summary-and-london.md +++ b/markdown/blog/2024-september-summary-and-london.md @@ -11,7 +11,6 @@ authors: link: https://www.linkedin.com/in/v-thulisile-sibanda/ byline: AsyncAPI Community Manager excerpt: 'September Community Update and London Conference Highlights' -featured: true --- In September, we had our second in-person AsyncAPI conference after Helsinki; read all about it in the [AsyncAPI Helsinki Conference update](https://www.asyncapi.com/blog/helsinki-and-community). diff --git a/markdown/blog/asyncapi-bounty-program-2024.md b/markdown/blog/asyncapi-bounty-program-2024.md index bc409d28581..bcfb5183d5d 100644 --- a/markdown/blog/asyncapi-bounty-program-2024.md +++ b/markdown/blog/asyncapi-bounty-program-2024.md @@ -11,7 +11,6 @@ authors: link: https://github.com/aeworxet byline: Bounty Program Coordinator excerpt: 'Annual update on the quarterly published set of tasks that are currently in demand among AsyncAPI Maintainers, targeted at engineers of Middle and Senior professional levels.' -featured: true --- ## AsyncAPI Bounty Program diff --git a/markdown/blog/helsinki-and-community.md b/markdown/blog/helsinki-and-community.md index ffb47a8f82a..5f1dae23225 100644 --- a/markdown/blog/helsinki-and-community.md +++ b/markdown/blog/helsinki-and-community.md @@ -11,7 +11,6 @@ authors: link: https://twitter.com/derberq byline: AsyncAPI Executive Director excerpt: 'Conferences are great. They bring communities together and give people a platform to share their experiences. But is that enough?' -featured: true --- ## How It All Started diff --git a/public/img/posts/2024-blog-banner/blog-banner-october.webp b/public/img/posts/2024-blog-banner/blog-banner-october.webp new file mode 100644 index 0000000000000000000000000000000000000000..6fa9652162b81eddb8360adb7576a20b1a7108bc GIT binary patch literal 135028 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 literal 0 HcmV?d00001 diff --git a/public/img/posts/2024-blog-banner/mascots.webp b/public/img/posts/2024-blog-banner/mascots.webp new file mode 100644 index 0000000000000000000000000000000000000000..2205f5072cb1ce7d76f3d03df94dca3d2782ff7f GIT binary patch literal 29518 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�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�$k=&B91c8X!f4bk;`Md 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 efB*m`-~a#s000000000000000000000001?-u}1% literal 0 HcmV?d00001 From 08ef9f4cd55fbdab939f4049b499da9adb6524cc Mon Sep 17 00:00:00 2001 From: Antonio Date: Thu, 7 Nov 2024 01:00:18 +0200 Subject: [PATCH 41/91] docs(concepts): improve writing style (#3354) --- markdown/docs/concepts/application.md | 9 +++++---- .../docs/concepts/asyncapi-document/index.md | 10 ++++------ markdown/docs/concepts/channel.md | 10 +++++----- markdown/docs/concepts/consumer.md | 9 +++++---- markdown/docs/concepts/index.md | 4 ++-- markdown/docs/concepts/message.md | 10 +++++----- markdown/docs/concepts/producer.md | 16 +++++++++------- markdown/docs/concepts/protocol.md | 10 +++++----- markdown/docs/concepts/server.md | 8 ++++---- 9 files changed, 44 insertions(+), 42 deletions(-) diff --git a/markdown/docs/concepts/application.md b/markdown/docs/concepts/application.md index 1d9c4634a94..63bc5d75757 100644 --- a/markdown/docs/concepts/application.md +++ b/markdown/docs/concepts/application.md @@ -5,12 +5,12 @@ weight: 23 ## What is an application? -An application is any computer program or a group of them. +An _application_ is a computer program or a group of them. -An application could also be a micro-service, IoT device (sensor), mainframe process, etc. Users may even write applications in different programming languages if they support one of the selected protocols. +An application can be a micro-service, IoT (Internet of things) device (for example, a sensor), mainframe process, and more. Users can create applications using various programming languages that support the chosen protocols. ## Why do we need applications? -In Event-Driven Architecture (EDA), an application must be a `producer`, a `consumer`, or both. Applications must also use the protocols the server supports if they wish to connect and exchange messages. +In Event-Driven Architecture (EDA), an application can either be a producer, a consumer, or both. Additionally, if an application wants to connect and exchange messages with the server, it must adhere to the protocols supported by the server. ### Applications: producers and consumers ```mermaid @@ -20,4 +20,5 @@ flowchart TD C --> D[message] D --> F[CONSUMER application] ``` -The above diagram describes a message communication traveling through a channel between a **PRODUCER application** and a **CONSUMER application**. + +The diagram above illustrates a message transmission between a Producer application and a Consumer application through a channel. \ No newline at end of file diff --git a/markdown/docs/concepts/asyncapi-document/index.md b/markdown/docs/concepts/asyncapi-document/index.md index 032e8a0a9e2..9419ff90ff8 100644 --- a/markdown/docs/concepts/asyncapi-document/index.md +++ b/markdown/docs/concepts/asyncapi-document/index.md @@ -3,11 +3,11 @@ title: 'Introduction' weight: 50 --- -The AsyncAPI Specification defines a set of fields that can be used in an AsyncAPI document to describe an application's API. The document may reference other files for additional details or shared fields, but it is typically a single, primary document that encapsulates the API description. +The AsyncAPI Specification defines a set of fields that can be used in an AsyncAPI document to describe an application’s API. While the document may reference other files for additional details or shared fields, it usually serves as a single, primary document that encapsulates the API description. -Furthermore, the AsyncAPI document acts as a communication contract between `receivers` and `senders` within an event-driven system. It specifies the payload content required when a service sends a message and offers clear guidance to the receiver regarding the message's properties. +Furthermore, the AsyncAPI document acts as a communication contract between receivers and senders within an event-driven system. It specifies the payload content necessary for a service to send a message and provides clear guidance to the receiver about the message's properties. -```YAML +```yaml asyncapi: 3.0.0 info: title: Cool Example @@ -37,7 +37,5 @@ operations: ``` -You might have additional fields depending on the implemented protocol (i.e., MQTT, AMQP, Kafka, etc.). - -For example, your AsyncAPI document could have additional fields for configuring Kafka bindings. +Depending on the implemented protocol (such as MQTT, AMQP, Kafka, etc.), you may have additional fields in your AsyncAPI document. For example, for configuring Kafka bindings. diff --git a/markdown/docs/concepts/channel.md b/markdown/docs/concepts/channel.md index 96fefe067f7..d44759b8a2c 100644 --- a/markdown/docs/concepts/channel.md +++ b/markdown/docs/concepts/channel.md @@ -4,12 +4,10 @@ weight: 20 --- # What is a channel? -A `channel` is a mechanism created by the server for the organization and transmission of messages. Users can define channels as a _topic, queue, routing key, path,_ or _subject_ depending on the protocol used. +A _channel_ is a mechanism created by the server that facilitates the organization and transmission of messages. Depending on the used protocol, users can define channels as a _topic_, _queue_, _routing key_, _path_, or _subject_. # Why do we need channels? -Channels play a crucial role in communication between `producers` and `consumers`. A producer can send a message through the channel, and the consumer receives messages from a particular channel. A channel's sole purpose is to ensure the right messages route to the right consumers. - - +Channels are pivotal for establishing communication between producers and consumers. They enable producers to send messages, while consumers receive messages from specific channels. The primary function of a channel is to ensure that the intended messages reach the appropriate consumers. ```mermaid graph LR @@ -19,4 +17,6 @@ graph LR C --> E[Consumer] C --> F[Consumer] ``` -The diagram above shows the communication between a `producer` and `consumer`, with the producer sending a `message` through the `channel`. The channel then queues the message to the specific consumer. + +The diagram above illustrates the communication process between a producer and a consumer. The producer sends a message through the channel, which then queues the message for delivery to the specific consumer. +The diagram above illustrates the communication process between a producer and multiple consumers. The producer sends a message through the channel, which then queues the message for delivery to the appropriate consumers. \ No newline at end of file diff --git a/markdown/docs/concepts/consumer.md b/markdown/docs/concepts/consumer.md index 512970e11d4..a115505419f 100644 --- a/markdown/docs/concepts/consumer.md +++ b/markdown/docs/concepts/consumer.md @@ -4,12 +4,12 @@ weight: 4 --- ## What is a consumer? -In an Event Driven Architecture (EDA), a consumer is an application that listens for a particular event from a broker and reacts to it. +A _consumer_ is an application that subscribes to a specific event from a broker and responds accordingly. ## Why do we need consumers? -Unlike traditional REST APIs, in EDA, event consumers are not expected to respond immediately on the same connection. In this architecture, a consumer is unaware of the producer or other consumers; all they know is that when a broker sends them an event, it is because they subscribed to it. +Unlike traditional REST APIs, in Event-Driven Architecture (EDA), event consumers are asynchronous, which means they are not required to respond immediately on the same connection. In this architecture, consumers are unaware of the producers or other consumers. All they know is that when a broker sends them an event, it is because they have subscribed to it. -When you want events processed asynchronously in your application, the consumer plays an important role in completing that event data flow in the event channel. +When you want your application to process events asynchronously, the consumer plays a crucial role in completing the event data flow through the event channel. ```mermaid flowchart LR @@ -26,7 +26,8 @@ flowchart LR end ``` -The above diagram depicts a sample flow of events from `producer` to `broker` to `consumer`. In this instance, the `producer` publishes two events _(A and B)_ and sends them to the `broker`. Then each `consumer` subscribes to receive those events. +The diagram above illustrates a sample flow of events from the `producer` to the `broker` to the `consumers`. In this scenario, the `producer` publishes two events _(A and B)_ and sends them to the `broker`. Subsequently, each `consumer` subscribes to receive those events. + Subscribers can also be producers. diff --git a/markdown/docs/concepts/index.md b/markdown/docs/concepts/index.md index 34e581fea07..63dd3b9573e 100644 --- a/markdown/docs/concepts/index.md +++ b/markdown/docs/concepts/index.md @@ -5,9 +5,9 @@ weight: 1 import ContributionNotes from '@/assets/docs/fragments/contribution-notes.md'; -## Concepts: Define AsyncAPI features and capabilities +## Concepts -Welcome to AsyncAPI **Concepts**! Our Concepts section will define the concepts of AsyncAPI features and capabilities. +Welcome to AsyncAPI **Concepts**! This section defines AsyncAPI features and capabilities. diff --git a/markdown/docs/concepts/message.md b/markdown/docs/concepts/message.md index e5e65e91fb0..497bfa30a08 100644 --- a/markdown/docs/concepts/message.md +++ b/markdown/docs/concepts/message.md @@ -4,8 +4,9 @@ weight: 30 --- ## What is a message? -A `message` is a communication asset used to transmit or exchange information from a sender to the receiver through `channels`. A single `message` can be consumed by multiple independent receivers and can also be defined as an _event_ or _command_. The sender includes a payload of data (that has been serialized into an appropriate format, e.g., JSON, XML, binary, etc.) that needs to be processed by the receiver. It may also include metadata; information that describes the message itself. This metadata is often known as _headers_ or _properties_. +A _message_ is a communication asset that transmits or exchanges information from a sender to the receiver through channels. +One message can also be defined as an event or command and can be consumed by multiple independent receivers. The sender encodes a payload of data (serialized into a suitable format, such as JSON, XML, binary, or others) that requires processing by the receiver. Additionally, the message may include _metadata_, which is information that describes the message itself. This metadata is commonly referred to as _headers_ or _properties_. ``` mermaid graph LR @@ -17,11 +18,10 @@ A{{sender application}} --> b --> C{{receiver application}} ``` -In the diagram above, the sender application transmits a `message` to the receiver application. +The diagram above illustrates how a sender application transmits a message through a channel to a receiver application, demonstrating the basic flow of message-based communication. ## Messages vs Events -A `message` carries information from one application to the other, while an `event` is a message that provides details of something that has already occurred. One important aspect to note is that depending on the type of information a `message` contains, it can fall under an _event_, _query_, or _command_. -*See the diagram below.* +A **message** conveys information between applications, while an **event** is a message that provides details of something that has already occurred. A crucial aspect to note is that depending on the type of information a message carries, it can either be an event, query, or command. Check the diagram below. ``` mermaid graph TD @@ -32,4 +32,4 @@ graph TD C --> E(Command) ``` -Overall, `events` are `messages` but not all `messages` are `events`. +Summing up, events are messages, but not all messages are events. diff --git a/markdown/docs/concepts/producer.md b/markdown/docs/concepts/producer.md index ce17b9e3104..c2614d9c5b8 100644 --- a/markdown/docs/concepts/producer.md +++ b/markdown/docs/concepts/producer.md @@ -4,24 +4,26 @@ weight: 3 --- ## What is a Producer? -A producer is an application that senses state changes (events) and publishes those events as messages. An event indicates a state change or update triggered by a user's/device's action. +A _producer_ is an application that detects state changes (_events_) and publishes these events as messages. An event signifies a state change or update triggered by a user’s or device’s action. The following are sample events: -* Placing an item in a shopping cart on an e-commerce website. +* Adding an item to a shopping cart on an e-commerce website. * Clicking the subscribe button on a YouTube channel. -* A temperature change in a sensor. +* Detecting a temperature change using a sensor. + ## Why do we need Producers? -One of the core concepts of event-driven architecture is the publish/subscribe communication model. Producers are publishers in this model; they're the first logical layer responsible for distributing messages to the broker so that others can subscribe to receive messages. +The publish/subscribe communication model is one of the core concepts of event-driven architecture. In this model, producers are publishers, acting as the first logical layer responsible for distributing messages to the broker, enabling others to subscribe and receive these messages. ```mermaid flowchart TD a[Producer]-- Message 1 --->d[(Broker)] d -- Message 1 --->g[Consumer] ``` -The diagram above depicts the communication between a **producer** publishing events to a specific channel in a **broker** and a **consumer** subscribed to the same channel. -In some cases, an entity can be both a producer publishing messages to a specific channel in the broker and a consumer subscribing to messages from a different channel in the broker. +The diagram above illustrates the communication flow between a producer who publishes events to a specific channel in a broker and a consumer who subscribes to the same channel. + +In some cases, an entity can simultaneously function as both a producer, publishing messages to a specific channel in the broker, and a consumer, subscribing to messages from a different channel in the broker. ```mermaid flowchart LR @@ -31,4 +33,4 @@ flowchart LR c -- Message 2 ---> d[Consumer] ``` -In the diagram above, we see a producer publishing messages to a specific channel and a consumer subscribing to messages from that channel. We also have a second producer who publishes to one channel, but subscribes to messages from another. +In the diagram above, there is a producer publishing messages to a specific channel and a consumer subscribing to messages from that channel. Also, there is a second producer publishing to one channel and subscribing to messages from another channel. diff --git a/markdown/docs/concepts/protocol.md b/markdown/docs/concepts/protocol.md index 61a45474484..8fb93541f00 100644 --- a/markdown/docs/concepts/protocol.md +++ b/markdown/docs/concepts/protocol.md @@ -5,7 +5,7 @@ weight: 25 ## What is a protocol? -A protocol is a set of rules that specifies how information is exchanged between applications and/or servers. +A _protocol_ is a set of rules that governs the exchange of information between applications and/or servers. Protocol examples: * [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) @@ -14,7 +14,7 @@ Protocol examples: * [MQTT](https://mqtt.org/) ## Why do we need protocols? -Whenever a producer detects a state change (events) and publishes those events as messages, a protocol carries those messages to the channel and then to a consumer. Protocol plays a vital role in message transmission. +Protocols play a crucial role in message transmission. Whenever a producer detects a state change (events) and publishes those events as messages, a protocol carries those messages to the channel and then to the consumer. ```mermaid sequenceDiagram @@ -23,8 +23,8 @@ sequenceDiagram Publisher->>+Publisher: Delete(Msg) ``` -The diagram above depicts the message exchange flow from `producer` to `broker` to `consumer` using the MQTT protocol with QoS0 (quality of service 0). This means that information exchanged from `producer` to `broker` to `consumer` is delivered at most once. +The diagram above illustrates the message exchange flow from `producer` to `broker` to `consumer` using the MQTT protocol with QoS0 (quality of service 0). In other words, the information transferred from the producer to broker to consumer is delivered at most once. -The quality of service information rule is specified on a protocol level. Broker implementations and other involved actors must act accordingly. +The quality of service information rule is defined at the protocol level. Broker implementations and other involved parties must adhere to this rule. -In AsyncAPI documents, all protocol-specific details that the application follows can be described using [bindings](/docs/reference/specification/v2.5.0#definitionsBindings). +In AsyncAPI documents, all protocol-specific details that the application follows can be described using [bindings](https://www.asyncapi.com/docs/reference/specification/latest#definitionsBindings). diff --git a/markdown/docs/concepts/server.md b/markdown/docs/concepts/server.md index 7d3a6441bb3..d6f46107613 100644 --- a/markdown/docs/concepts/server.md +++ b/markdown/docs/concepts/server.md @@ -5,10 +5,10 @@ weight: 2 ## What is a server? -A server represents a messaging broker system where connections and communication between a producer and a consumer are established. Unlike traditional API servers which are dependent on request/response, message broker interactions occur back and forth over different channels. +A _server_ acts as a _messaging broker_ system, establishing connections and facilitating communication between [_producers_](producer) and [_consumers_](consumer). Unlike traditional API servers that rely on request-response interactions, message broker interactions occur bidirectionally across various channels. ## What is the purpose of servers? -Servers play an important role in maintaining a relationship between producers and consumers. When designing and setting up an event-driven application, servers are in charge of delivering asynchronous messages from the producer to the consumers through the use of channels. By integrating different messaging protocols, servers can transmit and exchange messages between clients. +Servers play a crucial role in establishing a connection between producers and consumers. In the context of designing and setting up an event-driven application, servers are responsible for delivering asynchronous messages from the producer to the consumers through the use of [_channels_](channel). Additionally, servers can integrate various messaging [_protocols_](protocol) to facilitate the transmission and exchange of messages between _clients_. ### Clients and Server ```mermaid @@ -18,7 +18,7 @@ flowchart TD c[Client Mobile] --> b[(server)] b --> c ``` -The diagram above describes a bi-directional communication between several **clients** and one **server**. In this case, in your AsyncAPI file, you describe the `server`, and therefore the [`Server Object`](https://www.asyncapi.com/docs/reference/specification/latest#serverObject) holds information about the actual server, including its physical location. +The diagram above illustrates a bidirectional communication between one server and several clients. In this case, in your AsyncAPI file, you describe the `server`, so the [`Server Object`](https://www.asyncapi.com/docs/reference/specification/latest#serverObject) holds information about the actual server, including its physical location. ### Broker Centric @@ -35,4 +35,4 @@ flowchart TD a2 --> C[consumer2] ``` -The diagram above shows the *Broker Centric Architecture*. In this case, we created three AsyncAPI files for the `producer`, `consumer1`, and `consumer2`. In these AsyncAPI files, the [`Server Object`](https://www.asyncapi.com/docs/reference/specification/latest#serverObject) provides information about the `broker`, so that API users know where to connect to start receiving or sending messages. +The diagram above illustrates the Broker-centric Architecture. In this case, there are three AsyncAPI files for the `producer`, `consumer1`, and `consumer2`. In these AsyncAPI files, the [`Server Object`](https://www.asyncapi.com/docs/reference/specification/latest#serverObject) provides information about the `broker`, so that API users know where to connect to start receiving or sending messages. From 8e34ea8e13d257afe324b72a8d1bdbd28a58f0eb Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Thu, 7 Nov 2024 01:36:09 +0100 Subject: [PATCH 42/91] chore: update meetings.json and newsrooom_videos.json (#3369) --- config/newsroom_videos.json | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/config/newsroom_videos.json b/config/newsroom_videos.json index 2f999644269..104af1d12bb 100644 --- a/config/newsroom_videos.json +++ b/config/newsroom_videos.json @@ -1,32 +1,32 @@ [ { - "image_url": "https://i.ytimg.com/vi/wiM20HTCerM/hqdefault.jpg", - "title": "Using API spec as an Executable Contract To Mock and Test Mic - Hari Krishnanroservices", - "description": "AsyncAPI allows us to articulate communication channels between services clearly. What if I told you that this AsyncAPI ...", - "videoId": "wiM20HTCerM" + "image_url": "https://i.ytimg.com/vi/ap2ZiRN8MDs/hqdefault.jpg", + "title": "My GSoC Experience with AsyncAPI - Yuan Yuan", + "description": "", + "videoId": "ap2ZiRN8MDs" }, { - "image_url": "https://i.ytimg.com/vi/22LFOLeF9Lk/hqdefault.jpg", - "title": "AsyncAPI + WebSocket: The Collaborative Combo", - "description": "Build a real-time collaborative drawing app from scratch using WebSocket & AsyncAPI, where users can draw together and chat in ...", - "videoId": "22LFOLeF9Lk" + "image_url": "https://i.ytimg.com/vi/9MaHh4b-rmc/hqdefault.jpg", + "title": "Broadening the API Landscape: AsyncAPI and CloudEvents in the Enterprise - Daniel Kocot", + "description": "", + "videoId": "9MaHh4b-rmc" }, { - "image_url": "https://i.ytimg.com/vi/XGn8v0yBfOI/hqdefault.jpg", - "title": "AsyncAPI Online Conference 2024💜", - "description": "AsyncAPI Online Conference 2024 Welcome to the AsyncAPI Online Conference 2024 Edition.", - "videoId": "XGn8v0yBfOI" + "image_url": "https://i.ytimg.com/vi/lCTdXmougTk/hqdefault.jpg", + "title": "AsyncAPI and DDD - A Pretty Couple - Dr. Annegret Junker", + "description": "", + "videoId": "lCTdXmougTk" }, { - "image_url": "https://i.ytimg.com/vi/Hy3-C6V2ir8/hqdefault.jpg", - "title": "AsyncAPI Conference Dry Run", - "description": "Setup and conference prep.", - "videoId": "Hy3-C6V2ir8" + "image_url": "https://i.ytimg.com/vi/Q1q6JoFG0zM/hqdefault.jpg", + "title": "The Many Meanings Of An AsyncAPI File - Swen-Helge Huber", + "description": "", + "videoId": "Q1q6JoFG0zM" }, { - "image_url": "https://i.ytimg.com/vi/2WUchTKDPfs/hqdefault.jpg", - "title": "Marketing WG Meeting, 14:00 UTC Tuesday October 22nd 2024", - "description": "https://github.com/asyncapi/community/issues/1553.", - "videoId": "2WUchTKDPfs" + "image_url": "https://i.ytimg.com/vi/b_BStEcLNqg/hqdefault.jpg", + "title": "Sustaining Open Source Beyond Code: The Importance of Marketing and Funding - Oluwabamikemi Kayode", + "description": "", + "videoId": "b_BStEcLNqg" } ] \ No newline at end of file From d9f5cdc03da05ff2cc485ff41c46d7f29d72cfe6 Mon Sep 17 00:00:00 2001 From: Vishvamsinh Vaghela <90895835+vishvamsinh28@users.noreply.github.com> Date: Thu, 7 Nov 2024 09:17:07 +0530 Subject: [PATCH 43/91] feat: add tests for dashboard script (#3344) Co-authored-by: Ansh Goyal --- scripts/dashboard/build-dashboard.js | 44 ++++-- tests/dashboard/build-dashboard.test.js | 198 ++++++++++++++++++++++++ tests/fixtures/dashboardData.js | 81 ++++++++++ 3 files changed, 306 insertions(+), 17 deletions(-) create mode 100644 tests/dashboard/build-dashboard.test.js create mode 100644 tests/fixtures/dashboardData.js diff --git a/scripts/dashboard/build-dashboard.js b/scripts/dashboard/build-dashboard.js index 5b0a34bee17..c20be204e87 100644 --- a/scripts/dashboard/build-dashboard.js +++ b/scripts/dashboard/build-dashboard.js @@ -1,4 +1,4 @@ -const { writeFileSync } = require('fs'); +const { writeFile } = require('fs-extra'); const { resolve } = require('path'); const { graphql } = require('@octokit/graphql'); const { Queries } = require('./issue-queries'); @@ -44,10 +44,10 @@ async function getDiscussions(query, pageSize, endCursor = null) { return result.search.nodes.concat(await getDiscussions(query, pageSize, result.search.pageInfo.endCursor)); } catch (e) { console.error(e); - return Promise.reject(e); } } + async function getDiscussionByID(isPR, id) { try { const result = await graphql(isPR ? Queries.pullRequestById : Queries.issueById, { @@ -60,7 +60,6 @@ async function getDiscussionByID(isPR, id) { return result; } catch (e) { console.error(e); - return Promise.reject(e); } } @@ -69,7 +68,6 @@ async function processHotDiscussions(batch) { return Promise.all( batch.map(async (discussion) => { try { - // eslint-disable-next-line no-underscore-dangle const isPR = discussion.__typename === 'PullRequest'; if (discussion.comments.pageInfo.hasNextPage) { const fetchedDiscussion = await getDiscussionByID(isPR, discussion.id); @@ -83,9 +81,10 @@ async function processHotDiscussions(batch) { const finalInteractionsCount = isPR ? interactionsCount + - discussion.reviews.totalCount + - discussion.reviews.nodes.reduce((acc, curr) => acc + curr.comments.totalCount, 0) + discussion.reviews.totalCount + + discussion.reviews.nodes.reduce((acc, curr) => acc + curr.comments.totalCount, 0) : interactionsCount; + return { id: discussion.id, isPR, @@ -98,7 +97,7 @@ async function processHotDiscussions(batch) { score: finalInteractionsCount / (monthsSince(discussion.timelineItems.updatedAt) + 2) ** 1.8 }; } catch (e) { - console.error(`there was some issues while parsing this item: ${JSON.stringify(discussion)}`); + console.error(`there were some issues while parsing this item: ${JSON.stringify(discussion)}`); throw e; } }) @@ -111,21 +110,28 @@ async function getHotDiscussions(discussions) { for (let i = 0; i < discussions.length; i += batchSize) { const batch = discussions.slice(i, i + batchSize); - // eslint-disable-next-line no-await-in-loop const batchResults = await processHotDiscussions(batch); - - // eslint-disable-next-line no-await-in-loop await pause(1000); - result.push(...batchResults); } + result.sort((ElemA, ElemB) => ElemB.score - ElemA.score); const filteredResult = result.filter((issue) => issue.author !== 'asyncapi-bot'); return filteredResult.slice(0, 12); } -async function writeToFile(content) { - writeFileSync(resolve(__dirname, '..', '..', 'dashboard.json'), JSON.stringify(content, null, ' ')); + +async function writeToFile(content, writePath) { + try { + await writeFile(writePath, JSON.stringify(content, null, ' ')); + } catch (error) { + console.error('Failed to write dashboard data:', { + error: error.message, + writePath + }); + throw error; + } } + async function mapGoodFirstIssues(issues) { return issues.map((issue) => ({ id: issue.id, @@ -153,7 +159,7 @@ function monthsSince(date) { return Math.floor(months); } -async function start() { +async function start(writePath) { try { const issues = await getDiscussions(Queries.hotDiscussionsIssues, 20); const PRs = await getDiscussions(Queries.hotDiscussionsPullRequests, 20); @@ -163,12 +169,16 @@ async function start() { getHotDiscussions(discussions), mapGoodFirstIssues(rawGoodFirstIssues) ]); - writeToFile({ hotDiscussions, goodFirstIssues }); + return await writeToFile({ hotDiscussions, goodFirstIssues }, writePath); } catch (e) { console.log('There were some issues parsing data from github.'); console.log(e); } } -start(); -module.exports = { getLabel, monthsSince, mapGoodFirstIssues, getHotDiscussions, getDiscussionByID }; +/* istanbul ignore next */ +if (require.main === module) { + start(resolve(__dirname, '..', '..', 'dashboard.json')); +} + +module.exports = { getLabel, monthsSince, mapGoodFirstIssues, getHotDiscussions, getDiscussionByID, getDiscussions, writeToFile, start, processHotDiscussions }; diff --git a/tests/dashboard/build-dashboard.test.js b/tests/dashboard/build-dashboard.test.js new file mode 100644 index 00000000000..e7861c36dc6 --- /dev/null +++ b/tests/dashboard/build-dashboard.test.js @@ -0,0 +1,198 @@ +const { graphql } = require('@octokit/graphql'); +const { promises: fs, mkdirSync, rmSync } = require('fs-extra'); +const { resolve } = require('path'); +const os = require('os'); +const { + getLabel, + monthsSince, + mapGoodFirstIssues, + getHotDiscussions, + getDiscussionByID, + writeToFile, + getDiscussions, + start +} = require('../../scripts/dashboard/build-dashboard'); + +const { + issues, + mockDiscussion, + discussionWithMoreComments, + fullDiscussionDetails, + mockRateLimitResponse +} = require("../fixtures/dashboardData") + +jest.mock('@octokit/graphql'); + +describe('GitHub Discussions Processing', () => { + let tempDir; + let consoleErrorSpy; + let consoleLogSpy; + + beforeAll(() => { + tempDir = resolve(os.tmpdir(), 'test-config'); + mkdirSync(tempDir); + }); + + afterAll(() => { + rmSync(tempDir, { recursive: true, force: true }); + }); + + beforeEach(() => { + jest.clearAllMocks(); + consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { }); + consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { }); + }); + + afterEach(() => { + consoleErrorSpy.mockRestore(); + consoleLogSpy.mockRestore(); + }); + + it('should fetch additional discussion details when comments have next page', async () => { + graphql.mockResolvedValueOnce(fullDiscussionDetails); + + const result = await getHotDiscussions([discussionWithMoreComments]); + + expect(graphql).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + id: 'paginated-discussion', + headers: expect.any(Object) + }) + ); + + expect(result[0]).toMatchObject({ + id: 'paginated-discussion', + isPR: false, + title: 'Test with Pagination' + }); + + const firstResult = result[0]; + expect(firstResult.score).toBeGreaterThan(0); + }); + + it('should handle rate limit warnings', async () => { + graphql.mockResolvedValueOnce(mockRateLimitResponse); + + await getDiscussions('test-query', 10); + + expect(consoleLogSpy).toHaveBeenCalledWith( + '[WARNING] GitHub GraphQL rateLimit', + 'cost = 1', + 'limit = 5000', + 'remaining = 50', + expect.any(String) + ); + }); + + it('should handle pagination', async () => { + const mockFirstResponse = { + search: { + nodes: [mockDiscussion], + pageInfo: { hasNextPage: true, endCursor: 'cursor1' } + }, + rateLimit: { remaining: 1000 } + }; + + const mockSecondResponse = { + search: { + nodes: [{ ...mockDiscussion, id: 'test-id-2' }], + pageInfo: { hasNextPage: false } + }, + rateLimit: { remaining: 1000 } + }; + + graphql + .mockResolvedValueOnce(mockFirstResponse) + .mockResolvedValueOnce(mockSecondResponse); + + const result = await getDiscussions('test-query', 10); + expect(result).toHaveLength(2); + }); + + it('should handle complete failure', async () => { + graphql.mockRejectedValue(new Error('Complete API failure')); + + const filePath = resolve(tempDir, 'error-output.json'); + await start(filePath); + + expect(consoleLogSpy).toHaveBeenCalledWith('There were some issues parsing data from github.'); + }); + + it('should successfully process and write data', async () => { + graphql.mockResolvedValue(mockRateLimitResponse); + + const filePath = resolve(tempDir, 'success-output.json'); + await start(filePath); + + const content = JSON.parse(await fs.readFile(filePath, 'utf-8')); + expect(content).toHaveProperty('hotDiscussions'); + expect(content).toHaveProperty('goodFirstIssues'); + }); + + it('should get labels correctly', () => { + const issue = { + labels: { nodes: [{ name: 'area/bug' }, { name: 'good first issue' }] } + }; + expect(getLabel(issue, 'area/')).toBe('bug'); + expect(getLabel(issue, 'nonexistent/')).toBeUndefined(); + }); + + it('should calculate months since date', () => { + const date = new Date(); + date.setMonth(date.getMonth() - 2); + expect(monthsSince(date)).toBe(2); + }); + + it('should map good first issues', async () => { + + const result = await mapGoodFirstIssues(issues); + expect(result[0]).toMatchObject({ + id: '1', + area: 'docs' + }); + }); + + it('should handle discussion retrieval', async () => { + graphql.mockResolvedValueOnce({ node: mockDiscussion }); + const result = await getDiscussionByID(false, 'test-id'); + expect(result.node).toBeDefined(); + + graphql.mockRejectedValueOnce(new Error('API error')); + await expect(getDiscussionByID(true, 'test-id')).rejects.toThrow(); + }); + + it('should process hot discussions', async () => { + const prDiscussion = { + ...mockDiscussion, + __typename: 'PullRequest', + reviews: { + totalCount: 1, + nodes: [{ comments: { totalCount: 1 } }] + } + }; + + const result = await getHotDiscussions([mockDiscussion, prDiscussion]); + expect(result.length).toBeLessThanOrEqual(12); + }); + + it('should write to file', async () => { + const filePath = resolve(tempDir, 'test.json'); + await writeToFile({ test: true }, filePath); + const content = JSON.parse(await fs.readFile(filePath, 'utf-8')); + expect(content).toEqual({ test: true }); + }); + + it('should handle parsing errors in processHotDiscussions', async () => { + const localConsoleErrorSpy = jest.spyOn(console, 'error'); + + await expect(getHotDiscussions([undefined])).rejects.toThrow(); + + expect(consoleErrorSpy).toHaveBeenCalledWith( + 'there were some issues while parsing this item: undefined' + ); + + localConsoleErrorSpy.mockRestore(); + }); + +}); diff --git a/tests/fixtures/dashboardData.js b/tests/fixtures/dashboardData.js new file mode 100644 index 00000000000..fa0618c299a --- /dev/null +++ b/tests/fixtures/dashboardData.js @@ -0,0 +1,81 @@ +const mockDiscussion = { + id: 'test-id', + __typename: 'Issue', + title: 'Test', + author: { login: 'author' }, + resourcePath: '/path', + repository: { name: 'repo' }, + assignees: { totalCount: 0 }, + reactions: { totalCount: 5 }, + comments: { + totalCount: 2, + nodes: [{ reactions: { totalCount: 1 } }], + pageInfo: { hasNextPage: false } + }, + labels: { nodes: [] }, + timelineItems: { updatedAt: new Date().toISOString() } +}; + +const discussionWithMoreComments = { + id: 'paginated-discussion', + __typename: 'Issue', + title: 'Test with Pagination', + author: { login: 'author' }, + resourcePath: '/path', + repository: { name: 'repo' }, + assignees: { totalCount: 0 }, + reactions: { totalCount: 5 }, + comments: { + totalCount: 5, + nodes: [{ reactions: { totalCount: 1 } }], + pageInfo: { hasNextPage: true } + }, + labels: { nodes: [] }, + timelineItems: { updatedAt: new Date().toISOString() } +}; + +const fullDiscussionDetails = { + node: { + ...discussionWithMoreComments, + comments: { + totalCount: 5, + nodes: [ + { reactions: { totalCount: 1 } }, + { reactions: { totalCount: 2 } }, + { reactions: { totalCount: 3 } } + ], + pageInfo: { hasNextPage: false } + } + } +}; + +const mockRateLimitResponse = { + search: { + nodes: [mockDiscussion], + pageInfo: { hasNextPage: false } + }, + rateLimit: { + cost: 1, + limit: 5000, + remaining: 50, + resetAt: new Date().toISOString() + } +}; + +const issues = [{ + id: '1', + title: 'Test', + assignees: { totalCount: 1 }, + resourcePath: '/path', + repository: { name: 'repo' }, + author: { login: 'author' }, + labels: { nodes: [{ name: 'area/docs' }] } +}]; + +module.exports = { + issues, + mockDiscussion, + discussionWithMoreComments, + fullDiscussionDetails, + mockRateLimitResponse +}; From 8ec5340bd9574a5b3144330457dd96057eacffec Mon Sep 17 00:00:00 2001 From: Manas Malla Date: Thu, 7 Nov 2024 09:44:27 +0530 Subject: [PATCH 44/91] style: added uniform padding around the `on this page` header (#3249) Co-authored-by: Ansh Goyal --- components/TOC.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/TOC.tsx b/components/TOC.tsx index 43819f0257e..f51acadc0fe 100644 --- a/components/TOC.tsx +++ b/components/TOC.tsx @@ -47,7 +47,7 @@ export default function TOC({ className, cssBreakingPoint = 'xl', toc, contentSe return (
setOpen(!open)} >
Date: Fri, 8 Nov 2024 00:13:49 +0530 Subject: [PATCH 45/91] feat: add cursor pointer on selector element (#3346) Co-authored-by: Ansh Goyal --- styles/globals.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/styles/globals.css b/styles/globals.css index fa419b64514..ecbca2ff0cb 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -351,3 +351,7 @@ abbr[title] { .explorer-menu-wrapper > div > div > div > button { margin-top: 0px; } + +select { + cursor:pointer; +} \ No newline at end of file From 7ee14651597a40d2a172f1bd7d3e581cd6dc66f4 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Fri, 8 Nov 2024 01:36:29 +0100 Subject: [PATCH 46/91] chore: update meetings.json and newsrooom_videos.json (#3376) --- config/meetings.json | 7 ------- config/newsroom_videos.json | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/config/meetings.json b/config/meetings.json index 9a21a9d36ff..67c519e7c36 100644 --- a/config/meetings.json +++ b/config/meetings.json @@ -1,11 +1,4 @@ [ - { - "title": "Marketing WG Meeting", - "calLink": "https://www.google.com/calendar/event?eid=b2twOWkyZ3ExcGxnYnAxbzBobzA1MWxvcW8gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1321", - "banner": "", - "date": "2024-07-30T14:00:00.000Z" - }, { "title": "Essential Building Blocks Working Group", "calLink": "https://www.google.com/calendar/event?eid=YzYyaHNiNTdqbGQ1OTNybjE1NDZlb2ppODAgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", diff --git a/config/newsroom_videos.json b/config/newsroom_videos.json index 104af1d12bb..8a00582be7d 100644 --- a/config/newsroom_videos.json +++ b/config/newsroom_videos.json @@ -1,32 +1,32 @@ [ - { - "image_url": "https://i.ytimg.com/vi/ap2ZiRN8MDs/hqdefault.jpg", - "title": "My GSoC Experience with AsyncAPI - Yuan Yuan", - "description": "", - "videoId": "ap2ZiRN8MDs" - }, { "image_url": "https://i.ytimg.com/vi/9MaHh4b-rmc/hqdefault.jpg", "title": "Broadening the API Landscape: AsyncAPI and CloudEvents in the Enterprise - Daniel Kocot", "description": "", "videoId": "9MaHh4b-rmc" }, - { - "image_url": "https://i.ytimg.com/vi/lCTdXmougTk/hqdefault.jpg", - "title": "AsyncAPI and DDD - A Pretty Couple - Dr. Annegret Junker", - "description": "", - "videoId": "lCTdXmougTk" - }, { "image_url": "https://i.ytimg.com/vi/Q1q6JoFG0zM/hqdefault.jpg", "title": "The Many Meanings Of An AsyncAPI File - Swen-Helge Huber", "description": "", "videoId": "Q1q6JoFG0zM" }, + { + "image_url": "https://i.ytimg.com/vi/lCTdXmougTk/hqdefault.jpg", + "title": "AsyncAPI and DDD - A Pretty Couple - Dr. Annegret Junker", + "description": "", + "videoId": "lCTdXmougTk" + }, { "image_url": "https://i.ytimg.com/vi/b_BStEcLNqg/hqdefault.jpg", "title": "Sustaining Open Source Beyond Code: The Importance of Marketing and Funding - Oluwabamikemi Kayode", "description": "", "videoId": "b_BStEcLNqg" + }, + { + "image_url": "https://i.ytimg.com/vi/G6YyV1JvvSM/hqdefault.jpg", + "title": "Streamlining EDA: AsyncAPI-Driven Design, Documentation, and Testing - Giri Venkatesan", + "description": "", + "videoId": "G6YyV1JvvSM" } ] \ No newline at end of file From 0909e2f58c8a3c3dcaa48f40d0378c419e4b333a Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Fri, 8 Nov 2024 12:42:40 +0100 Subject: [PATCH 47/91] docs(community): update latest maintainers list (#3377) --- config/MAINTAINERS.json | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/config/MAINTAINERS.json b/config/MAINTAINERS.json index 60932854b74..badcaae5faf 100644 --- a/config/MAINTAINERS.json +++ b/config/MAINTAINERS.json @@ -181,8 +181,8 @@ "github": "jonaslagoni", "linkedin": "jonaslagoni", "slack": "UQ2ANBG1E", + "company": "EventStack", "availableForHire": false, - "company": "Postman", "isTscMember": true, "repos": [ "spec-json-schemas", @@ -250,8 +250,7 @@ "linkedin": "lukasz-gornicki-a621914", "slack": "UD698Q5LM", "twitter": "derberq", - "availableForHire": false, - "company": "Postman", + "availableForHire": true, "isTscMember": true, "repos": [ "spec", @@ -315,7 +314,6 @@ "github": "AceTheCreator", "twitter": "_acebuild", "slack": "U01RWDD69PZ", - "company": "Postman", "availableForHire": false, "isTscMember": true, "repos": [ @@ -411,8 +409,8 @@ "slack": "U01N6AW5V5G", "twitter": "amzani", "linkedin": "amzani", + "company": "Apideck", "availableForHire": false, - "company": "Postman", "isTscMember": true, "repos": [ "studio", @@ -426,8 +424,8 @@ "linkedin": "smoya", "slack": "UN22ZTLHG", "twitter": "smoyac", + "company": "Timescale", "availableForHire": false, - "company": "Postman", "isTscMember": true, "repos": [ "spec", @@ -452,8 +450,7 @@ "slack": "U01SGCZMJKW", "twitter": "souvik_ns", "linkedin": "souvik-de-a2b941169", - "availableForHire": false, - "company": "Postman", + "availableForHire": true, "isTscMember": true, "repos": [ "cli", @@ -468,8 +465,7 @@ "twitter": "QuetzalliWrites", "slack": "U02AKC14WAJ", "linkedin": "quetzalli-writes", - "availableForHire": false, - "company": "Postman", + "availableForHire": true, "isTscMember": true, "repos": [ "website" From 79b249162a5f7ea890acfee423d7ba868bdc84a9 Mon Sep 17 00:00:00 2001 From: Aakanksha Bhende <63249668+aakankshabhende@users.noreply.github.com> Date: Fri, 8 Nov 2024 22:55:11 +0530 Subject: [PATCH 48/91] feat: integrated Coderabbit for AI powered PR reviews (#3298) Co-authored-by: Akshat Nema <76521428+akshatnema@users.noreply.github.com>%0ACo-authored-by: Ansh Goyal --- .coderrabbit.yml | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .coderrabbit.yml diff --git a/.coderrabbit.yml b/.coderrabbit.yml new file mode 100644 index 00000000000..e673f66e890 --- /dev/null +++ b/.coderrabbit.yml @@ -0,0 +1,45 @@ +language: "en-US" +reviews: + profile: "assertive" + request_changes_workflow: false + high_level_summary: true + poem: true + review_status: true + auto_review: + enabled: true +tools: + spellcheck: + enabled: true + markdownlint: + enabled: true + biome: + enabled: true + github-checks: + enabled: true + timeout_ms: 180000 + languagetool: + enabled: true + enabled_only: false + level: default + hadolint: + enabled: true + yamllint: + enabled: true + gitleaks: + enabled: true + eslint: + enabled: true + actionlint: + enabled: true + semgrep: + enabled: true +chat: + auto_reply: true +knowledge_base: + opt_out: false + learnings: + scope: "local" + issues: + scope: "local" + pull_requests: + scope: "local" From 311886b316664dfad6019b6e0a0d76d173fd864f Mon Sep 17 00:00:00 2001 From: Vishvamsinh Vaghela <90895835+vishvamsinh28@users.noreply.github.com> Date: Sat, 9 Nov 2024 12:29:51 +0530 Subject: [PATCH 49/91] feat: added test for build-rss.js (#3101) Co-authored-by: Akshat Nema <76521428+akshatnema@users.noreply.github.com>%0ACo-authored-by: Ansh Goyal %0ACo-authored-by: asyncapi-bot --- package-lock.json | 29 ++++++++ package.json | 3 +- scripts/build-rss.js | 128 ++++++++++++++++++++------------- tests/build-rss.test.js | 147 ++++++++++++++++++++++++++++++++++++++ tests/fixtures/rssData.js | 93 ++++++++++++++++++++++++ 5 files changed, 349 insertions(+), 51 deletions(-) create mode 100644 tests/build-rss.test.js create mode 100644 tests/fixtures/rssData.js diff --git a/package-lock.json b/package-lock.json index 837177c7acf..afff3d9c026 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "clsx": "^2.1.0", "cssnano": "^6.0.3", "dotenv": "^16.4.4", + "fast-xml-parser": "^4.5.0", "fs-extra": "^11.2.0", "fuse.js": "^7.0.0", "googleapis": "^133.0.0", @@ -13859,6 +13860,28 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-xml-parser": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", + "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -27471,6 +27494,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "license": "MIT" + }, "node_modules/style-loader": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", diff --git a/package.json b/package.json index 3885874ae36..84f538697d4 100644 --- a/package.json +++ b/package.json @@ -157,6 +157,7 @@ "remark-cli": "^12.0.1", "remark-lint": "^10.0.0", "remark-mdx": "^3.0.1", - "storybook": "^8.2.4" + "storybook": "^8.2.4", + "fast-xml-parser": "^4.5.0" } } diff --git a/scripts/build-rss.js b/scripts/build-rss.js index a5461f5e0ba..673da1398fe 100644 --- a/scripts/build-rss.js +++ b/scripts/build-rss.js @@ -1,8 +1,8 @@ -const fs = require('fs') +const fs = require('fs').promises const json2xml = require('jgexml/json2xml') function getAllPosts() { - return require('../config/posts.json') + return require('../config/posts.json'); } function clean(s) { @@ -15,61 +15,89 @@ function clean(s) { return s } -module.exports = function rssFeed(type, title, desc, outputPath) { +module.exports = async function rssFeed(type, title, desc, outputPath) { + try { - const posts = getAllPosts()[`${type}`] - .sort((i1, i2) => { - const i1Date = new Date(i1.date) - const i2Date = new Date(i2.date) + let posts = getAllPosts()[`${type}`] + const missingDatePosts = posts.filter(post => !post.date); + posts = posts.filter(post => post.date); + posts.sort((i1, i2) => { + const i1Date = new Date(i1.date); + const i2Date = new Date(i2.date); + if (i1.featured && !i2.featured) return -1; + if (!i1.featured && i2.featured) return 1; + return i2Date - i1Date; + }); - if (i1.featured && !i2.featured) return -1 - if (!i1.featured && i2.featured) return 1 - return i2Date - i1Date - }) + if (missingDatePosts.length > 0) { + throw new Error(`Missing date in posts: ${missingDatePosts.map(p => p.title || p.slug).join(', ')}`); + } + + const base = 'https://www.asyncapi.com' + const tracking = '?utm_source=rss'; + + const feed = {} + const rss = {} + rss['@version'] = '2.0' + rss["@xmlns:atom"] = 'http://www.w3.org/2005/Atom' + rss.channel = {} + rss.channel.title = title + rss.channel.link = `${base}/${outputPath}` + rss.channel["atom:link"] = {} + rss.channel["atom:link"]["@rel"] = 'self' + rss.channel["atom:link"]["@href"] = rss.channel.link + rss.channel["atom:link"]["@type"] = 'application/rss+xml' + rss.channel.description = desc + rss.channel.language = 'en-gb'; + rss.channel.copyright = 'Made with :love: by the AsyncAPI Initiative.'; + rss.channel.webMaster = 'info@asyncapi.io (AsyncAPI Initiative)' + rss.channel.pubDate = new Date().toUTCString() + rss.channel.generator = 'next.js' + rss.channel.item = [] - const base = 'https://www.asyncapi.com' - const tracking = '?utm_source=rss'; + const invalidPosts = posts.filter(post => + !post.title || !post.slug || !post.excerpt || !post.date + ); - const feed = {} - const rss = {} - rss['@version'] = '2.0' - rss["@xmlns:atom"] = 'http://www.w3.org/2005/Atom' - rss.channel = {} - rss.channel.title = title - rss.channel.link = `${base}/${outputPath}` - rss.channel["atom:link"] = {} - rss.channel["atom:link"]["@rel"] = 'self' - rss.channel["atom:link"]["@href"] = rss.channel.link - rss.channel["atom:link"]["@type"] = 'application/rss+xml' - rss.channel.description = desc - rss.channel.language = 'en-gb'; - rss.channel.copyright = 'Made with :love: by the AsyncAPI Initiative.'; - rss.channel.webMaster = 'info@asyncapi.io (AsyncAPI Initiative)' - rss.channel.pubDate = new Date().toUTCString() - rss.channel.generator = 'next.js' - rss.channel.item = [] + if (invalidPosts.length > 0) { + throw new Error(`Missing required fields in posts: ${invalidPosts.map(p => p.title || p.slug).join(', ')}`); + } - for (let post of posts) { - const link = `${base}${post.slug}${tracking}`; - const item = { title: post.title, description: clean(post.excerpt), link, category: type, guid: { '@isPermaLink': true, '': link }, pubDate: new Date(post.date).toUTCString() } - if (post.cover) { - const enclosure = {}; - enclosure["@url"] = base+post.cover; - enclosure["@length"] = 15026; // dummy value, anything works - enclosure["@type"] = 'image/jpeg'; - if (typeof enclosure["@url"] === 'string') { - let tmp = enclosure["@url"].toLowerCase(); - if (tmp.indexOf('.png')>=0) enclosure["@type"] = 'image/png'; - if (tmp.indexOf('.svg')>=0) enclosure["@type"] = 'image/svg+xml'; - if (tmp.indexOf('.webp')>=0) enclosure["@type"] = 'image/webp'; + for (let post of posts) { + const link = `${base}${post.slug}${tracking}`; + const { title, excerpt, date } = post; + const pubDate = new Date(date).toUTCString(); + const description = clean(excerpt); + const guid = { '@isPermaLink': true, '': link }; + const item = { + title, + description, + link, + category: type, + guid, + pubDate + }; + if (post.cover) { + const enclosure = {}; + enclosure["@url"] = base + post.cover; + enclosure["@length"] = 15026; // dummy value, anything works + enclosure["@type"] = 'image/jpeg'; + if (typeof enclosure["@url"] === 'string') { + let tmp = enclosure["@url"].toLowerCase(); + if (tmp.indexOf('.png') >= 0) enclosure["@type"] = 'image/png'; + if (tmp.indexOf('.svg') >= 0) enclosure["@type"] = 'image/svg+xml'; + if (tmp.indexOf('.webp') >= 0) enclosure["@type"] = 'image/webp'; + } + item.enclosure = enclosure; } - item.enclosure = enclosure; + rss.channel.item.push(item) } - rss.channel.item.push(item) - } - feed.rss = rss + feed.rss = rss - const xml = json2xml.getXml(feed,'@','',2) - fs.writeFileSync(`./public/${outputPath}`, xml, 'utf8') + const xml = json2xml.getXml(feed, '@', '', 2); + await fs.writeFile(`./public/${outputPath}`, xml, 'utf8'); + } catch (err) { + throw new Error(`Failed to generate RSS feed: ${err.message}`); + } }; diff --git a/tests/build-rss.test.js b/tests/build-rss.test.js new file mode 100644 index 00000000000..7961740fe5c --- /dev/null +++ b/tests/build-rss.test.js @@ -0,0 +1,147 @@ +const fs = require('fs'); +const path = require('path'); +const rssFeed = require('../scripts/build-rss'); +const { XMLParser } = require('fast-xml-parser'); +const parser = new XMLParser({ ignoreAttributes: false }); +const { mockRssData, title, type, desc, missingDateMockData, incompletePostMockData } = require('./fixtures/rssData'); + +describe('rssFeed', () => { + const testOutputDir = path.join(__dirname, '..', 'public', 'test-output'); + const outputPath = 'test-output/rss.xml'; + + beforeAll(async () => { + try { + await fs.promises.mkdir(testOutputDir, { recursive: true }); + } catch (err) { + throw new Error(`Error while creating temp dir: ${err.message}`); + } + }); + + afterAll(async () => { + try { + const files = await fs.promises.readdir(testOutputDir); + await Promise.all(files.map(file => fs.promises.unlink(path.join(testOutputDir, file)))); + await fs.promises.rmdir(testOutputDir); + } catch (err) { + throw new Error(`Error while deleting temp dir: ${err.message}`); + } + }); + + afterEach(() => { + jest.resetModules(); + }); + + it('should generate RSS feed and write to file', async () => { + + jest.doMock('../config/posts.json', () => mockRssData, { virtual: true }); + + await expect(rssFeed(type, title, desc, outputPath)).resolves.toBeUndefined() + + const filePath = path.join(__dirname, '..', 'public', outputPath); + expect(fs.existsSync(filePath)).toBe(true); + const fileContent = fs.readFileSync(filePath, 'utf8'); + expect(fileContent).toContain(' { + jest.doMock('../config/posts.json', () => mockRssData, { virtual: true }); + + await expect(rssFeed(type, title, desc, outputPath)).resolves.toBeUndefined(); + + const filePath = path.join(__dirname, '..', 'public', outputPath); + const fileContent = fs.readFileSync(filePath, 'utf8'); + + const parsedContent = parser.parse(fileContent); + const itemTitles = parsedContent.rss.channel.item.map(item => item.title); + + expect(itemTitles[0]).toBe('Test Post 1'); + expect(itemTitles[1]).toBe('Another Featured Post'); + + expect(itemTitles[2]).toBe('Post with Special Characters: & < > "'); + expect(itemTitles[3]).toBe('Post with UTC Date Format'); + expect(itemTitles[4]).toBe('Non-Featured Post 1'); + expect(itemTitles[5]).toBe('Non-Featured Post 3'); + }); + + it('should sort posts by date in descending order', async () => { + jest.doMock('../config/posts.json', () => mockRssData, { virtual: true }); + + await expect(rssFeed(type, title, desc, outputPath)).resolves.toBeUndefined(); + + const filePath = path.join(__dirname, '..', 'public', outputPath); + const fileContent = fs.readFileSync(filePath, 'utf8'); + + const parsedContent = parser.parse(fileContent); + const itemTitles = parsedContent.rss.channel.item.map(item => item.title); + + expect(itemTitles[0]).toBe('Test Post 1'); + expect(itemTitles[1]).toBe('Another Featured Post') + expect(itemTitles[2]).toBe('Post with Special Characters: & < > "'); + expect(itemTitles[3]).toBe('Post with UTC Date Format'); + expect(itemTitles[4]).toBe('Non-Featured Post 1'); + expect(itemTitles[5]).toBe('Non-Featured Post 3'); + }); + + it('should set correct enclosure type based on image extension', async () => { + jest.doMock('../config/posts.json', () => mockRssData, { virtual: true }); + + await expect(rssFeed(type, title, desc, outputPath)).resolves.toBeUndefined() + + const filePath = path.join(__dirname, '..', 'public', outputPath); + const fileContent = fs.readFileSync(filePath, 'utf8'); + + expect(fileContent).toContain(' { + jest.doMock('../config/posts.json', () => mockRssData, { virtual: true }); + + const invalidOutputPath = "invalid/path"; + + await expect(rssFeed(type, title, desc, invalidOutputPath)).rejects.toThrow(/ENOENT|EACCES/); + + }); + + it('should throw an error when posts.json is malformed', async () => { + jest.doMock('../config/posts.json', () => { + return { invalidKey: [] }; + }, { virtual: true }); + + await expect(rssFeed(type, title, desc, outputPath)).rejects.toThrow('Failed to generate RSS feed'); + + }); + + it('should handle empty posts array', async () => { + const emptyMockData = { blog: [] }; + jest.doMock('../config/posts.json', () => emptyMockData, { virtual: true }); + + await expect(rssFeed(type, title, desc, outputPath)).resolves.toBeUndefined() + + const filePath = path.join(__dirname, '..', 'public', outputPath); + const fileContent = fs.readFileSync(filePath, 'utf8'); + expect(fileContent).toContain(''); + }); + + it('should throw an error when post is missing required fields', async () => { + + jest.doMock('../config/posts.json', () => incompletePostMockData, { virtual: true }); + + await expect(rssFeed(type, title, desc, outputPath)).rejects.toThrow('Missing required fields'); + + }); + + it('should throw an error when a post is missing a date field during sorting', async () => { + + jest.doMock('../config/posts.json', () => missingDateMockData, { virtual: true }); + + await expect(rssFeed(type, title, desc, outputPath)).rejects.toThrow('Failed to generate RSS feed: Missing date in posts: Post without Date'); + + }); + +}); diff --git a/tests/fixtures/rssData.js b/tests/fixtures/rssData.js new file mode 100644 index 00000000000..89717784e51 --- /dev/null +++ b/tests/fixtures/rssData.js @@ -0,0 +1,93 @@ +const mockRssData = { + blog: [ + { + title: 'Non-Featured Post 1', + slug: '/blog/non-featured-post-1', + excerpt: 'This is a non-featured post', + date: '2023-07-05', + featured: false, + }, + { + title: 'Test Post 1', + slug: '/blog/test-post-1', + excerpt: 'This is a featured test post', + date: '2023-07-07', + featured: true, + cover: '/img/test-cover.jpg', + }, + { + title: 'Another Featured Post', + slug: '/blog/another-featured-post', + excerpt: 'This is another featured post', + date: '2023-07-06', + featured: true, + cover: '/img/test-cover.svg', + }, + { + title: 'Non-Featured Post 2', + slug: '/blog/non-featured-post-2', + excerpt: 'This is another non-featured post', + date: '2023-07-03', + featured: false, + cover: '/img/test-cover.webp', + }, + { + title: 'Non-Featured Post 3', + slug: '/blog/non-featured-post-3', + excerpt: 'This is yet another non-featured post', + date: '2023-07-04', + featured: false, + cover: '/img/test-cover.png', + }, + { + title: 'Post with Special Characters: & < > "', + slug: '/blog/special-chars', + excerpt: 'Testing HTML entities & encoding', + date: '2023-07-06T12:00:00Z', + featured: false, + }, + { + title: 'Post with UTC Date Format', + slug: '/blog/utc-date-format', + excerpt: 'This post uses a UTC date format', + date: 'Wed, 05 Jul 2023 12:00:00 GMT', + featured: false, + }, + ], +}; + +const missingDateMockData = { + blog: [ + { + title: 'Post without Date', + slug: '/blog/no-date-post', + excerpt: 'This post is missing a date', + featured: false, + }, + { + title: 'Valid Post', + slug: '/blog/valid-post', + excerpt: 'This post has a valid date', + date: '2024-07-05', + featured: true, + }, + ], +}; + +const incompletePostMockData = { + blog: [ + { + slug: '/blog/incomplete-post', + excerpt: 'This post is incomplete', + date: '2024-07-05', + featured: false, + }, + ], +}; + +const type = 'blog'; +const title = 'Test Blog RSS'; +const desc = 'Test blog RSS feed'; +const outputPath = 'test-output/blog.xml'; + +module.exports = { mockRssData, title, type, desc, outputPath, missingDateMockData, incompletePostMockData }; From f6757b495b6067f619519aa14e087b66646ed62c Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Sun, 10 Nov 2024 13:33:42 +0100 Subject: [PATCH 50/91] chore: update meetings.json and newsrooom_videos.json (#3379) Co-authored-by: asyncapi-bot --- dashboard.json | 316 +++++++++++++++++++++++----------------------- package-lock.json | 4 +- 2 files changed, 161 insertions(+), 159 deletions(-) diff --git a/dashboard.json b/dashboard.json index d4ecb4b72ce..a0f83848214 100644 --- a/dashboard.json +++ b/dashboard.json @@ -17,26 +17,109 @@ "score": 34.46095064991105 }, { - "id": "PR_kwDOFLhIt855u7Eb", + "id": "I_kwDODou01c5BZZv-", + "isPR": false, + "isAssigned": false, + "title": "Open Graph link preview image according to the document to open", + "author": "smoya", + "resourcePath": "/asyncapi/studio/issues/224", + "repo": "asyncapi/studio", + "labels": [ + { + "name": "enhancement", + "color": "a2eeef" + }, + { + "name": "keep-open", + "color": "f9dd4b" + } + ], + "score": 31.302030173669205 + }, + { + "id": "I_kwDOGQYLdM5AX1lK", + "isPR": false, + "isAssigned": true, + "title": "Brand Refresh: Mascot", + "author": "mcturco", + "resourcePath": "/asyncapi/brand/issues/12", + "repo": "asyncapi/brand", + "labels": [ + { + "name": ":art: design", + "color": "0D67D3" + }, + { + "name": "bounty", + "color": "0E8A16" + } + ], + "score": 22.112443333692923 + }, + { + "id": "PR_kwDOFLhIt85bqKL8", "isPR": true, "isAssigned": false, - "title": "docs: added community marketing strategy doc", - "author": "iambami", - "resourcePath": "/asyncapi/community/pull/1358", + "title": "docs: add Bounty Program Rules", + "author": "aeworxet", + "resourcePath": "/asyncapi/community/pull/897", "repo": "asyncapi/community", "labels": [], - "score": 19.527872034949596 + "score": 22.112443333692923 + }, + { + "id": "I_kwDOBW5R_c5BIl5P", + "isPR": false, + "isAssigned": false, + "title": "Add new page for collecting user testing participants", + "author": "mcturco", + "resourcePath": "/asyncapi/website/issues/529", + "repo": "asyncapi/website", + "labels": [ + { + "name": "enhancement", + "color": "84b6eb" + }, + { + "name": "Epic", + "color": "3E4B9E" + }, + { + "name": "keep-open", + "color": "ffee84" + }, + { + "name": "area/design", + "color": "0d67d3" + }, + { + "name": "area/javascript", + "color": "ededed" + } + ], + "score": 21.538094156194408 }, { - "id": "PR_kwDOBW5R_c52BRgf", + "id": "PR_kwDOBW5R_c5-T7mG", "isPR": true, "isAssigned": false, - "title": "feat: added test for build-rss.js", + "title": "feat: add tests for build post list script", "author": "vishvamsinh28", - "resourcePath": "/asyncapi/website/pull/3101", + "resourcePath": "/asyncapi/website/pull/3284", "repo": "asyncapi/website", "labels": [], - "score": 19.527872034949596 + "score": 20.38939580119737 + }, + { + "id": "PR_kwDOFLhIt855u7Eb", + "isPR": true, + "isAssigned": false, + "title": "docs: added marketing strategy doc", + "author": "iambami", + "resourcePath": "/asyncapi/community/pull/1358", + "repo": "asyncapi/community", + "labels": [], + "score": 20.102221212448114 }, { "id": "PR_kwDOFLhIt85oVQqh", @@ -50,24 +133,20 @@ "score": 18.666348268701817 }, { - "id": "I_kwDOGQYLdM5AX1lK", - "isPR": false, - "isAssigned": true, - "title": "Brand Refresh: Mascot", - "author": "mcturco", - "resourcePath": "/asyncapi/brand/issues/12", - "repo": "asyncapi/brand", + "id": "PR_kwDOBW5R_c535wDj", + "isPR": true, + "isAssigned": false, + "title": "feat: add test for combine tools script", + "author": "vishvamsinh28", + "resourcePath": "/asyncapi/website/pull/3136", + "repo": "asyncapi/website", "labels": [ { - "name": ":art: design", - "color": "0D67D3" - }, - { - "name": "bounty", - "color": "0E8A16" + "name": "gsoc", + "color": "F4D03F" } ], - "score": 17.230475324955524 + "score": 16.65612614745701 }, { "id": "PR_kwDOFLhIt853IEwA", @@ -91,44 +170,6 @@ "labels": [], "score": 15.220253203710714 }, - { - "id": "PR_kwDOCHlHJM54CmhW", - "isPR": true, - "isAssigned": false, - "title": "fix: add the migration guide and nunjucks depreciation notes", - "author": "Gmin2", - "resourcePath": "/asyncapi/generator/pull/1253", - "repo": "asyncapi/generator", - "labels": [], - "score": 13.78438025996442 - }, - { - "id": "I_kwDODou01c5o2x-Z", - "isPR": false, - "isAssigned": false, - "title": "Start using a React framework", - "author": "fmvilas", - "resourcePath": "/asyncapi/studio/issues/661", - "repo": "asyncapi/studio", - "labels": [], - "score": 13.210031082465903 - }, - { - "id": "I_kwDOFLhIt85xI2wH", - "isPR": false, - "isAssigned": false, - "title": "Measure AsyncAPI Adoption", - "author": "fmvilas", - "resourcePath": "/asyncapi/community/issues/879", - "repo": "asyncapi/community", - "labels": [ - { - "name": "stale", - "color": "ededed" - } - ], - "score": 12.922856493716644 - }, { "id": "PR_kwDOBW5R_c59wJxU", "isPR": true, @@ -138,69 +179,79 @@ "resourcePath": "/asyncapi/website/pull/3276", "repo": "asyncapi/website", "labels": [], - "score": 11.199808961221091 - }, + "score": 14.07155484871368 + } + ], + "goodFirstIssues": [ { - "id": "I_kwDODwv8N86BkfYV", - "isPR": false, + "id": "I_kwDOFLhIt86dkhlL", + "title": "Design for mentors for promotion", "isAssigned": false, - "title": "Add Gallery Section to AACoT'24 Conference Website", - "author": "Mayaleeeee", - "resourcePath": "/asyncapi/conference-website/issues/264", - "repo": "asyncapi/conference-website", + "resourcePath": "/asyncapi/community/issues/1582", + "repo": "asyncapi/community", + "author": "iambami", + "area": "design", "labels": [ { - "name": "Hacktoberfest", - "color": "FF8AE2" + "name": ":loudspeaker: marketing", + "color": "a829e2" } - ], - "score": 10.912634372471834 - } - ], - "goodFirstIssues": [ + ] + }, { - "id": "I_kwDODwv8N86bdV6Z", - "title": "Links in the Resources Hub Should Open in a New Window", + "id": "I_kwDOFLhIt86dker5", + "title": "Designs for the mentees selected for the mentorship program for promotion", "isAssigned": false, - "resourcePath": "/asyncapi/conference-website/issues/434", - "repo": "asyncapi/conference-website", - "author": "AceTheCreator", - "area": "Unknown", + "resourcePath": "/asyncapi/community/issues/1581", + "repo": "asyncapi/community", + "author": "iambami", + "area": "design", "labels": [ { - "name": "Hacktoberfest", - "color": "FF8AE2" + "name": ":loudspeaker: marketing", + "color": "a829e2" } ] }, { - "id": "I_kwDOFLhIt86bdQd-", - "title": "Add Proposed Project Ideas to Mentorship Directory", + "id": "I_kwDOBW5R_c6ddpHW", + "title": "[BUG] algolia search icon not visible on website navbar", "isAssigned": false, - "resourcePath": "/asyncapi/community/issues/1564", - "repo": "asyncapi/community", - "author": "AceTheCreator", + "resourcePath": "/asyncapi/website/issues/3371", + "repo": "asyncapi/website", + "author": "anshgoyalevil", "area": "Unknown", "labels": [ { - "name": "Hacktoberfest", - "color": "FF8AE2" + "name": "bug", + "color": "ee0701" } ] }, { - "id": "I_kwDOBW5R_c6aKzLD", - "title": "[FEATURE] Add coderabbit configuration to the repo", + "id": "I_kwDOBW5R_c6crqQz", + "title": "Improve image type detection in build-rss.js", "isAssigned": true, - "resourcePath": "/asyncapi/website/issues/3293", + "resourcePath": "/asyncapi/website/issues/3357", "repo": "asyncapi/website", - "author": "akshatnema", + "author": "coderabbitai", "area": "Unknown", "labels": [ { "name": "enhancement", "color": "84b6eb" - }, + } + ] + }, + { + "id": "I_kwDOFLhIt86bdQd-", + "title": "Add Proposed Project Ideas to Mentorship Directory", + "isAssigned": false, + "resourcePath": "/asyncapi/community/issues/1564", + "repo": "asyncapi/community", + "author": "AceTheCreator", + "area": "Unknown", + "labels": [ { "name": "Hacktoberfest", "color": "FF8AE2" @@ -241,21 +292,6 @@ } ] }, - { - "id": "I_kwDOCVQpZM6YZc4E", - "title": "Remove this redundant \"undefined\"", - "isAssigned": false, - "resourcePath": "/asyncapi/asyncapi-react/issues/1053", - "repo": "asyncapi/asyncapi-react", - "author": "AceTheCreator", - "area": "Unknown", - "labels": [ - { - "name": "Hacktoberfest", - "color": "FF8AE2" - } - ] - }, { "id": "I_kwDOCVQpZM6YZbiE", "title": "Remove this redundant \"undefined\"", @@ -290,51 +326,6 @@ } ] }, - { - "id": "I_kwDODwv8N86Vde8t", - "title": "Sponsor announcement design for social media", - "isAssigned": false, - "resourcePath": "/asyncapi/conference-website/issues/380", - "repo": "asyncapi/conference-website", - "author": "thulieblack", - "area": "Unknown", - "labels": [ - { - "name": "design", - "color": "5D0F46" - } - ] - }, - { - "id": "I_kwDODwv8N86VdePb", - "title": "The conference countdown banner", - "isAssigned": false, - "resourcePath": "/asyncapi/conference-website/issues/378", - "repo": "asyncapi/conference-website", - "author": "thulieblack", - "area": "Unknown", - "labels": [ - { - "name": "design", - "color": "5D0F46" - } - ] - }, - { - "id": "I_kwDOBW5R_c6VIyCf", - "title": "[Docs Bug 🐞 report]: Broken link to Generator Github Actions", - "isAssigned": false, - "resourcePath": "/asyncapi/website/issues/3190", - "repo": "asyncapi/website", - "author": "chinma-yyy", - "area": "Unknown", - "labels": [ - { - "name": "🐞 docs bug", - "color": "FFD23F" - } - ] - }, { "id": "I_kwDOGQYLdM6VGsJA", "title": "Design a Graphic for the Member Spotlight Post", @@ -453,7 +444,12 @@ "repo": "asyncapi/cli", "author": "Amzani", "area": "typescript", - "labels": [] + "labels": [ + { + "name": "stale", + "color": "ededed" + } + ] }, { "id": "I_kwDOFDnrNc6Gp8Qd", @@ -502,7 +498,7 @@ { "id": "I_kwDOE8Qh3857Kllp", "title": "Add loading animation for when playground generate models ", - "isAssigned": true, + "isAssigned": false, "resourcePath": "/asyncapi/modelina/issues/1725", "repo": "asyncapi/modelina", "author": "jonaslagoni", @@ -632,6 +628,10 @@ { "name": "bug", "color": "d73a4a" + }, + { + "name": "stale", + "color": "ededed" } ] }, diff --git a/package-lock.json b/package-lock.json index afff3d9c026..0749d409a5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,6 @@ "clsx": "^2.1.0", "cssnano": "^6.0.3", "dotenv": "^16.4.4", - "fast-xml-parser": "^4.5.0", "fs-extra": "^11.2.0", "fuse.js": "^7.0.0", "googleapis": "^133.0.0", @@ -116,6 +115,7 @@ "eslint-plugin-storybook": "^0.8.0", "eslint-plugin-tailwindcss": "^3.14.2", "eslint-plugin-unused-imports": "^3.1.0", + "fast-xml-parser": "^4.5.0", "inquirer": "^9.2.14", "jest": "^29.7.0", "postcss-import": "^16.0.1", @@ -13864,6 +13864,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", + "dev": true, "funding": [ { "type": "github", @@ -27498,6 +27499,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "dev": true, "license": "MIT" }, "node_modules/style-loader": { From fd0e5f15a26eff47a344fea9ac4a6008f4ef022d Mon Sep 17 00:00:00 2001 From: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> Date: Mon, 11 Nov 2024 07:54:33 +0200 Subject: [PATCH 51/91] feat: add paris ticket banner (#3363) Co-authored-by: Akshat Nema <76521428+akshatnema@users.noreply.github.com>%0ACo-authored-by: akshatnema --- .eslintrc | 5 +++-- components/campaigns/banners.ts | 14 +++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.eslintrc b/.eslintrc index ddab7e016ee..f77da8144e9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -9,7 +9,8 @@ "env": { "browser": true, "es2021": true, - "node": true + "node": true, + "jest": true }, "plugins": [ "react", @@ -313,4 +314,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/campaigns/banners.ts b/components/campaigns/banners.ts index 0620e6bdde9..7aad4527c83 100644 --- a/components/campaigns/banners.ts +++ b/components/campaigns/banners.ts @@ -17,12 +17,12 @@ export function shouldShowBanner(cfpDeadline: string) { export const banners = [ { - title: "AsyncAPI Online Conference'24", - city: 'YouTube', - dateLocation: '30th of October, 2024 | YouTube & LinkedIn', - cfaText: 'Join us Live', - eventName: 'the AsyncAPI Online Conference', - cfpDeadline: '2024-10-30T06:00:00Z', - link: 'https://www.youtube.com/live/F9wHxd-v2f0?si=kPCqgUzqAKC0FaqJ' + title: 'AsyncAPI Conference', + city: 'Paris Edition', + dateLocation: '5th of December, 2024 | France, Paris', + cfaText: 'Get Your Tickets', + eventName: 'the AsyncAPI Conf in Paris', + cfpDeadline: '2024-12-01T06:00:00Z', + link: 'https://conference.asyncapi.com/#tickets' } ]; From 9291da3f3fcfea988f58cc4ddfc1c60c2ef1722e Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Mon, 11 Nov 2024 14:54:08 +0100 Subject: [PATCH 52/91] docs(community): update latest maintainers list (#3380) --- config/MAINTAINERS.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config/MAINTAINERS.json b/config/MAINTAINERS.json index badcaae5faf..d94f257ad86 100644 --- a/config/MAINTAINERS.json +++ b/config/MAINTAINERS.json @@ -983,5 +983,18 @@ "kotlin-asyncapi" ], "githubID": 758568 + }, + { + "name": "Ashmit Jagtap", + "github": "ashmit-coder", + "linkedin": "ashmit-jagtap", + "twitter": "AshmitJagtap", + "slack": "U06RA7GDHU1", + "availableForHire": true, + "isTscMember": true, + "repos": [ + "conference-website" + ], + "githubID": 69006513 } ] \ No newline at end of file From 6f1538121c3eefb154290183e3302e36edee33e8 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Tue, 12 Nov 2024 13:09:20 +0100 Subject: [PATCH 53/91] ci: update update-maintainers-trigger.yaml workflow from global .github repo (#3382) --- .../workflows/update-maintainers-trigger.yaml | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/update-maintainers-trigger.yaml diff --git a/.github/workflows/update-maintainers-trigger.yaml b/.github/workflows/update-maintainers-trigger.yaml new file mode 100644 index 00000000000..12fc4abe4f0 --- /dev/null +++ b/.github/workflows/update-maintainers-trigger.yaml @@ -0,0 +1,28 @@ +# This action is centrally managed in https://github.com/asyncapi/.github/ +# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo + +name: Trigger MAINTAINERS.yaml file update + +on: + push: + branches: [ master ] + paths: + # Check all valid CODEOWNERS locations: + # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-file-location + - 'CODEOWNERS' + - '.github/CODEOWNERS' + - '.docs/CODEOWNERS' + +jobs: + trigger-maintainers-update: + name: Trigger updating MAINTAINERS.yaml because of CODEOWNERS change + runs-on: ubuntu-latest + + steps: + - name: Repository Dispatch + uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # https://github.com/peter-evans/repository-dispatch/releases/tag/v3.0.0 + with: + # The PAT with the 'public_repo' scope is required + token: ${{ secrets.GH_TOKEN }} + repository: ${{ github.repository_owner }}/community + event-type: trigger-maintainers-update From 09e83be778b6da3a8ab352e84bd23bb4980afa03 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Thu, 14 Nov 2024 22:28:37 +0100 Subject: [PATCH 54/91] docs(community): update latest tsc members list (#3397) --- config/AMBASSADORS_MEMBERS.json | 66 --------------------------------- 1 file changed, 66 deletions(-) diff --git a/config/AMBASSADORS_MEMBERS.json b/config/AMBASSADORS_MEMBERS.json index c86c4cca989..7e0bb122ce7 100644 --- a/config/AMBASSADORS_MEMBERS.json +++ b/config/AMBASSADORS_MEMBERS.json @@ -287,72 +287,6 @@ } ] }, - { - "name": "Jesse Menning", - "github": "jessemenning", - "twitter": "JesseMenning", - "bio": "Jesse Menning teams with companies and government agencies to design event-driven architecture and microservices at scale. To guide those discussions, I draw upon more than 15 years of integration architecture and implementation experience, particularly with IBM and Solace platforms. I've been involved with AsyncAPI since 2020, along with other open-source initiatives such as CloudEvents and OpenTelemetry.", - "linkedin": "jesse-menning", - "company": "Solace", - "title": "Architect, Office of the CTO at Solace", - "img": "https://avatars.githubusercontent.com/u/62108913?v=4", - "contributions": [ - { - "type": "article", - "title": "AsyncAPI 2.3 Adds Solace Bindings to Unlock Full Power of PubSub+", - "date": { - "year": 2022, - "month": "January" - }, - "link": "https://solace.com/blog/asyncapi-adds-solace-bindings/" - }, - { - "type": "article", - "title": "Align Production Reality and Event Documentation with the AsyncAPI Discovery Tool", - "date": { - "year": 2021, - "month": "November" - }, - "link": "https://solace.com/blog/asyncapi-discovery-tool/" - }, - { - "type": "article", - "title": "AsyncAPI vs. OpenAPI: Answers to Your Burning Questions About the Two Leading API Specs", - "date": { - "year": 2021, - "month": "June" - }, - "link": "https://solace.com/blog/asyncapi-vs-openapi/" - }, - { - "type": "article", - "title": "AsyncAPI, CloudEvents, OpenTelemetry: Which Event-Driven Specs Should Your DevOps Include?", - "date": { - "year": 2021, - "month": "March" - }, - "link": "https://solace.com/blog/asyncapi-cloudevents-opentelemetry-event-driven-specs-devops/" - }, - { - "type": "presentation", - "title": "Future of AsyncAPI, Panel discussion, AsyncAPI Conference", - "date": { - "year": 2021, - "month": "November" - }, - "link": "https://www.youtube.com/watch?v=3EeMHhbwyOQ" - }, - { - "type": "presentation", - "title": "Thinking Out Loud #4 — with Jesse Menning", - "date": { - "year": 2021, - "month": "August" - }, - "link": "https://www.youtube.com/watch?v=eJewFUR-OaM" - } - ] - }, { "name": "Ludovic Dussart", "github": "M3lkior", From 2b92e001b4ced49b92a569cd4fa9016929a77ab5 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Thu, 14 Nov 2024 22:28:48 +0100 Subject: [PATCH 55/91] docs(community): update latest maintainers list (#3398) --- config/MAINTAINERS.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/MAINTAINERS.json b/config/MAINTAINERS.json index d94f257ad86..ee02bec23fb 100644 --- a/config/MAINTAINERS.json +++ b/config/MAINTAINERS.json @@ -238,7 +238,7 @@ "twitter": "ldussart", "availableForHire": false, "company": "zatsit", - "isTscMember": true, + "isTscMember": false, "repos": [ "avro-schema-parser" ], @@ -343,7 +343,7 @@ "linkedin": "nektarios-fifes-372740220", "slack": "U01SE93Q48N", "availableForHire": true, - "isTscMember": true, + "isTscMember": false, "repos": [ "simulator" ], From 384da222d2b3eb7f375b2a72fafb46b10e19a1d4 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Fri, 15 Nov 2024 01:38:43 +0100 Subject: [PATCH 56/91] chore: update meetings.json and newsrooom_videos.json (#3399) --- config/meetings.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config/meetings.json b/config/meetings.json index 67c519e7c36..1cec6f23b60 100644 --- a/config/meetings.json +++ b/config/meetings.json @@ -6,13 +6,6 @@ "banner": "", "date": "2024-08-13T18:00:00.000Z" }, - { - "title": "Community Meeting", - "calLink": "https://www.google.com/calendar/event?eid=aG45bXYwN2I4NWthanBpZ290bzRnbjE1cWMgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", - "url": "https://github.com/asyncapi/community/issues/1335", - "banner": "https://github.com/user-attachments/assets/9d68eacc-c5b3-4f49-a7a2-4120ead380b0", - "date": "2024-08-06T08:00:00.000Z" - }, { "title": "Community Meeting", "calLink": "https://www.google.com/calendar/event?eid=cnIwc3U0c2o1a3FoaWM0M2VvZXFjNzJvZzQgY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", @@ -138,5 +131,12 @@ "url": "https://github.com/asyncapi/community/issues/1569", "banner": "https://github.com/user-attachments/assets/0cdfc741-e61d-4710-bb0a-af9f7485ff9a", "date": "2024-11-01T13:00:00.000Z" + }, + { + "title": "Marketing WG Meeting", + "calLink": "https://www.google.com/calendar/event?eid=dHVrZHMyYm9kMzcydmJpYW5qMmdpcWU5MW8gY19xOXRzZWlnbG9tZHNqNm5qdWh2YnB0czExY0Bn", + "url": "https://github.com/asyncapi/community/issues/1589", + "banner": "", + "date": "2024-11-19T14:00:00.000Z" } ] \ No newline at end of file From b6b05733ee865e527eb72c1a5df33e105151ac2f Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Mon, 18 Nov 2024 01:40:09 +0100 Subject: [PATCH 57/91] chore: update tools.json (#3404) --- config/all-tags.json | 2 +- config/tools-automated.json | 266 ++++++++++++++++++------------------ 2 files changed, 134 insertions(+), 134 deletions(-) diff --git a/config/all-tags.json b/config/all-tags.json index b2a1c6f3c3a..b8274f82abb 100644 --- a/config/all-tags.json +++ b/config/all-tags.json @@ -1 +1 @@ -{"languages":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"},{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"},{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"},{"name":"HTML","color":"bg-[#E2A291]","borderColor":"border-[#E44D26]"},{"name":"C/C++","color":"bg-[#93CDEF]","borderColor":"border-[#0080CC]"},{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"},{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"},{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"},{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"},{"name":"Scala","color":"bg-[#FFA299]","borderColor":"border-[#DF301F]"},{"name":"Markdown","color":"bg-[#BABEBF]","borderColor":"border-[#445B64]"},{"name":"YAML","color":"bg-[#FFB764]","borderColor":"border-[#F1901F]"},{"name":"R","color":"bg-[#84B5ED]","borderColor":"border-[#246BBE]"},{"name":"Ruby","color":"bg-[#FF8289]","borderColor":"border-[#FF000F]"},{"name":"Rust","color":"bg-[#FFB8AA]","borderColor":"border-[#E43716]"},{"name":"Shell","color":"bg-[#87D4FF]","borderColor":"border-[#389ED7]"},{"name":"Groovy","color":"bg-[#B6D5E5]","borderColor":"border-[#609DBC]"}],"technologies":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Hermes","color":"bg-[#8AEEBD]","borderColor":"border-[#2AB672]"},{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"},{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"AWS","color":"bg-[#FF9F59]","borderColor":"border-[#EF6703]"},{"name":"Docker","color":"bg-[#B8E0FF]","borderColor":"border-[#2596ED]"},{"name":"Node-RED","color":"bg-[#FF7474]","borderColor":"border-[#8F0101]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Saas","color":"bg-[#6AB8EC]","borderColor":"border-[#2275AD]"},{"name":"Kubernetes-native","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Scala","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Azure","color":"bg-[#4B93FF]","borderColor":"border-[#015ADF]"},{"name":"Jenkins","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Nest Js","color":"bg-[#E1224E]","borderColor":"border-[#B9012b]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Socket.IO","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Kotlin","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Groovy","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Markdown","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Shell","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"WebComponents","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Babel","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Storybook","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"VSCode","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"SmartPaste","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JetBrains","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"IntelliJ IDEA","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"HTML","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Java","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}]} \ No newline at end of file +{"languages":[{"name":"Go/Golang","color":"bg-[#8ECFDF]","borderColor":"border-[#00AFD9]"},{"name":"Java","color":"bg-[#ECA2A4]","borderColor":"border-[#EC2125]"},{"name":"JavaScript","color":"bg-[#F2F1C7]","borderColor":"border-[#BFBE86]"},{"name":"HTML","color":"bg-[#E2A291]","borderColor":"border-[#E44D26]"},{"name":"C/C++","color":"bg-[#93CDEF]","borderColor":"border-[#0080CC]"},{"name":"C#","color":"bg-[#E3AFE0]","borderColor":"border-[#9B4F96]"},{"name":"Python","color":"bg-[#A8D0EF]","borderColor":"border-[#3878AB]"},{"name":"TypeScript","color":"bg-[#7DBCFE]","borderColor":"border-[#2C78C7]"},{"name":"Kotlin","color":"bg-[#B1ACDF]","borderColor":"border-[#756BD9]"},{"name":"Scala","color":"bg-[#FFA299]","borderColor":"border-[#DF301F]"},{"name":"Markdown","color":"bg-[#BABEBF]","borderColor":"border-[#445B64]"},{"name":"YAML","color":"bg-[#FFB764]","borderColor":"border-[#F1901F]"},{"name":"R","color":"bg-[#84B5ED]","borderColor":"border-[#246BBE]"},{"name":"Ruby","color":"bg-[#FF8289]","borderColor":"border-[#FF000F]"},{"name":"Rust","color":"bg-[#FFB8AA]","borderColor":"border-[#E43716]"},{"name":"Shell","color":"bg-[#87D4FF]","borderColor":"border-[#389ED7]"},{"name":"Groovy","color":"bg-[#B6D5E5]","borderColor":"border-[#609DBC]"}],"technologies":[{"name":"Node.js","color":"bg-[#BDFF67]","borderColor":"border-[#84CE24]"},{"name":"Hermes","color":"bg-[#8AEEBD]","borderColor":"border-[#2AB672]"},{"name":"React JS","color":"bg-[#9FECFA]","borderColor":"border-[#08D8FE]"},{"name":".NET","color":"bg-[#A184FF]","borderColor":"border-[#5026D4]"},{"name":"ASP.NET","color":"bg-[#71C2FB]","borderColor":"border-[#1577BC]"},{"name":"Springboot","color":"bg-[#98E279]","borderColor":"border-[#68BC44]"},{"name":"AWS","color":"bg-[#FF9F59]","borderColor":"border-[#EF6703]"},{"name":"Docker","color":"bg-[#B8E0FF]","borderColor":"border-[#2596ED]"},{"name":"Node-RED","color":"bg-[#FF7474]","borderColor":"border-[#8F0101]"},{"name":"Maven","color":"bg-[#FF6B80]","borderColor":"border-[#CA1A33]"},{"name":"Saas","color":"bg-[#6AB8EC]","borderColor":"border-[#2275AD]"},{"name":"Kubernetes-native","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Scala","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Azure","color":"bg-[#4B93FF]","borderColor":"border-[#015ADF]"},{"name":"Jenkins","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Flask","color":"bg-[#D7C7F2]","borderColor":"border-[#A387D2]"},{"name":"Nest Js","color":"bg-[#E1224E]","borderColor":"border-[#B9012b]"},{"name":"TypeScript","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Socket.IO","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Liquid","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Kotlin","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Gradle","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Spring Cloud Streams","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JHipster JDL","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Groovy","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Markdown","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Shell","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"WebComponents","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Babel","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Storybook","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"AsyncAPI Generator","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"JetBrains","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"IntelliJ IDEA","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"VSCode","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"SmartPaste","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"HTML","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"},{"name":"Java","color":"bg-[#61d0f2]","borderColor":"border-[#40ccf7]"}]} \ No newline at end of file diff --git a/config/tools-automated.json b/config/tools-automated.json index 6378b0db96c..20f6621b8fe 100644 --- a/config/tools-automated.json +++ b/config/tools-automated.json @@ -71,28 +71,6 @@ "isAsyncAPIOwner": false } }, - { - "title": "Zod Sockets", - "description": "Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.", - "links": { - "websiteUrl": "https://www.npmjs.com/package/zod-sockets", - "repoUrl": "https://github.com/RobinTail/zod-sockets" - }, - "filters": { - "language": "TypeScript", - "technology": [ - "Node.js", - "TypeScript" - ], - "categories": [ - "code-first", - "dsl", - "framework" - ], - "hasCommercial": false, - "isAsyncAPIOwner": false - } - }, { "title": "nestjs-asyncapi", "description": "Utilize decorators to generate AsyncAPI document utilizing DTOs (similar to @nestjs/swagger) and a web UI.", @@ -133,27 +111,34 @@ "hasCommercial": false, "isAsyncAPIOwner": false } - } - ] - }, - "Code Generators": { - "description": "The following is a list of tools that generate code from an AsyncAPI document; not the other way around.", - "toolsList": [ + }, { - "title": "Golang AsyncAPI Code Generator", - "description": "Generate Go user and application boilerplate from AsyncAPI specifications. Can be called from `go generate` without requirements.\n", + "title": "Zod Sockets", + "description": "Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.", "links": { - "repoUrl": "https://github.com/lerenn/asyncapi-codegen" + "websiteUrl": "https://www.npmjs.com/package/zod-sockets", + "repoUrl": "https://github.com/RobinTail/zod-sockets" }, "filters": { - "language": "golang", + "language": "TypeScript", + "technology": [ + "Node.js", + "TypeScript" + ], "categories": [ - "code-generator" + "code-first", + "dsl", + "framework" ], "hasCommercial": false, "isAsyncAPIOwner": false } - }, + } + ] + }, + "Code Generators": { + "description": "The following is a list of tools that generate code from an AsyncAPI document; not the other way around.", + "toolsList": [ { "title": "ZenWave SDK", "description": "DDD and API-First for Event-Driven Microservices", @@ -180,6 +165,21 @@ "isAsyncAPIOwner": false } }, + { + "title": "Golang AsyncAPI Code Generator", + "description": "Generate Go user and application boilerplate from AsyncAPI specifications. Can be called from `go generate` without requirements.\n", + "links": { + "repoUrl": "https://github.com/lerenn/asyncapi-codegen" + }, + "filters": { + "language": "golang", + "categories": [ + "code-generator" + ], + "hasCommercial": false, + "isAsyncAPIOwner": false + } + }, { "title": "AsyncAPI Modelina", "description": "Generate payload models into Java, TypeScript, Go, etc, you name it, from AsyncAPI documents. This tool gives you full control over the models through high customization", @@ -289,28 +289,6 @@ "DSL": { "description": "Writing YAML by hand is no fun, and maybe you don't want a GUI, so use a Domain Specific Language to write AsyncAPI in your language of choice.", "toolsList": [ - { - "title": "Zod Sockets", - "description": "Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.", - "links": { - "websiteUrl": "https://www.npmjs.com/package/zod-sockets", - "repoUrl": "https://github.com/RobinTail/zod-sockets" - }, - "filters": { - "language": "TypeScript", - "technology": [ - "Node.js", - "TypeScript" - ], - "categories": [ - "code-first", - "dsl", - "framework" - ], - "hasCommercial": false, - "isAsyncAPIOwner": false - } - }, { "title": "ZenWave SDK", "description": "DDD and API-First for Event-Driven Microservices", @@ -336,6 +314,28 @@ "hasCommercial": false, "isAsyncAPIOwner": false } + }, + { + "title": "Zod Sockets", + "description": "Socket.IO solution with I/O validation and the ability to generate AsyncAPI specification and a contract for consumers.", + "links": { + "websiteUrl": "https://www.npmjs.com/package/zod-sockets", + "repoUrl": "https://github.com/RobinTail/zod-sockets" + }, + "filters": { + "language": "TypeScript", + "technology": [ + "Node.js", + "TypeScript" + ], + "categories": [ + "code-first", + "dsl", + "framework" + ], + "hasCommercial": false, + "isAsyncAPIOwner": false + } } ] }, @@ -404,34 +404,34 @@ } }, { - "title": "GitHub Action for CLI", - "description": "GitHub Action with generator, validator, converter and others - all in one for your AsyncAPI documents with AsyncAPI CLI as backbone", + "title": "GitHub Action for Generator", + "description": "CLI to work with your AsyncAPI files. You can validate them and in the future use a generator and even bootstrap a new file. Contributions are welcomed!", "links": { - "repoUrl": "https://github.com/asyncapi/github-action-for-cli" + "repoUrl": "https://github.com/asyncapi/cli" }, "filters": { "technology": [ - "AsyncAPI CLI" + "AsyncAPI Generator" ], "categories": [ - "github-action" + "github-actions" ], "hasCommercial": false, "isAsyncAPIOwner": true } }, { - "title": "GitHub Action for Generator", - "description": "CLI to work with your AsyncAPI files. You can validate them and in the future use a generator and even bootstrap a new file. Contributions are welcomed!", + "title": "GitHub Action for CLI", + "description": "GitHub Action with generator, validator, converter and others - all in one for your AsyncAPI documents with AsyncAPI CLI as backbone", "links": { - "repoUrl": "https://github.com/asyncapi/cli" + "repoUrl": "https://github.com/asyncapi/github-action-for-cli" }, "filters": { "technology": [ - "AsyncAPI Generator" + "AsyncAPI CLI" ], "categories": [ - "github-actions" + "github-action" ], "hasCommercial": false, "isAsyncAPIOwner": true @@ -581,25 +581,6 @@ "CLIs": { "description": "The following is a list of tools that you can work with in terminal or do some CI/CD automation.", "toolsList": [ - { - "title": "AsyncAPI CLI", - "description": "One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n", - "links": { - "websiteUrl": "https://www.asyncapi.com/tools/cli", - "repoUrl": "https://github.com/asyncapi/cli" - }, - "filters": { - "technology": [ - "TypeScript" - ], - "categories": [ - "others", - "cli" - ], - "hasCommercial": false, - "isAsyncAPIOwner": true - } - }, { "title": "ZenWave SDK", "description": "DDD and API-First for Event-Driven Microservices", @@ -626,6 +607,25 @@ "isAsyncAPIOwner": false } }, + { + "title": "AsyncAPI CLI", + "description": "One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n", + "links": { + "websiteUrl": "https://www.asyncapi.com/tools/cli", + "repoUrl": "https://github.com/asyncapi/cli" + }, + "filters": { + "technology": [ + "TypeScript" + ], + "categories": [ + "others", + "cli" + ], + "hasCommercial": false, + "isAsyncAPIOwner": true + } + }, { "title": "AsyncAPI CLI", "description": "One CLI to rule them all. \nThis is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. \nYou can use it to generate docs or code, validate AsyncAPI document and event create new documents.\n", @@ -673,24 +673,6 @@ "IDE Extensions": { "description": "The following is a list of extensions for different IDEs like VSCode, IntelliJ IDEA and others", "toolsList": [ - { - "title": "asyncapi-preview", - "description": "VSCode extension that enables you to:\n - Preview documentation generated using you AsyncAPI document. It uses AsyncAPI React component under the hood,\n - Create AsyncAPI documents faster using SmartPaste functionality\n", - "links": { - "repoUrl": "https://github.com/asyncapi/vs-asyncapi-preview" - }, - "filters": { - "technology": [ - "VSCode", - "SmartPaste" - ], - "categories": [ - "ide-extension" - ], - "hasCommercial": false, - "isAsyncAPIOwner": true - } - }, { "title": "jAsyncAPI - IDEA plugin", "description": "Idea plugin for the java-asyncapi - Helps to edit and validate AsyncAPI schemas.", @@ -711,30 +693,30 @@ "hasCommercial": false, "isAsyncAPIOwner": true } - } - ] - }, - "AsyncAPI Generator Templates": { - "description": "The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents.", - "toolsList": [ + }, { - "title": "Node.js Websockets Template", - "description": "Node.js WebSockets template for the AsyncAPI Generator. It showcases how from a single AsyncAPI document you can generate a server and a client at the same time.", + "title": "asyncapi-preview", + "description": "VSCode extension that enables you to:\n - Preview documentation generated using you AsyncAPI document. It uses AsyncAPI React component under the hood,\n - Create AsyncAPI documents faster using SmartPaste functionality\n", "links": { - "repoUrl": "https://github.com/asyncapi/nodejs-ws-template" + "repoUrl": "https://github.com/asyncapi/vs-asyncapi-preview" }, "filters": { - "language": "javascript", "technology": [ - "Node.js" + "VSCode", + "SmartPaste" ], "categories": [ - "generator-template" + "ide-extension" ], "hasCommercial": false, "isAsyncAPIOwner": true } - }, + } + ] + }, + "AsyncAPI Generator Templates": { + "description": "The following is a list of templates compatible with AsyncAPI Generator. You can use them to generate apps, clients or documentation from your AsyncAPI documents.", + "toolsList": [ { "title": "HTML Template", "description": "HTML template for AsyncAPI Generator. Use it to generate a static docs. It is using AsyncAPI React component under the hood.", @@ -754,18 +736,17 @@ } }, { - "title": "Java Spring Cloud Stream Template", - "description": "Java Spring Cloud Stream template for the AsyncAPI Generator", + "title": "Java Template", + "description": "Java template for the AsyncAPI Generator", "links": { - "repoUrl": "https://github.com/asyncapi/java-spring-cloud-stream-template" + "repoUrl": "https://github.com/asyncapi/java-template" }, "filters": { "language": [ "javascript" ], "technology": [ - "Spring Cloud Streams", - "Maven" + "Java" ], "categories": [ "generator-template" @@ -775,17 +756,15 @@ } }, { - "title": "Java Template", - "description": "Java template for the AsyncAPI Generator", + "title": "Node.js Multiprotocol Template", + "description": "This template generates a server using your AsyncAPI document. It supports multiple different protocols, like Kafka or MQTT. It is designed in the way that generated code is a library and with it's API you can start the server, send messages or register a middleware for listening incoming messages. Runtime message validation included.", "links": { - "repoUrl": "https://github.com/asyncapi/java-template" + "repoUrl": "https://github.com/asyncapi/nodejs-template" }, "filters": { - "language": [ - "javascript" - ], + "language": "javascript", "technology": [ - "Java" + "Node.js" ], "categories": [ "generator-template" @@ -795,15 +774,18 @@ } }, { - "title": "Node.js Multiprotocol Template", - "description": "This template generates a server using your AsyncAPI document. It supports multiple different protocols, like Kafka or MQTT. It is designed in the way that generated code is a library and with it's API you can start the server, send messages or register a middleware for listening incoming messages. Runtime message validation included.", + "title": "Java Spring Cloud Stream Template", + "description": "Java Spring Cloud Stream template for the AsyncAPI Generator", "links": { - "repoUrl": "https://github.com/asyncapi/nodejs-template" + "repoUrl": "https://github.com/asyncapi/java-spring-cloud-stream-template" }, "filters": { - "language": "javascript", + "language": [ + "javascript" + ], "technology": [ - "Node.js" + "Spring Cloud Streams", + "Maven" ], "categories": [ "generator-template" @@ -833,6 +815,24 @@ "hasCommercial": false, "isAsyncAPIOwner": true } + }, + { + "title": "Node.js Websockets Template", + "description": "Node.js WebSockets template for the AsyncAPI Generator. It showcases how from a single AsyncAPI document you can generate a server and a client at the same time.", + "links": { + "repoUrl": "https://github.com/asyncapi/nodejs-ws-template" + }, + "filters": { + "language": "javascript", + "technology": [ + "Node.js" + ], + "categories": [ + "generator-template" + ], + "hasCommercial": false, + "isAsyncAPIOwner": true + } } ] }, From 6bf75fb91a9c0ca9f9e14ecbc8c0fc6e3aa42acb Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Tue, 19 Nov 2024 08:42:21 +0100 Subject: [PATCH 58/91] chore: update meetings.json and newsrooom_videos.json (#3390) Co-authored-by: asyncapi-bot-eve %0ACo-authored-by: asyncapi-bot From bf857b33898a1ee2652b9b1494575edba178b175 Mon Sep 17 00:00:00 2001 From: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:50:31 +0200 Subject: [PATCH 59/91] feat: update banner description (#3412) --- components/campaigns/banners.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/campaigns/banners.ts b/components/campaigns/banners.ts index 7aad4527c83..8d15e19aad7 100644 --- a/components/campaigns/banners.ts +++ b/components/campaigns/banners.ts @@ -20,7 +20,7 @@ export const banners = [ title: 'AsyncAPI Conference', city: 'Paris Edition', dateLocation: '5th of December, 2024 | France, Paris', - cfaText: 'Get Your Tickets', + cfaText: 'Get Your Free Ticket', eventName: 'the AsyncAPI Conf in Paris', cfpDeadline: '2024-12-01T06:00:00Z', link: 'https://conference.asyncapi.com/#tickets' From d92638a3de8a21cc9ddf3b79b14ba964cac2a8ec Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Wed, 20 Nov 2024 07:21:07 +0100 Subject: [PATCH 60/91] docs(cli): update latest cli documentation (#3391) Co-authored-by: asyncapi-bot-eve %0ACo-authored-by: asyncapi-bot --- markdown/docs/tools/cli/usage.md | 61 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/markdown/docs/tools/cli/usage.md b/markdown/docs/tools/cli/usage.md index d10e249f190..502d70fff85 100644 --- a/markdown/docs/tools/cli/usage.md +++ b/markdown/docs/tools/cli/usage.md @@ -27,7 +27,7 @@ $ npm install -g @asyncapi/cli $ asyncapi COMMAND running command... $ asyncapi (--version) -@asyncapi/cli/2.8.0 linux-x64 node-v18.20.4 +@asyncapi/cli/2.8.1 linux-x64 node-v18.20.4 $ asyncapi --help [COMMAND] USAGE $ asyncapi COMMAND @@ -99,7 +99,7 @@ EXAMPLES $ asyncapi bundle ./asyncapi.yaml -o final-asyncapi.yaml --base ../public-api/main.yaml --baseDir ./social-media/comments-service ``` -_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/bundle.ts)_ +_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/bundle.ts)_ ## `asyncapi config` @@ -113,7 +113,7 @@ DESCRIPTION CLI config settings ``` -_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/index.ts)_ +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/index.ts)_ ## `asyncapi config analytics` @@ -133,7 +133,7 @@ DESCRIPTION Enable or disable analytics for metrics collection ``` -_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/analytics.ts)_ +_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/analytics.ts)_ ## `asyncapi config context` @@ -147,7 +147,7 @@ DESCRIPTION Manage short aliases for full paths to AsyncAPI documents ``` -_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/index.ts)_ +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/context/index.ts)_ ## `asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH` @@ -169,7 +169,7 @@ DESCRIPTION Add a context to the store ``` -_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/add.ts)_ +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/context/add.ts)_ ## `asyncapi config context current` @@ -186,7 +186,7 @@ DESCRIPTION Shows the current context that is being used ``` -_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/current.ts)_ +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/context/current.ts)_ ## `asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` @@ -207,7 +207,7 @@ DESCRIPTION Edit a context in the store ``` -_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/edit.ts)_ +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/context/edit.ts)_ ## `asyncapi config context init [CONTEXT-FILE-PATH]` @@ -230,7 +230,7 @@ DESCRIPTION Initialize context ``` -_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/init.ts)_ +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/context/init.ts)_ ## `asyncapi config context list` @@ -247,7 +247,7 @@ DESCRIPTION List all the stored contexts in the store ``` -_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/list.ts)_ +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/context/list.ts)_ ## `asyncapi config context remove CONTEXT-NAME` @@ -267,7 +267,7 @@ DESCRIPTION Delete a context from the store ``` -_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/remove.ts)_ +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/context/remove.ts)_ ## `asyncapi config context use CONTEXT-NAME` @@ -287,7 +287,7 @@ DESCRIPTION Set a context as current ``` -_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/context/use.ts)_ +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/context/use.ts)_ ## `asyncapi config versions` @@ -304,7 +304,7 @@ DESCRIPTION Show versions of AsyncAPI tools used ``` -_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/config/versions.ts)_ +_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/config/versions.ts)_ ## `asyncapi convert [SPEC-FILE]` @@ -332,7 +332,7 @@ DESCRIPTION Convert asyncapi documents older to newer versions or OpenAPI/postman-collection documents to AsyncAPI ``` -_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.8.0/src/commands/convert.ts)_ +_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v2.8.1/src/commands/convert.ts)_ ## `asyncapi diff OLD NEW` @@ -342,7 +342,7 @@ Find diff between two asyncapi files USAGE $ asyncapi diff OLD NEW [-h] [-f json|yaml|yml|md] [-t breaking|non-breaking|unclassified|all] [--markdownSubtype json|yaml|yml] [-o ] [--no-error] [-w] [--log-diagnostics] [--diagnostics-format - json|stylish|junit|html|text|teamcity|pretty] [--fail-severity error|warn|info|hint] + json|stylish|junit|html|text|teamcity|pretty] [--fail-severity error|warn|info|hint] [-o ] ARGUMENTS OLD old spec path, URL or context-name @@ -352,6 +352,7 @@ FLAGS -f, --format=