Repository: asyncapi/parser-js
Pull request #799 (2023-07-13 22:33:20)

chore: merge `master` into `next-major-spec`
> **Warning**
> This PR should be merged manually by using Merge with commit strategy. More info on https://github.com/asyncapi/community/issues/641


Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 41ab981..928ba9e 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -180,8 +180,18 @@
         "bug",
         "code"
       ]
+    },
+    {
+      "login": "Ruchip16",
+      "name": "Ruchi Pakhle",
+      "avatar_url": "https://avatars.githubusercontent.com/u/72685035?v=4",
+      "profile": "https://github.com/Ruchip16",
+      "contributions": [
+        "doc"
+      ]
     }
   ],
   "contributorsPerLine": 4,
-  "skipCi": false
+  "skipCi": false,
+  "commitType": "docs"
 }
diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml
index f4955c2..d4ba4a4 100644
--- a/.github/workflows/help-command.yml
+++ b/.github/workflows/help-command.yml
@@ -27,13 +27,13 @@ jobs:
               repo: context.repo.repo,
               body: `Hello, @${{ github.actor }}! 👋🏼 
 
-                    I'm Genie from the magic lamp. Looks like somebody needs a hand! 🆘 
+                    I'm 🧞🧞🧞 Genie 🧞🧞🧞 from the magic lamp. Looks like somebody needs a hand!
         
                     At the moment the following comments are supported in pull requests:
         
-                    - `/ready-to-merge` or `/rtm` - This comment will trigger automerge of PR in case all required checks are green, approvals in place and do-not-merge label is not added
-                    - `/do-not-merge` or `/dnm` - This comment will block automerging even if all conditions are met and ready-to-merge label is added
-                    - `/autoupdate` or `/au` - This comment will add `autoupdate` label to the PR and keeps your PR up-to-date to the target branch's future changes. Unless there is a merge conflict or it is a draft PR.`
+                    - \`/ready-to-merge\` or \`/rtm\` - This comment will trigger automerge of PR in case all required checks are green, approvals in place and do-not-merge label is not added
+                    - \`/do-not-merge\` or \`/dnm\` - This comment will block automerging even if all conditions are met and ready-to-merge label is added
+                    - \`/autoupdate\` or \`/au\` - This comment will add \`autoupdate\` label to the PR and keeps your PR up-to-date to the target branch's future changes. Unless there is a merge conflict or it is a draft PR.`
             })
 
   create_help_comment_issue:
@@ -51,10 +51,10 @@ jobs:
               repo: context.repo.repo,
               body: `Hello, @${{ github.actor }}! 👋🏼 
 
-              I'm Genie from the magic lamp. Looks like somebody needs a hand! 🆘 
+              I'm 🧞🧞🧞 Genie 🧞🧞🧞 from the magic lamp. Looks like somebody needs a hand!
   
               At the moment the following comments are supported in issues:
   
-              - `/good-first-issue {js | ts | java | go | docs | design | ci-cd} ` or `/gfi {js | ts | java | go | docs | design | ci-cd} ` - label an issue as a `good first issue`.
-              example: `/gfi js` or `/good-first-issue ci-cd`
-            })
+              - \`/good-first-issue {js | ts | java | go | docs | design | ci-cd}\` or \`/gfi {js | ts | java | go | docs | design | ci-cd}\` - label an issue as a \`good first issue\`.
+              example: \`/gfi js\` or \`/good-first-issue ci-cd\``
+            })
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 2c72215..943fd79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
 node_modules
 .vscode
 .DS_Store
-/docs
+/docs/api.md
 /coverage
 /lib
 /esm
diff --git a/.sonarcloud.properties b/.sonarcloud.properties
index 1b41ae5..98a487f 100644
--- a/.sonarcloud.properties
+++ b/.sonarcloud.properties
@@ -1,2 +1,3 @@
 # Disable specific duplicate code since it would introduce more complexity to reduce it.
-sonar.cpd.exclusions=src/models/**/*.ts
\ No newline at end of file
+sonar.cpd.exclusions=src/models/**/*.ts
+sonar.exclusions=test/**/*
diff --git a/README.md b/README.md
index d1e9dc9..015f1ce 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,10 @@ Updated bundle for the browser is always attached to the GitHub Release.
 > **Warning**
 > This package has rewrote the Model API (old one) to [Intent API](https://github.com/asyncapi/parser-api). If you still need to use the old API, read the [Convert to the old API](#convert-to-the-old-api) section.
 
+> **Note**
+> Read the [migration guide from v1 to v2](./docs/migrations/v1-to-v2.md).
+
+
 <!-- toc is generated with GitHub Actions do not remove toc markers -->
 
 <!-- toc -->
@@ -28,6 +32,7 @@ Updated bundle for the browser is always attached to the GitHub Release.
   * [Example with performing actions on file source](#example-with-performing-actions-on-file-source)
   * [Example with stringify and unstringify parsed document](#example-with-stringify-and-unstringify-parsed-document)
 - [API documentation](#api-documentation)
+- [Spectral rulesets](#spectral-rulesets)
 - [Using in the browser/SPA applications](#using-in-the-browserspa-applications)
 - [Custom schema parsers](#custom-schema-parsers)
   * [Official supported custom schema parsers](#official-supported-custom-schema-parsers)
@@ -77,9 +82,7 @@ Check out the [examples](#examples) of using the above mentioned functionalities
 
 ```ts
 import { Parser } from '@asyncapi/parser';
-
 const parser = new Parser();
-
 const { document } = await parser.parse(`
   asyncapi: '2.4.0'
   info:
@@ -225,6 +228,43 @@ Additionally to all the methods declared in the [Parser-API](https://github.com/
 - `jsonPath()` which returns the JSON Path of the given object.
 - `meta()` which returns the metadata of a given object, like a parsed AsyncAPI Document.
 
+## Spectral rulesets
+
+[Spectral](https://github.com/stoplightio/spectral) powers the validation of AsyncAPI documents within ParserJS. For this reason, it is possible to use your rulesets/rules or overwrite existing ones, passing the `ruleset` option to the Parser instance: 
+
+```ts
+import { Parser, stringify, unstringify } from '@asyncapi/parser';
+const parser = new Parser({
+  ruleset: {
+    extends: [],
+    rules: {
+      'asyncapi-defaultContentType': 'off',
+      'asyncapi-termsOfService': {
+        description: 'Info "termsOfService" should be present and non-empty string.',
+        recommended: true,
+        given: '$',
+        then: {
+          field: 'info.termsOfService',
+          function: 'truthy',
+        },
+      },
+    }
+  }
+});
+// The returned diagnostics object will include `asyncapi-termsOfService` diagnostic with `warning` (`recommended: true`) severity because `$.info.termsOfService` is not defined in the following AsyncAPI document.
+// On the other hand, since we turned it off, we won't see the diagnostics related to the `defaultContentType` field.
+const diagnostics = await parser.validate(`
+  asyncapi: '2.0.0'
+  info:
+    title: Example AsyncAPI specification
+    version: '0.1.0'
+  channels: {}
+`);
+```
+
+[ParserJS has some built-in Spectral rulesets](./docs/ruleset) that validate AsyncAPI documents and inform on good practices. 
+
+
 ## Using in the browser/SPA applications
 
 The package contains a built-in version of the parser. To use it, you need to import the parser into the HTML file as below:
@@ -393,7 +433,6 @@ const oldAsyncAPIDocument = convertToOldAPI(document);
 ## Notes
 
 ### Using with Webpack
-
 Versions `<5` of Webpack should handle bundling without problems. Due to the fact that Webpack 5 no longer does fallbacks to native NodeJS modules by default we need to install `buffer` package and add fallbacks:
 
 ```js
@@ -431,8 +470,16 @@ moduleNameMapper: {
 1. Make sure you are using Node.js 16 or higher and npm 8 or higher
 2. Write code and tests.
 3. Make sure all tests pass `npm test`
+
+For Windows environments, some tests might still fail randomly during local development even when you made no changes to the tests. The reason for this from file endings are different than expected and this comes from Git defaulting to an unexpected file ending. If you encounter this issue you can run the following commands to set Git to use the expected one:
+```
+git config --global core.autocrlf false
+git config --global core.eol lf
+```
+
 4. Make sure code is well formatted and secure `npm run lint`
 
+
 ## Contributing
 
 Read [CONTRIBUTING](https://github.com/asyncapi/.github/blob/master/CONTRIBUTING.md) guide.
@@ -447,28 +494,31 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
 <table>
   <tbody>
     <tr>
-      <td align="center"><a href="http://www.fmvilas.com/"><img src="https://avatars3.githubusercontent.com/u/242119?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fran Méndez</b></sub></a><br /><a href="#question-fmvilas" title="Answering Questions">💬</a> <a href="https://github.com/asyncapi/parser-js/issues?q=author%3Afmvilas" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=fmvilas" title="Code">💻</a> <a href="https://github.com/asyncapi/parser-js/commits?author=fmvilas" title="Documentation">📖</a> <a href="#ideas-fmvilas" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-fmvilas" title="Maintenance">🚧</a> <a href="#plugin-fmvilas" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/asyncapi/parser-js/pulls?q=is%3Apr+reviewed-by%3Afmvilas" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/asyncapi/parser-js/commits?author=fmvilas" title="Tests">⚠️</a></td>
-      <td align="center"><a href="https://resume.github.io/?derberg"><img src="https://avatars1.githubusercontent.com/u/6995927?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lukasz Gornicki</b></sub></a><br /><a href="#question-derberg" title="Answering Questions">💬</a> <a href="https://github.com/asyncapi/parser-js/issues?q=author%3Aderberg" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=derberg" title="Code">💻</a> <a href="https://github.com/asyncapi/parser-js/commits?author=derberg" title="Documentation">📖</a> <a href="#ideas-derberg" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-derberg" title="Maintenance">🚧</a> <a href="https://github.com/asyncapi/parser-js/pulls?q=is%3Apr+reviewed-by%3Aderberg" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/asyncapi/parser-js/commits?author=derberg" title="Tests">⚠️</a></td>
-      <td align="center"><a href="https://github.com/jonaslagoni"><img src="https://avatars1.githubusercontent.com/u/13396189?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonas Lagoni</b></sub></a><br /><a href="#question-jonaslagoni" title="Answering Questions">💬</a> <a href="https://github.com/asyncapi/parser-js/issues?q=author%3Ajonaslagoni" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=jonaslagoni" title="Code">💻</a> <a href="#ideas-jonaslagoni" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/asyncapi/parser-js/pulls?q=is%3Apr+reviewed-by%3Ajonaslagoni" title="Reviewed Pull Requests">👀</a></td>
-      <td align="center"><a href="https://github.com/magicmatatjahu"><img src="https://avatars2.githubusercontent.com/u/20404945?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Maciej Urbańczyk</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/issues?q=author%3Amagicmatatjahu" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=magicmatatjahu" title="Code">💻</a> <a href="https://github.com/asyncapi/parser-js/pulls?q=is%3Apr+reviewed-by%3Amagicmatatjahu" title="Reviewed Pull Requests">👀</a></td>
+      <td align="center" valign="top" width="25%"><a href="http://www.fmvilas.com/"><img src="https://avatars3.githubusercontent.com/u/242119?v=4?s=100" width="100px;" alt="Fran Méndez"/><br /><sub><b>Fran Méndez</b></sub></a><br /><a href="#question-fmvilas" title="Answering Questions">💬</a> <a href="https://github.com/asyncapi/parser-js/issues?q=author%3Afmvilas" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=fmvilas" title="Code">💻</a> <a href="https://github.com/asyncapi/parser-js/commits?author=fmvilas" title="Documentation">📖</a> <a href="#ideas-fmvilas" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-fmvilas" title="Maintenance">🚧</a> <a href="#plugin-fmvilas" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/asyncapi/parser-js/pulls?q=is%3Apr+reviewed-by%3Afmvilas" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/asyncapi/parser-js/commits?author=fmvilas" title="Tests">⚠️</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://resume.github.io/?derberg"><img src="https://avatars1.githubusercontent.com/u/6995927?v=4?s=100" width="100px;" alt="Lukasz Gornicki"/><br /><sub><b>Lukasz Gornicki</b></sub></a><br /><a href="#question-derberg" title="Answering Questions">💬</a> <a href="https://github.com/asyncapi/parser-js/issues?q=author%3Aderberg" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=derberg" title="Code">💻</a> <a href="https://github.com/asyncapi/parser-js/commits?author=derberg" title="Documentation">📖</a> <a href="#ideas-derberg" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-derberg" title="Maintenance">🚧</a> <a href="https://github.com/asyncapi/parser-js/pulls?q=is%3Apr+reviewed-by%3Aderberg" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/asyncapi/parser-js/commits?author=derberg" title="Tests">⚠️</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/jonaslagoni"><img src="https://avatars1.githubusercontent.com/u/13396189?v=4?s=100" width="100px;" alt="Jonas Lagoni"/><br /><sub><b>Jonas Lagoni</b></sub></a><br /><a href="#question-jonaslagoni" title="Answering Questions">💬</a> <a href="https://github.com/asyncapi/parser-js/issues?q=author%3Ajonaslagoni" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=jonaslagoni" title="Code">💻</a> <a href="#ideas-jonaslagoni" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/asyncapi/parser-js/pulls?q=is%3Apr+reviewed-by%3Ajonaslagoni" title="Reviewed Pull Requests">👀</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/magicmatatjahu"><img src="https://avatars2.githubusercontent.com/u/20404945?v=4?s=100" width="100px;" alt="Maciej Urbańczyk"/><br /><sub><b>Maciej Urbańczyk</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/issues?q=author%3Amagicmatatjahu" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=magicmatatjahu" title="Code">💻</a> <a href="https://github.com/asyncapi/parser-js/pulls?q=is%3Apr+reviewed-by%3Amagicmatatjahu" title="Reviewed Pull Requests">👀</a></td>
+    </tr>
+    <tr>
+      <td align="center" valign="top" width="25%"><a href="https://www.inmensia.com/"><img src="https://avatars2.githubusercontent.com/u/6494060?v=4?s=100" width="100px;" alt="Juan Mellado"/><br /><sub><b>Juan Mellado</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=jcmellado" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://www.jamescrowley.net/"><img src="https://avatars1.githubusercontent.com/u/509533?v=4?s=100" width="100px;" alt="James Crowley"/><br /><sub><b>James Crowley</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=jamescrowley" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/rmelian"><img src="https://avatars3.githubusercontent.com/u/4565267?v=4?s=100" width="100px;" alt="raisel melian"/><br /><sub><b>raisel melian</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=rmelian" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/DanielChuDC"><img src="https://avatars3.githubusercontent.com/u/52316624?v=4?s=100" width="100px;" alt="danielchu"/><br /><sub><b>danielchu</b></sub></a><br /><a href="#infra-DanielChuDC" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/asyncapi/parser-js/commits?author=DanielChuDC" title="Code">💻</a></td>
     </tr>
     <tr>
-      <td align="center"><a href="https://www.inmensia.com/"><img src="https://avatars2.githubusercontent.com/u/6494060?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juan Mellado</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=jcmellado" title="Code">💻</a></td>
-      <td align="center"><a href="https://www.jamescrowley.net/"><img src="https://avatars1.githubusercontent.com/u/509533?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Crowley</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=jamescrowley" title="Code">💻</a></td>
-      <td align="center"><a href="https://github.com/rmelian"><img src="https://avatars3.githubusercontent.com/u/4565267?v=4?s=100" width="100px;" alt=""/><br /><sub><b>raisel melian</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=rmelian" title="Code">💻</a></td>
-      <td align="center"><a href="https://github.com/DanielChuDC"><img src="https://avatars3.githubusercontent.com/u/52316624?v=4?s=100" width="100px;" alt=""/><br /><sub><b>danielchu</b></sub></a><br /><a href="#infra-DanielChuDC" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/asyncapi/parser-js/commits?author=DanielChuDC" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://www.linkedin.com/in/jbreitenbaumer/"><img src="https://avatars3.githubusercontent.com/u/683438?v=4?s=100" width="100px;" alt="Jürgen B."/><br /><sub><b>Jürgen B.</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=juergenbr" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/aeworxet"><img src="https://avatars.githubusercontent.com/u/16149591?v=4?s=100" width="100px;" alt="Viacheslav Turovskyi"/><br /><sub><b>Viacheslav Turovskyi</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=aeworxet" title="Tests">⚠️</a> <a href="https://github.com/asyncapi/parser-js/commits?author=aeworxet" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/KhudaDad414"><img src="https://avatars.githubusercontent.com/u/32505158?v=4?s=100" width="100px;" alt="Khuda Dad Nomani"/><br /><sub><b>Khuda Dad Nomani</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=KhudaDad414" title="Code">💻</a> <a href="https://github.com/asyncapi/parser-js/issues?q=author%3AKhudaDad414" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=KhudaDad414" title="Tests">⚠️</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/aayushmau5"><img src="https://avatars.githubusercontent.com/u/54525741?v=4?s=100" width="100px;" alt="Aayush Kumar Sahu"/><br /><sub><b>Aayush Kumar Sahu</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=aayushmau5" title="Tests">⚠️</a></td>
     </tr>
     <tr>
-      <td align="center"><a href="https://www.linkedin.com/in/jbreitenbaumer/"><img src="https://avatars3.githubusercontent.com/u/683438?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jürgen B.</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=juergenbr" title="Code">💻</a></td>
-      <td align="center"><a href="https://github.com/aeworxet"><img src="https://avatars.githubusercontent.com/u/16149591?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Viacheslav Turovskyi</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=aeworxet" title="Tests">⚠️</a> <a href="https://github.com/asyncapi/parser-js/commits?author=aeworxet" title="Code">💻</a></td>
-      <td align="center"><a href="https://github.com/KhudaDad414"><img src="https://avatars.githubusercontent.com/u/32505158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Khuda Dad Nomani</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=KhudaDad414" title="Code">💻</a> <a href="https://github.com/asyncapi/parser-js/issues?q=author%3AKhudaDad414" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=KhudaDad414" title="Tests">⚠️</a></td>
-      <td align="center"><a href="https://github.com/aayushmau5"><img src="https://avatars.githubusercontent.com/u/54525741?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aayush Kumar Sahu</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=aayushmau5" title="Tests">⚠️</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/JQrdan"><img src="https://avatars.githubusercontent.com/u/25624685?v=4?s=100" width="100px;" alt="Jordan Tucker"/><br /><sub><b>Jordan Tucker</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=JQrdan" title="Tests">⚠️</a> <a href="https://github.com/asyncapi/parser-js/commits?author=JQrdan" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/vishesh13byte"><img src="https://avatars.githubusercontent.com/u/66796715?v=4?s=100" width="100px;" alt="vishesh13byte"/><br /><sub><b>vishesh13byte</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=vishesh13byte" title="Tests">⚠️</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://iamdevelopergirl.github.io/Website-With-Animations/"><img src="https://avatars.githubusercontent.com/u/16351809?v=4?s=100" width="100px;" alt="Elakya"/><br /><sub><b>Elakya</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=iamdevelopergirl" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://schwank.cc"><img src="https://avatars.githubusercontent.com/u/8232196?v=4?s=100" width="100px;" alt="Dominik Schwank"/><br /><sub><b>Dominik Schwank</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/issues?q=author%3Adschwank" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=dschwank" title="Code">💻</a></td>
     </tr>
     <tr>
-      <td align="center"><a href="https://github.com/JQrdan"><img src="https://avatars.githubusercontent.com/u/25624685?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jordan Tucker</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=JQrdan" title="Tests">⚠️</a> <a href="https://github.com/asyncapi/parser-js/commits?author=JQrdan" title="Code">💻</a></td>
-      <td align="center"><a href="https://github.com/vishesh13byte"><img src="https://avatars.githubusercontent.com/u/66796715?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vishesh13byte</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=vishesh13byte" title="Tests">⚠️</a></td>
-      <td align="center"><a href="https://iamdevelopergirl.github.io/Website-With-Animations/"><img src="https://avatars.githubusercontent.com/u/16351809?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Elakya</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=iamdevelopergirl" title="Code">💻</a></td>
-      <td align="center"><a href="https://schwank.cc"><img src="https://avatars.githubusercontent.com/u/8232196?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dominik Schwank</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/issues?q=author%3Adschwank" title="Bug reports">🐛</a> <a href="https://github.com/asyncapi/parser-js/commits?author=dschwank" title="Code">💻</a></td>
+      <td align="center" valign="top" width="25%"><a href="https://github.com/Ruchip16"><img src="https://avatars.githubusercontent.com/u/72685035?v=4?s=100" width="100px;" alt="Ruchi Pakhle"/><br /><sub><b>Ruchi Pakhle</b></sub></a><br /><a href="https://github.com/asyncapi/parser-js/commits?author=Ruchip16" title="Documentation">📖</a></td>
     </tr>
   </tbody>
 </table>
diff --git a/docs/migrations/v1-to-v2.md b/docs/migrations/v1-to-v2.md
new file mode 100644
index 0000000..0d5b785
--- /dev/null
+++ b/docs/migrations/v1-to-v2.md
@@ -0,0 +1,288 @@
+# Migrating from v1 to v2
+
+## TL;DR
+
+- The parser API has been rewritten from the ground up. It's now based on user intents instead of a 1:1 map to the spec. [Read more](#new-intent-api).
+- Source code has been rewritten in TypeScript and ESM. This makes the package fully [tree-shakable](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking). [Read more](#typescript-and-esm).
+- The parser is now exposed as a class, making it possible to have multiple parser instances with different configurations. [Read more](#parser-class).
+- It validates AsyncAPI documents using [Spectral](https://github.com/stoplightio/spectral). This enables better validation and introduces linting capabilities. [Read more](#Powered-by-Spectral).
+- API Changes
+  - Introduces validation without parsing via the `.validate()` method. [Read more](#validate-method).
+  - The `.parse()` method now also returns diagnostics (errors, warnings, and bits of advice). [Read more](#parse-method).
+  - The `parseFromUrl()` method has been deprecated in favor of the `fromURL` standalone function. [Read more](#parseFromUrl-is-now-deprecated).
+  - Custom parsers now have a `validate()` method. [Read more](#new-custom-schema-parser-interface).
+  - The way to pass custom `$ref` resolvers has changed. [Read more](#custom-reference-resolvers).
+  - Stringify and unstringify the parsed document is now a separate functionality. [Read more](#standalone-stringify-and-unstringify-functionality).
+  - If there is a need to use an old version of the API, the Parser provides the `convertToOldAPI` functionality. [Read more](#convert-new-api-to-the-old-one).
+
+## New Intent API
+
+The old Document API based 1:1 on AsyncAPI Specification has been rewritten to support the new so-called [Parser API](https://github.com/asyncapi/parser-api), which makes it easier to operate on the document and retrieve collections of needed objects from it. Due to the fact that the new API does not stick firmly to the AsyncAPI Specification file structure, it allows for better integration with future versions of AsyncAPI. The user does not need to know the new API against the new version of AsyncAPI - all methods will remain the same with the inclusion of new/deprecated fields. Also new API has been enhanced with some additional functionality like retrieving the JSON Path of the object using the `.jsonPath()` method etc.
+
+## TypeScript and ESM
+
+The source code of the package has been rewritten to ESM (EcmaScript modules). This enables [tree-shaking](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking) and much better integration in browser-based environments. In addition, the package exposes a `cjs` directory containing the CommonJS version of the parser, for compatibility with older environments. Both versions have support for Typescript types.
+
+## Powered by Spectral
+
+[Spectral](https://github.com/stoplightio/spectral) is an open-source API linting tool by [Stoplight](https://stoplight.io/) that allows users to create custom style guides to enforce validations on API design automatically. This allows for better validation and shows all errors in one validation process - the old parser had a huge problem with this. In addition, there is the ability to show good practices though like defining `operationId` for each operation or enforcing things that are optional but required for a project or company (API governance). Together with [Stoplight](https://stoplight.io/), we have an official partnership and will be improving integration as well as [Spectral](https://github.com/stoplightio/spectral) itself for better quality validation of AsyncAPI documents.
+
+## Custom reference resolvers
+
+In v1, there was an option to pass a custom resolver to the reference resolver ([json-schema-ref-parser](https://github.com/APIDevTools/json-schema-ref-parser)), which allowed custom logic for retrieving reference data - e.g. for mapping data located on the external resources to local data (used by `--map-base-url` flag for [Generator](https://github.com/asyncapi/generator#cli-usage)'s CLI). The current logic is similar, but differs in a few things:
+
+- custom resolver has to be passed in the `Parser`'s constructor, in the `__unstable.resolver.resolvers` array.
+- must define what schema it supports, such as `https`, or `file`.
+
+```ts
+import { Parser } from '@asyncapi/parser';
+
+const parser = new Parser({
+  __unstable: {
+    resolver: {
+      resolvers: [
+        {
+          schema: 'customProtocol',
+          read(uri) {
+            if (uri.path() === '/someRef') {
+              return '{"someRef": "value"}';
+            }
+            return '{"anotherRef": "value"}';
+          },
+        }
+      ]
+    }
+  }
+});
+
+const asyncApiDocument = {
+  asyncapi: '2.5.0',
+  info: {
+    title: 'Example AsyncApi document',
+    version: '1.0',
+  },
+  channels: {
+    someChannel: {
+      publish: {
+        operationId: 'publish',
+        message: {
+          payload: {
+            $ref: 'customProtocol:///someRef'
+          }
+        }
+      },
+      subscribe: {
+        operationId: 'subscribe',
+        message: {
+          payload: {
+            $ref: 'customProtocol:///anotherRef'
+          }
+        }
+      },
+    }
+  },
+};
+const { document } = await parser.parse(asyncApiDocument);
+// document.json().channels.someChannel.publish.message.payload == { "someRef": "value" };
+// document.json().channels.someChannel.subscribe.message.payload == { "anotherRef": "value" };
+```
+
+> **Note**
+> As [Spectral](https://github.com/stoplightio/spectral) natively does not support multiple custom resolvers, `Parser` implements a wrapper for existing logic in [Spectral](https://github.com/stoplightio/spectral), and due to that fact, custom resolvers need to be passed with `__unstable.resolver.resolvers` array. If [Spectral](https://github.com/stoplightio/spectral) will support out-in-the-box multiple custom resolvers we will include this logic permanently in the `Parser`, currently it is in the "unstable" phase.
+
+### New Custom Schema Parser interface
+
+The custom parser interface has been changed to shape including methods:
+
+- `validate` (**NEW FUNCTION**) - the function that validates (its syntax) used schema.
+- `parse` - the function that parses the given schema to the [AsyncAPI Schema Format](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#schemaObject).
+- `getMimeTypes` - the function that returns the list of mime types that will be used as the `schemaFormat` property to determine the mime type of a given schema.
+
+Example:
+    
+```ts
+export default {
+  validate(input) { ... },
+  parse(input) { ... },
+  getMimeTypes() {
+    return [
+      'application/vnd.custom.type;version=1.0.0',
+      'application/vnd.custom.type+json;version=1.0.0',
+    ]
+  }
+}
+```
+
+Before parsing/validating an AsyncAPI document with a parser, register the additional custom schema parser like in the old parser:
+
+```ts
+import { Parser } from '@asyncapi/parser';
+import myCustomSchemaParser from './my-custom-schema-parser';
+
+const parser = new Parser();
+parser.registerSchemaParser(myCustomSchemaParser);
+```
+
+## Convert new API to the old one
+
+Because a large part of the AsyncAPI tooling ecosystem uses a Parser with the old API and rewriting the tool for the new one can be time-consuming and difficult, the package exposes the `convertToOldAPI()` function to convert the new API to the old one:
+
+```js
+import { Parser, convertToOldAPI } from '@asyncapi/parser';
+
+const parser = new Parser();
+const { document } = parser.parse(...);
+const oldAsyncAPIDocument = convertToOldAPI(document);
+```
+
+> **Warning**
+> The old API will be supported only for a certain period. The target date for turning off support of the old API is around the end of March 2024.
+
+If there is a need to convert an existing instance of the old API to the new one, the library provides the `convertToNewAPI` function:
+
+```js
+import { Parser, convertToNewAPI } from '@asyncapi/parser';
+
+const newAsyncAPIDocument = convertToNewAPI(oldDocument);
+```
+
+> **Warning**
+> Due to the fact that the new Parser validates the document more restrictively, it may be that a parsed document in the old way will not work 100% in accordance with the new API.
+
+## Important API changes
+
+These are all the exposed API changes and how you interact with the parser. For how to interact with the AsyncAPI document, checkout [the intent API](#new-intent-api).
+
+### Parser class
+In v1 we had only one instance of the Parser because it was global. The new version exposes the Parser class, so now it's possible to have several different instances of Parser with different configurations.
+
+```ts
+import { Parser } from '@asyncapi/parser';
+
+const parser = new Parser();
+
+const { document } = await parser.parse(`...AsyncAPI document`, ...?options);
+```
+
+### `.parse()` method
+
+The function `.parse()` returns not only parsed AsyncAPi `document` but also possible `diagnostics` array based on validation configuration:
+
+```ts
+import { Parser } from '@asyncapi/parser';
+
+const parser = new Parser();
+
+const { document, diagnostics } = await parser.parse(`
+  asyncapi: '2.4.0'
+  info:
+    title: Example AsyncAPI specification
+    version: '0.1.0'
+  channels:
+    example-channel:
+      subscribe:
+        message:
+          payload:
+            type: object
+            properties:
+              exampleField:
+                type: string
+              exampleNumber:
+                type: number
+              exampleDate:
+                type: string
+                format: date-time
+`);
+
+if (document) {
+  // => Example AsyncAPI specification
+  console.log(document.info().title());
+}
+```
+
+### `.validate()` method
+
+In v2 it brings a new `.validate()` method (exposed by Parser class) which only validates the AsyncAPI document based on [Spectral](https://github.com/stoplightio/spectral) configuration. This is a useful feature for cases when we only need to know if a given AsyncAPI document is valid or not.
+
+```ts
+import { Parser } from '@asyncapi/parser';
+
+const parser = new Parser();
+
+// One of the diagnostics will contain an error regarding an unsupported version of AsyncAPI (2.1.37)
+const diagnostics = await parser.validate(`
+  asyncapi: '2.1.37'
+  info:
+    title: Example AsyncAPI specification
+    version: '0.1.0'
+  channels:
+    example-channel:
+      subscribe:
+        message:
+          payload:
+            type: object
+            properties:
+              exampleField:
+                type: string
+              exampleNumber:
+                type: number
+              exampleDate:
+                type: string
+                format: date-time
+`);
+```
+
+### `parseFromUrl()` is now deprecated
+
+The `parseFromUrl()` function has been deprecated in favor of the new `fromURL` function:
+
+```ts
+import { Parser, fromURL } from '@asyncapi/parser';
+
+const parser = new Parser();
+
+const { document } = fromURL(parser, 'https://my.server.com/example-asyncapi.yaml', ...?fetching options).parse();
+// `validate` function is also available:
+// fromURL(parser, ...).validate();
+```
+
+> **Note**
+> Parser exposes a similar function to handle file system sources - `fromFile`.
+
+### Standalone stringify and un-stringify functionality
+
+The ability to stringify and un-stringify (parsing of stringified AsyncAPI document) was possible as methods in the old `AsyncAPiDocument` instance. Currently, both functions are standalone:
+
+```ts
+import { Parser, stringify, unstringify } from '@asyncapi/parser';
+
+const parser = new Parser();
+
+const { document } = await parser.parse(`
+  asyncapi: '2.4.0'
+  info:
+    title: Example AsyncAPI specification
+    version: '0.1.0'
+  channels:
+    example-channel:
+      subscribe:
+        message:
+          payload:
+            type: object
+            properties:
+              exampleField:
+                type: string
+              exampleNumber:
+                type: number
+              exampleDate:
+                type: string
+                format: date-time
+`);
+
+if (document) {
+  // stringify function returns string type
+  const stringifiedDocument = stringify(document);
+  // unstringify function returns new AsyncAPIDocument instance
+  const unstringifiedDocument = unstringify(stringifiedDocument);
+}
+```
diff --git a/docs/ruleset/README.md b/docs/ruleset/README.md
new file mode 100644
index 0000000..44f70a1
--- /dev/null
+++ b/docs/ruleset/README.md
@@ -0,0 +1,11 @@
+# AsyncAPI Spectral Ruleset
+
+ParserJS has some built-in Spectral rulesets that validate AsyncAPI documents and inform about good practices. Those are:
+
+- [Core Ruleset](./core-ruleset.md) - validates the overall structure of AsyncAPI documents (applied for each version, starting from `2.0.0`).
+- [Recommended Ruleset](./recommended-ruleset.md) - verifies good practices within AsyncAPI documents structure (applied for each version, starting from `2.0.0`).
+- [v2 Core Ruleset](./v2-core-ruleset.md) - validates the overall structure of AsyncAPI version `2.x.x` documents.
+- [v2 Recommended Ruleset](./v2-recommended-ruleset.md) - verifies good practices within AsyncAPI version `2.x.x` documents.
+
+> **Note**
+> The described rulesets are similar to the one found at https://github.com/stoplightio/spectral/blob/develop/docs/reference/asyncapi-rules.md. They have been adapted under the rights of the Apache-2.0 license.
diff --git a/docs/ruleset/core-ruleset.md b/docs/ruleset/core-ruleset.md
new file mode 100644
index 0000000..6ce48bb
--- /dev/null
+++ b/docs/ruleset/core-ruleset.md
@@ -0,0 +1,118 @@
+# AsyncAPI Core Ruleset
+
+The core ruleset validates the overall structure of AsyncAPI documents.
+
+> **Note**
+> These rules will apply to each version, starting from `2.0.0`.
+
+## Rules
+
+### asyncapi-is-asyncapi
+
+The input must be a document with a supported version of AsyncAPI.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+...
+```
+
+#### Bad example
+
+```yaml
+openapi: 3.1.0
+...
+```
+
+```yaml
+asyncapi: 2.1.37
+...
+```
+
+### asyncapi-latest-version
+
+Checking if the AsyncAPI document is using the latest version.
+
+#### Good example
+
+Assuming the latest version is `2.6.0`:
+
+```yaml
+asyncapi: 2.6.0
+...
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.5.0
+...
+```
+
+### asyncapi-document-resolved
+
+Checking if the AsyncAPI document has a valid resolved (with resolved references) structure based on the specification's JSON Schema.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+channels:
+  user/signup:
+    publish:
+      message:
+        $ref: '#/components/messages/user'
+components:
+  messages:
+    user: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+```
+
+### asyncapi-document-unresolved
+
+Checking if the AsyncAPI document has a valid unresolved (with unresolved references) structure based on the specification's JSON Schema.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+channels:
+  user/signup:
+    publish:
+      message:
+        $ref: '#/components/messages/user'
+components:
+  messages:
+    user: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+channels:
+  user/signup:
+    publish:
+      $ref: '#/components/x-operations/someOperation'
+components:
+  'x-operations':
+    someOperation: {}
+```
diff --git a/docs/ruleset/recommended-ruleset.md b/docs/ruleset/recommended-ruleset.md
new file mode 100644
index 0000000..1cac29f
--- /dev/null
+++ b/docs/ruleset/recommended-ruleset.md
@@ -0,0 +1,238 @@
+# AsyncAPI Recommended Ruleset
+
+The recommended ruleset verifies good practices within AsyncAPI documents structure.
+
+> **Note**
+> These rules will apply to each version, starting from `2.0.0`.
+
+## Rules
+
+### asyncapi-id
+
+AsyncAPI document should have an `id` field.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+id: 'urn:some:id'
+...
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+...
+```
+
+### asyncapi-defaultContentType
+
+AsyncAPI document should have a `defaultContentType` field.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+defaultContentType: 'application/json'
+...
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+...
+```
+
+### asyncapi-info-description
+
+Info `description` should be present and a non-empty string.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+  description: Description of awesome AsyncAPI document
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+```
+
+### asyncapi-info-contact
+
+Info object should have a `contact` object.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+  contact: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+```
+
+### asyncapi-info-contact-properties
+
+Contact object should have `name`, `url`, and `email` fields.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+  contact:
+    name: API Support
+    url: www.asyncapi.com/support
+    email: support@asyncapi.com
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+  contact:
+    name: API Support
+```
+
+### asyncapi-info-license
+
+Info object should have a `license` object.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+  license: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+```
+
+### asyncapi-info-license-url
+
+License object should have a `url` field.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+  license:
+    name: Apache 2.0
+    url: https://www.apache.org/licenses/LICENSE-2.0.html
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+  license:
+    name: Apache 2.0
+```
+
+### asyncapi-servers
+
+AsyncAPI document should have a non-empty `servers` object.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  development:
+    url: development.gigantic-server.com
+    description: Development server
+    protocol: kafka
+    protocolVersion: '1.0.0'
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+```
+
+### asyncapi-unused-component
+
+A potentially unused component has been detected in the AsyncAPI document.
+
+> **Warning**
+> This rule may identify false positives when linting a specification that acts as a library (a container storing reusable objects, leveraged by other specifications that reference those objects).
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+channels:
+  user/signup:
+    publish:
+      message:
+        $ref: '#/components/messages/user'
+components:
+  messages:
+    user: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+channels:
+  user/signup:
+    publish:
+      message: {...}
+components:
+  messages:
+    unusedMessage: {...}
+```
diff --git a/docs/ruleset/v2-core-ruleset.md b/docs/ruleset/v2-core-ruleset.md
new file mode 100644
index 0000000..94b9157
--- /dev/null
+++ b/docs/ruleset/v2-core-ruleset.md
@@ -0,0 +1,581 @@
+# AsyncAPI v2 Core Ruleset
+
+The core ruleset, which validates the overall structure of the `2.x.x` specifications.
+
+> **Note**
+> These rules will only apply to AsyncAPI `2.x.x` documents.
+
+## Rules
+
+### asyncapi2-server-security
+
+Server `security` values must match a scheme defined in the `$.components.securitySchemes` object. It also checks if there are `oauth2` scopes that have been defined for the given security.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.mosquitto.org
+    security:
+      - authKey: []
+components:
+  securitySchemes:
+    authKey: {...}
+```
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.mosquitto.org
+    security:
+      - oauth2: ['write:user', 'read:user']
+components:
+  securitySchemes:
+    oauth2:
+      flows:
+        implicit:
+          scopes:
+            'write:user': '...',
+            'read:user': '...',
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.mosquitto.org
+    security:
+      - notDefined: []
+components:
+  securitySchemes:
+    authKey: {...}
+```
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.mosquitto.org
+    security:
+      - oauth2: ['write:user', 'not:defined']
+components:
+  securitySchemes:
+    oauth2:
+      flows:
+        implicit:
+          scopes:
+            'write:user': '...',
+            'read:user': '...',
+```
+
+### asyncapi2-server-variables
+
+All server URL variables should be defined in the `variables` object of the server. They should also not contain redundant variables that do not exist in the server address.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.{variable}.mosquitto.org
+    variables:
+      variable: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.{variable}.mosquitto.org
+```
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.{variable}.mosquitto.org
+    variables:
+      variable: {...}
+      redundantVariable: {...}
+```
+
+### asyncapi2-channel-parameters
+
+All channel parameters should be defined in the `parameters` object of the channel. They should also not contain redundant parameters that do not exist in the channel address.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+channels: 
+  'users/{userId}/signedUp':
+    parameters:
+      userId: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+channels: 
+  'users/{userId}/signedUp': {}
+```
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+channels: 
+  'users/{userId}/signedUp':
+    parameters:
+      userId: {...}
+      redundantParameter: {...}
+```
+
+### asyncapi2-channel-servers
+
+Channel servers must be defined in the `servers` object.
+
+#### Good example
+
+```yaml
+asyncapi: 2.2.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.{variable}.mosquitto.org
+    variables:
+      variable: {...}
+channels:
+  users/signedUp:
+    servers:
+      - production
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.2.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.{variable}.mosquitto.org
+    variables:
+      variable: {...}
+channels:
+  users/signedUp:
+    servers:
+      - development
+```
+
+### asyncapi2-operation-operationId-uniqueness
+
+`operationId` must be unique across all the operations (except the ones defined in the components).
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.on:
+    publish:
+      operationId: turnOn
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.off:
+    publish:
+      operationId: turnOff
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.on:
+    publish:
+      operationId: turn
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.off:
+    publish:
+      operationId: turn
+```
+
+### asyncapi2-operation-security
+
+Operation `security` values must match a scheme defined in the `$.components.securitySchemes` object. It also checks if there are `oauth2` scopes that have been defined for the given security.
+
+#### Good example
+
+```yaml
+asyncapi: 2.4.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      security:
+        - authKey: []
+components:
+  securitySchemes:
+    authKey: {...}
+```
+
+```yaml
+asyncapi: 2.4.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      security:
+        - oauth2: ['write:user', 'read:user']
+components:
+  securitySchemes:
+    oauth2:
+      flows:
+        implicit:
+          scopes:
+            'write:user': '...',
+            'read:user': '...',
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.4.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      security:
+        - notDefined: []
+components:
+  securitySchemes:
+    authKey: {...}
+```
+
+```yaml
+asyncapi: 2.4.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      security:
+      - oauth2: ['write:user', 'not:defined']
+components:
+  securitySchemes:
+    oauth2:
+      flows:
+        implicit:
+          scopes:
+            'write:user': '...',
+            'read:user': '...',
+```
+
+### asyncapi2-message-examples
+
+All examples in message object should follow `payload` and `headers` schemas.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+components:
+  messages:
+    someMessage:
+      payload:
+        type: string
+      headers:
+        type: object
+      examples:
+        - payload: foobar
+          headers:
+            someHeader: someValue
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+components:
+  messages:
+    someMessage:
+      payload:
+        type: string
+      headers:
+        type: object
+      examples:
+        - payload: 2137
+          headers: someHeader
+```
+
+### asyncapi2-message-messageId-uniqueness
+
+`messageId` must be unique across all the messages (except those one defined in the components).
+
+#### Good example
+
+```yaml
+asyncapi: 2.4.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.on:
+    publish:
+      message:
+        messageId: turnOnMessage
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.off:
+    publish:
+      message:
+        messageId: turnOffMessage
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.4.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.on:
+    publish:
+      message:
+        messageId: turnMessage
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.off:
+    publish:
+      message:
+        messageId: turnMessage
+```
+
+### asyncapi2-tags-uniqueness
+
+Tags must not have duplicate names (identifiers).
+
+#### Good example
+
+```yaml
+tags:
+  - name: "env:production"
+  - name: "e-commerce"
+```
+
+#### Bad example
+
+```yaml
+tags:
+  - name: "e-commerce"
+  - name: "e-commerce"
+```
+
+### asyncapi2-schemas
+
+Custom schema must be correctly formatted from the point of view of the used format.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      message:
+        payload:
+          type: object
+```
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      message:
+        schemaFormat: 'application/vnd.aai.asyncapi;version=2.0.0',
+        payload:
+          type: object
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      message:
+        payload:
+          oneOf: 'this should be an array'
+          properties:
+            name:
+              if: 'this should be an if'
+```
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      message:
+        schemaFormat: 'notExisting',
+        payload:
+          type: object
+```
+
+### asyncapi2-schema-default
+
+`default` objects should be valid against the schema they decorate.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      message:
+        payload:
+          type: string
+          default: 'foobar'
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      message:
+        payload:
+          type: string
+          default: 2137
+```
+
+### asyncapi2-schema-examples
+
+Values of the `examples` array should be valid against the schema they decorate.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      message:
+        payload:
+          type: string
+          examples: ['foobar']
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  "user/signup":
+    publish:
+      message:
+        payload:
+          type: string
+          examples: ['foobar', 2137]
+```
diff --git a/docs/ruleset/v2-recommended-ruleset.md b/docs/ruleset/v2-recommended-ruleset.md
new file mode 100644
index 0000000..7de8c9a
--- /dev/null
+++ b/docs/ruleset/v2-recommended-ruleset.md
@@ -0,0 +1,296 @@
+# AsyncAPI v2 Recommended Ruleset
+
+The recommended ruleset verifies good practices within AsyncAPI version `2.x.x` documents.
+
+> **Note**
+> These rules will only apply to AsyncAPI `2.x.x` documents.
+
+## Rules
+
+### asyncapi2-tags
+
+AsyncAPI document should have a non-empty `tags` array.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+tags:
+  - e-commerce
+servers: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+```
+
+### asyncapi2-server-no-empty-variable
+
+Server URL variable declarations cannot be empty (e.g., `gigantic-server.com/{}` is invalid).
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.{variable}.mosquitto.org
+    variables:
+      variable: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.{}.mosquitto.org
+```
+
+### asyncapi2-server-no-trailing-slash
+
+Server URL should not have a trailing slash.
+
+Some tooling forgets to strip trailing slashes off when it's joining the `$.servers.[*].url` with channels, and you can get awkward URLs like `mqtt://example.com/broker//pets`. Best to just strip them off yourself.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: example.com/broker
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: example.com/broker/
+```
+
+### asyncapi2-channel-no-empty-parameter
+
+Channel parameter declarations cannot be empty (e.g., `./given/{}` is invalid).
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+channels:
+  users/{userId}/signedUp: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+channels:
+  users/{}/signedUp: {...}
+```
+
+### asyncapi2-channel-no-query-nor-fragment
+
+Query parameters and fragments shouldn't be used in channel names. Instead, use bindings to define them.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+channels:
+  users/{userId}/signedUp: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+channels:
+  users/{userId}/signedOut?query={...}: {...}
+  users/{userId}/signedOut#hash: {...}
+```
+
+### asyncapi2-channel-no-trailing-slash
+
+Keep trailing slashes off of channel names, as it can cause some confusion. Most messaging protocols will treat `example/foo` and `example/foo/` as different things. Keep in mind that tooling may replace slashes (`/`) with protocol-specific notation (e.g.: `.` for AMQP), therefore, a trailing slash may result in an invalid channel name in some protocols.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+channels:
+  users/{userId}/signedUp: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+channels:
+  users/{userId}/signedUp/: {...}
+```
+
+### asyncapi2-operation-operationId
+
+The `operationId` should be defined in each operation, essentially as an operation reference. Tools may use `operationId` for defining function names, class method names, and even URL hashes in documentation systems.
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.on:
+    publish:
+      operationId: turnOn
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.off:
+    publish:
+      operationId: turnOff
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.on:
+    publish:
+      operationId: turn
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.off:
+    publish: {...} # without `operationId`
+```
+
+### asyncapi2-message-messageId
+
+The `messageId` should be defined in each message, essentially a message reference. Tools may use `messageId` for defining function names, class method names, and even URL hashes in documentation systems.
+
+#### Good example
+
+```yaml
+asyncapi: 2.4.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.on:
+    publish:
+      message:
+        messageId: turnOnMessage
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.off:
+    publish:
+      message:
+        messageId: turnOffMessage
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.4.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers: {...}
+channels:
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.on:
+    publish:
+      message:
+        messageId: turnMessage
+  smartylighting.streetlights.1.0.action.{streetlightId}.turn.off:
+    publish:
+      message: {...} # without `messageId`
+```
+
+### asyncapi2-unused-securityScheme
+
+A potentially unused security scheme has been detected in the AsyncAPI document.
+
+> **Warning**
+> This rule may identify false positives when linting a specification that acts as a library (a container storing reusable objects, leveraged by other specifications that reference those objects).
+
+#### Good example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Valid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.mosquitto.org
+    protocol: mqtt
+    security:
+      - usedSchema: []
+channels:
+  ...
+components:
+  securitySchemas:
+    usedSchema: {...}
+```
+
+#### Bad example
+
+```yaml
+asyncapi: 2.0.0
+info:
+  title: Invalid AsyncAPI document
+  version: 1.0
+servers:
+  production:
+    url: test.mosquitto.org
+    protocol: mqtt
+channels:
+  ...
+components:
+  securitySchemas:
+    unusedSchema: {...}
+```
diff --git a/package-lock.json b/package-lock.json
index 42cd20e..033d4ae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "@asyncapi/parser",
-  "version": "2.0.2",
-  "lockfileVersion": 3,
+  "version": "2.0.3",
+  "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "@asyncapi/parser",
-      "version": "2.0.2",
+      "version": "2.0.3",
       "license": "Apache-2.0",
       "dependencies": {
         "@asyncapi/specs": "^5.1.0",
diff --git a/package.json b/package.json
index 1a81d03..cefdd88 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@asyncapi/parser",
-  "version": "2.0.2",
+  "version": "2.0.3",
   "description": "JavaScript AsyncAPI parser.",
   "bugs": {
     "url": "https://github.com/asyncapi/parser-js/issues"
diff --git a/src/ruleset/v2/ruleset.ts b/src/ruleset/v2/ruleset.ts
index a2e7816..419a6a0 100644
--- a/src/ruleset/v2/ruleset.ts
+++ b/src/ruleset/v2/ruleset.ts
@@ -123,17 +123,17 @@ export const v2CoreRuleset = {
       given: [
         // messages
         '$.channels.*.[publish,subscribe].[?(@property === \'message\' && @.schemaFormat === void 0)]',
-        '$.channels.*.[publish,subscribe].message.oneOf[?(@.schemaFormat === void 0)]',
+        '$.channels.*.[publish,subscribe].message.oneOf[?(!@null && @.schemaFormat === void 0)]',
         '$.components.channels.*.[publish,subscribe].[?(@property === \'message\' && @.schemaFormat === void 0)]',
-        '$.components.channels.*.[publish,subscribe].message.oneOf[?(@.schemaFormat === void 0)]',
-        '$.components.messages[?(@.schemaFormat === void 0)]',
+        '$.components.channels.*.[publish,subscribe].message.oneOf[?(!@null && @.schemaFormat === void 0)]',
+        '$.components.messages[?(!@null && @.schemaFormat === void 0)]',
         // message traits
-        '$.channels.*.[publish,subscribe].message.traits[?(@.schemaFormat === void 0)]',
-        '$.channels.*.[publish,subscribe].message.oneOf.*.traits[?(@.schemaFormat === void 0)]',
-        '$.components.channels.*.[publish,subscribe].message.traits[?(@.schemaFormat === void 0)]',
-        '$.components.channels.*.[publish,subscribe].message.oneOf.*.traits[?(@.schemaFormat === void 0)]',
-        '$.components.messages.*.traits[?(@.schemaFormat === void 0)]',
-        '$.components.messageTraits[?(@.schemaFormat === void 0)]',
+        '$.channels.*.[publish,subscribe].message.traits[?(!@null && @.schemaFormat === void 0)]',
+        '$.channels.*.[publish,subscribe].message.oneOf.*.traits[?(!@null && @.schemaFormat === void 0)]',
+        '$.components.channels.*.[publish,subscribe].message.traits[?(!@null && @.schemaFormat === void 0)]',
+        '$.components.channels.*.[publish,subscribe].message.oneOf.*.traits[?(!@null && @.schemaFormat === void 0)]',
+        '$.components.messages.*.traits[?(!@null && @.schemaFormat === void 0)]',
+        '$.components.messageTraits[?(!@null && @.schemaFormat === void 0)]',
       ],
       then: {
         function: messageExamples,


Test patch:
diff --git a/test/ruleset/rules/v2/asyncapi2-message-examples.spec.ts b/test/ruleset/rules/v2/asyncapi2-message-examples.spec.ts
index aa3f638..d8d2ff0 100644
--- a/test/ruleset/rules/v2/asyncapi2-message-examples.spec.ts
+++ b/test/ruleset/rules/v2/asyncapi2-message-examples.spec.ts
@@ -360,6 +360,7 @@ testRule('asyncapi2-message-examples', [
     },
     errors: [],
   },
+
   {
     name: 'invalid avro spec case',
     document: {
@@ -391,5 +392,87 @@ testRule('asyncapi2-message-examples', [
       },
     },
     errors: [],
-  }
+  },
+
+  {
+    name: 'avro can contain null values',
+    document: {
+      asyncapi: '2.6.0',
+      channels: {
+        someChannel: {
+          publish: {
+            message: {
+              schemaFormat: 'application/vnd.apache.avro;version=1.9.0',
+              payload: {
+                type: 'record',
+                name: 'Command',
+                fields: [{
+                  name: 'foo',
+                  default: null,
+                  type: ['null', 'string'],
+                }],
+              },
+              examples: [
+                {
+                  payload: {}
+                },
+              ],
+            },
+          },
+        },
+      },
+    },
+    errors: [],
+  },
+
+  {
+    name: 'handles oneOf processing',
+    document: {
+      asyncapi: '2.6.0',
+      channels: {
+        someChannel: {
+          publish: {
+            message: {
+              oneOf: [
+                {
+                  schemaFormat: 'application/vnd.apache.avro;version=1.9.0',
+                  payload: {
+                    type: 'record',
+                    name: 'Command',
+                    fields: [{
+                      name: 'foo',
+                      default: null,
+                      type: ['null', 'string'],
+                    }],
+                  },
+                  examples: [
+                    {
+                      payload: {}
+                    },
+                  ],
+                },
+                {
+                  payload: {
+                    type: 'string'
+                  },
+                  examples: [
+                    {
+                      payload: 1
+                    },
+                  ],
+                },
+              ],
+            },
+          },
+        },
+      },
+    },
+    errors: [
+      {
+        message: '"payload" property type must be string',
+        path: ['channels', 'someChannel', 'publish', 'message', 'oneOf', '1', 'examples', '0', 'payload'],
+        severity: DiagnosticSeverity.Error,
+      },
+    ],
+  },
 ]);
diff --git a/test/ruleset/tester.ts b/test/ruleset/tester.ts
index c630e44..42f384f 100644
--- a/test/ruleset/tester.ts
+++ b/test/ruleset/tester.ts
@@ -31,6 +31,7 @@ export function testRule(ruleName: RuleNames, tests: Scenario,): void {
         const doc = JSON.stringify(testCase.document);
 
         const errors = await parser.validate(doc);
+        expect(errors.filter(({ code }) => code === 'uncaught-error')).toHaveLength(0);
         expect(errors.filter(({ code }) => code === ruleName)).toEqual(
           testCase.errors.map(error => expect.objectContaining(error) as unknown),
         );