diff --git a/.asyncapi-tool b/.asyncapi-tool
index 71583182..c15324ea 100644
--- a/.asyncapi-tool
+++ b/.asyncapi-tool
@@ -14,7 +14,7 @@
"categories": [
"converters",
"code-first",
- "validator",
+ "validator"
],
"hasCommercial": false
}
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 4561e7f9..13e2f191 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -4,6 +4,8 @@ ci/cd:
- .github/**/*
asyncapi.readers:
- src/LEGO.AsyncAPI.Readers/**/*
+asyncapi.bindings:
+- src/LEGO.AsyncAPI.Bindings/**/*
asyncapi.models:
- src/LEGO.AsyncAPI/**/*
asyncapi.tests:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 447ff2b5..3d1d849d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,14 +1,16 @@
name: Build & Test
on:
push:
- branches: [ main ]
+ branches: [ main, vnext ]
paths:
- 'src/**'
+ - 'test/**'
- '!**/*.md'
pull_request:
- branches: [ main ]
+ branches: [ main, vnext ]
paths:
- 'src/**'
+ - 'test/**'
- '!**/*.md'
workflow_dispatch:
jobs:
@@ -23,7 +25,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
- dotnet-version: '6.0.x'
+ dotnet-version: '8.0.x'
include-prerelease: true
- name: Restore dependencies
run: dotnet restore
diff --git a/.github/workflows/release-beta.yml b/.github/workflows/release-beta.yml
new file mode 100644
index 00000000..9cbebb05
--- /dev/null
+++ b/.github/workflows/release-beta.yml
@@ -0,0 +1,46 @@
+name: Publish beta NuGet package
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - vnext
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ name: Check release
+ environment: AsyncAPI
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v1
+
+ - name: Semantic Release
+ id: semantic
+ uses: cycjimmy/semantic-release-action@v3
+ with:
+ dry_run: true
+ ci: false
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ outputs:
+ version: ${{ steps.semantic.outputs.new_release_version }}
+
+ pre-release:
+ runs-on: ubuntu-latest
+ name: Publish NuGet packages
+ needs: check
+ environment: AsyncAPI
+ strategy:
+ matrix:
+ package-name: [ "LEGO.AsyncAPI", "LEGO.AsyncAPI.Readers", "LEGO.AsyncAPI.Bindings" ]
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v1
+
+ - name: Setup .NET Core @ Latest
+ uses: actions/setup-dotnet@v1
+
+ - name: Build ${{ matrix.package-name }} project and pack NuGet package
+ run: dotnet pack src/${{ matrix.package-name }}/${{ matrix.package-name }}.csproj -c Release -o out-${{ matrix.package-name }} -p:PackageVersion=${{ needs.check.outputs.version }}-beta.${{github.run_number}}
+
+ - name: Push generated package to GitHub Packages registry
+ run: dotnet nuget push out-${{ matrix.package-name }}/*.nupkg -s https://api.nuget.org/v3/index.json --skip-duplicate -n --api-key ${{secrets.NUGET}}
diff --git a/.github/workflows/release-internal.yml b/.github/workflows/release-internal.yml
deleted file mode 100644
index 8b54315b..00000000
--- a/.github/workflows/release-internal.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-name: Publish internal NuGet package
-on:
- push:
- branches: [ main ]
- paths:
- - 'src/LEGO.AsyncAPI/**'
- - 'src/LEGO.AsyncAPI.Readers/**'
- - 'src/LEGO.AsyncAPI.Writers/**'
- - ".github/workflows/release-package.yml"
- - '!**/*.md'
- workflow_dispatch:
-
-jobs:
- release:
- runs-on: ubuntu-latest
- name: Publish NuGet packages
- strategy:
- matrix:
- package-name: [ "LEGO.AsyncAPI", "LEGO.AsyncAPI.Readers"]
- steps:
- - name: Checkout repository
- uses: actions/checkout@v1
-
- - name: Setup .NET Core @ Latest
- uses: actions/setup-dotnet@v1
- with:
- source-url: https://nuget.pkg.github.com/LEGO/index.json
- env:
- NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
-
- - name: Build ${{ matrix.package-name }} project and pack NuGet package
- run: dotnet pack src/${{ matrix.package-name }}/${{ matrix.package-name }}.csproj -c Release -o out-${{ matrix.package-name }} -p:PackageVersion=0.2.$GITHUB_RUN_NUMBER.0-prerelease
-
- - name: Push generated package to GitHub Packages registry
- run: dotnet nuget push out-${{ matrix.package-name }}/*.nupkg --skip-duplicate -n --api-key ${{secrets.GITHUB_TOKEN}}
diff --git a/.github/workflows/release-manual.yml b/.github/workflows/release-manual.yml
new file mode 100644
index 00000000..0eeca64b
--- /dev/null
+++ b/.github/workflows/release-manual.yml
@@ -0,0 +1,28 @@
+name: Publish custom NuGet package version
+on:
+ workflow_dispatch:
+ inputs:
+ package_version:
+ description: 'NuGet package version (e.g. 6.0.0-beta.1041)'
+ required: true
+
+jobs:
+ pre-release:
+ runs-on: ubuntu-latest
+ name: Publish NuGet packages
+ environment: AsyncAPI
+ strategy:
+ matrix:
+ package-name: [ "LEGO.AsyncAPI", "LEGO.AsyncAPI.Readers", "LEGO.AsyncAPI.Bindings" ]
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v1
+
+ - name: Setup .NET Core @ Latest
+ uses: actions/setup-dotnet@v1
+
+ - name: Build ${{ matrix.package-name }} project and pack NuGet package
+ run: dotnet pack src/${{ matrix.package-name }}/${{ matrix.package-name }}.csproj -c Release -o out-${{ matrix.package-name }} -p:PackageVersion=${{ github.event.inputs.package_version }}
+
+ - name: Push generated package to NuGet
+ run: dotnet nuget push out-${{ matrix.package-name }}/*.nupkg -s https://api.nuget.org/v3/index.json --skip-duplicate -n --api-key ${{secrets.NUGET}}
diff --git a/.github/workflows/release-package.yml b/.github/workflows/release-package.yml
index 0f064176..9e52a9fe 100644
--- a/.github/workflows/release-package.yml
+++ b/.github/workflows/release-package.yml
@@ -56,7 +56,7 @@ jobs:
environment: AsyncAPI
strategy:
matrix:
- package-name: [ "LEGO.AsyncAPI", "LEGO.AsyncAPI.Readers" ]
+ package-name: [ "LEGO.AsyncAPI", "LEGO.AsyncAPI.Readers", "LEGO.AsyncAPI.Bindings" ]
steps:
- name: Checkout repository
uses: actions/checkout@v1
diff --git a/AsyncAPI.sln b/AsyncAPI.sln
index bf944501..db79f153 100644
--- a/AsyncAPI.sln
+++ b/AsyncAPI.sln
@@ -12,8 +12,11 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DE167614-5BCB-4046-BD4C-ABB70E9F3462}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
+ Common.Build.props = Common.Build.props
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LEGO.AsyncAPI.Bindings", "src\LEGO.AsyncAPI.Bindings\LEGO.AsyncAPI.Bindings.csproj", "{33CA31F4-ECFE-4227-BFE9-F49783DD29A0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -32,6 +35,10 @@ Global
{7D9C6FBA-4B6F-48A0-B3F5-E7357021F8F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D9C6FBA-4B6F-48A0-B3F5-E7357021F8F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D9C6FBA-4B6F-48A0-B3F5-E7357021F8F9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {33CA31F4-ECFE-4227-BFE9-F49783DD29A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {33CA31F4-ECFE-4227-BFE9-F49783DD29A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {33CA31F4-ECFE-4227-BFE9-F49783DD29A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {33CA31F4-ECFE-4227-BFE9-F49783DD29A0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f493bf3f..7dea98ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,132 @@
+## [5.2.4](https://github.com/LEGO/AsyncAPI.NET/compare/v5.2.3...v5.2.4) (2024-07-29)
+
+
+### Bug Fixes
+
+* remove persistence nullability ([52165f2](https://github.com/LEGO/AsyncAPI.NET/commit/52165f213502d9436e25a4e761804b5796b5de8c))
+
+## [5.2.3](https://github.com/LEGO/AsyncAPI.NET/compare/v5.2.2...v5.2.3) (2024-07-29)
+
+
+### Bug Fixes
+
+* add missing walk and visit methods for bindings. ([#191](https://github.com/LEGO/AsyncAPI.NET/issues/191)) ([b8307c5](https://github.com/LEGO/AsyncAPI.NET/commit/b8307c57a6f9bc7c546702c24dffdfb1833aa5d3))
+
+## [5.2.2](https://github.com/LEGO/AsyncAPI.NET/compare/v5.2.1...v5.2.2) (2024-07-29)
+
+
+### Bug Fixes
+
+* correct typing of exclusive maximums and minimums for draft7 jso… ([#188](https://github.com/LEGO/AsyncAPI.NET/issues/188)) ([fb50d00](https://github.com/LEGO/AsyncAPI.NET/commit/fb50d00192896f9ac26e65df1e991854b33aa17c))
+* resolving wrong reference ([#180](https://github.com/LEGO/AsyncAPI.NET/issues/180)) ([47685cd](https://github.com/LEGO/AsyncAPI.NET/commit/47685cd19c7e58391625be043b1e5d82c49eedc8))
+
+## [5.2.1](https://github.com/LEGO/AsyncAPI.NET/compare/v5.2.0...v5.2.1) (2024-06-12)
+
+
+### Bug Fixes
+
+* inline channel parameters should not deserialize as references ([#172](https://github.com/LEGO/AsyncAPI.NET/issues/172)) ([7fd3af0](https://github.com/LEGO/AsyncAPI.NET/commit/7fd3af0e6669d18e805e0bab9cafac819ea64c1d))
+
+# [5.2.0](https://github.com/LEGO/AsyncAPI.NET/compare/v5.1.1...v5.2.0) (2024-03-30)
+
+
+### Features
+
+* add cultureinfo to reader/writer settings. ([#152](https://github.com/LEGO/AsyncAPI.NET/issues/152)) ([0199420](https://github.com/LEGO/AsyncAPI.NET/commit/01994205ecde4e17317762374b03ec23aad17022))
+* **bindings:** add amqp bindings ([#153](https://github.com/LEGO/AsyncAPI.NET/issues/153)) ([8d128db](https://github.com/LEGO/AsyncAPI.NET/commit/8d128db869d8164cfaad156d4f29a7130a00827e))
+* **bindings:** add mqtt bindings ([#154](https://github.com/LEGO/AsyncAPI.NET/issues/154)) ([f5529e0](https://github.com/LEGO/AsyncAPI.NET/commit/f5529e0e96d139e0cb1958d6b0620ed826e21cb5))
+* improve AsyncApiAny api surface. ([9063f4e](https://github.com/LEGO/AsyncAPI.NET/commit/9063f4e4f19929f8ccbdee5bd46dd9e27a3e0c08))
+* targetframework to netstandard2.0 ([#150](https://github.com/LEGO/AsyncAPI.NET/issues/150)) ([9291da6](https://github.com/LEGO/AsyncAPI.NET/commit/9291da603335fd202b59f421945629952f136296))
+
+## [5.1.1](https://github.com/LEGO/AsyncAPI.NET/compare/v5.1.0...v5.1.1) (2024-02-16)
+
+
+### Bug Fixes
+
+* long values for missing retention properties ([93ba475](https://github.com/LEGO/AsyncAPI.NET/commit/93ba4755babd05a0d21f3530aab417eeed3b7073))
+
+# [5.1.0](https://github.com/LEGO/AsyncAPI.NET/compare/v5.0.0...v5.1.0) (2024-02-15)
+
+
+### Bug Fixes
+
+* updated topic configuration data types ([eace86d](https://github.com/LEGO/AsyncAPI.NET/commit/eace86dde4fc704d4652d19e7073be3b37ade6c7))
+
+
+### Features
+
+* added new topic configuration properties ([4a6c6a8](https://github.com/LEGO/AsyncAPI.NET/commit/4a6c6a8fed3a970153bd511daad5e614dbcdf2df))
+
+# [5.0.0](https://github.com/LEGO/AsyncAPI.NET/compare/v4.1.0...v5.0.0) (2023-12-14)
+
+
+### Bug Fixes
+
+* add type to references, always. ([#139](https://github.com/LEGO/AsyncAPI.NET/issues/139)) ([3031023](https://github.com/LEGO/AsyncAPI.NET/commit/30310232bb3869258486d9f7f85721d4e3fb46eb))
+* added missing mapping for ordering ([#138](https://github.com/LEGO/AsyncAPI.NET/issues/138)) ([510426e](https://github.com/LEGO/AsyncAPI.NET/commit/510426e200b4fe97ad1b8e9a6e94a615593c2a3c))
+* patternProperties should also be walked as a reference ([#133](https://github.com/LEGO/AsyncAPI.NET/issues/133)) ([dc544f1](https://github.com/LEGO/AsyncAPI.NET/commit/dc544f1c01be3b95ded08ee894453ce8529eafb3))
+
+
+* chore(settings)!: make reader bindings IEnumerable to allow for simpler usage ([e1f8c87](https://github.com/LEGO/AsyncAPI.NET/commit/e1f8c8766767ce642546a911810064a5234f04c3))
+
+
+### Features
+
+* allow non-component references ([#132](https://github.com/LEGO/AsyncAPI.NET/issues/132)) ([71fe571](https://github.com/LEGO/AsyncAPI.NET/commit/71fe571a3db0b4fbc13f4573b4d4b53f4f6b0911))
+* **bindings:** add high throughput fifo properties ([#135](https://github.com/LEGO/AsyncAPI.NET/issues/135)) ([44ffcf4](https://github.com/LEGO/AsyncAPI.NET/commit/44ffcf4ceaf06a5168597e1eeb9407f09d47ab23))
+
+
+### BREAKING CHANGES
+
+* changes how bindings are applied.
+
+# [4.1.0](https://github.com/LEGO/AsyncAPI.NET/compare/v4.0.2...v4.1.0) (2023-09-27)
+
+
+### Features
+
+* **bindings:** update FilterPolicy to match AWS API ([#128](https://github.com/LEGO/AsyncAPI.NET/issues/128)) ([5b64654](https://github.com/LEGO/AsyncAPI.NET/commit/5b6465474ae09d42a27377bf04d58fdbd1dd8a59))
+
+## [4.0.2](https://github.com/LEGO/AsyncAPI.NET/compare/v4.0.1...v4.0.2) (2023-08-01)
+
+
+### Bug Fixes
+
+* add missing properties to json schema ([#124](https://github.com/LEGO/AsyncAPI.NET/issues/124)) ([adcd017](https://github.com/LEGO/AsyncAPI.NET/commit/adcd017b3ff6875eddac9649c2c95c398e49dec0))
+* nullref if type is not set on jsonschema when using enum. ([#123](https://github.com/LEGO/AsyncAPI.NET/issues/123)) ([e53db72](https://github.com/LEGO/AsyncAPI.NET/commit/e53db729813bd76c17a335baf9bf0d0efc34e0bc))
+* parse const keyword in a schema object ([#121](https://github.com/LEGO/AsyncAPI.NET/issues/121)) ([22b329c](https://github.com/LEGO/AsyncAPI.NET/commit/22b329c6c8068e4ff2090cb6dd11bab2d5a254a5))
+
+## [4.0.1](https://github.com/LEGO/AsyncAPI.NET/compare/v4.0.0...v4.0.1) (2023-07-11)
+
+
+### Bug Fixes
+
+* add ability to have 'false' as the value for 'additionalproperties' ([#118](https://github.com/LEGO/AsyncAPI.NET/issues/118)) ([9e4867f](https://github.com/LEGO/AsyncAPI.NET/commit/9e4867fbec9377964489e53c71f38a239e359cdf))
+* async schema deserializer "additionalProperties" not deserializing JsonSchema correctly ([#120](https://github.com/LEGO/AsyncAPI.NET/issues/120)) ([3761f52](https://github.com/LEGO/AsyncAPI.NET/commit/3761f521570268febb8b00fde9896379acb7047b))
+
+# [4.0.0](https://github.com/LEGO/AsyncAPI.NET/compare/v3.0.2...v4.0.0) (2023-06-12)
+
+
+### Bug Fixes
+
+* add setter to BindingParsers collection ([211646e](https://github.com/LEGO/AsyncAPI.NET/commit/211646e95b82b3e32563fe75c57656cd6882267b))
+
+
+### Features
+
+* **jsonschema**!: type as flag rather than list (#115) ([d44efb0](https://github.com/LEGO/AsyncAPI.NET/commit/d44efb048402c70377064b87bd962b0e455e08b3)), closes [#115](https://github.com/LEGO/AsyncAPI.NET/issues/115)
+* **jsonschema**!: changed out decimal for double to allow for bigger numbers ([ab00976](https://github.com/LEGO/AsyncAPI.NET/commit/ab009764a916171c8926c129384ce18b3162e71e))
+* **bindings**!: separate bindings and allow for custom bindings. (#107) ([d38c33f](https://github.com/LEGO/AsyncAPI.NET/commit/d38c33f14d6de73e2563e29534965b06d423edac)), closes [#107](https://github.com/LEGO/AsyncAPI.NET/issues/107)
+* **bindings:** add SNS AWS bindings ([#108](https://github.com/LEGO/AsyncAPI.NET/issues/108)) ([d48f166](https://github.com/LEGO/AsyncAPI.NET/commit/d48f1669ebfd9ad3f661b2b5928df1d622a4e7ba))
+* **bindings:** add SQS AWS Bindings ([#113](https://github.com/LEGO/AsyncAPI.NET/issues/113)) ([4a93c7a](https://github.com/LEGO/AsyncAPI.NET/commit/4a93c7a26dbc0dd28914ac96575070deb0a6d2c1))
+
+
+### BREAKING CHANGES
+
+* The type of `Type` in JsonSchema is now a Flags enum, rather than a List of enum. This provides an easier to use interface, for adding and checking types.
+* 3 properties, previously of type `decimal` in the JsonSchema type have been changed to `double`.
+* Bindings have been moved to a separate project
+
## [3.0.2](https://github.com/LEGO/AsyncAPI.NET/compare/v3.0.1...v3.0.2) (2023-03-30)
diff --git a/CODEOWNERS b/CODEOWNERS
index f1759cb1..2e87be63 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1 +1 @@
-* @VisualBean
+* @VisualBean @UlrikSandberg
diff --git a/Common.Build.props b/Common.Build.props
new file mode 100644
index 00000000..ba84a0f8
--- /dev/null
+++ b/Common.Build.props
@@ -0,0 +1,20 @@
+
+
+
+ 10
+ netstandard2.0;net6
+ disable
+ The LEGO Group
+ https://github.com/LEGO/AsyncAPI.NET
+ README.md
+ https://github.com/LEGO/AsyncAPI.NET
+ asyncapi .net openapi documentation
+ logo.png
+ LICENSE.txt
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE.txt
similarity index 100%
rename from LICENSE
rename to LICENSE.txt
diff --git a/README.md b/README.md
index cacd288a..ce65fd33 100644
--- a/README.md
+++ b/README.md
@@ -13,10 +13,17 @@ The AsyncAPI.NET SDK contains a useful object model for the AsyncAPI specificati
## Installation
Install the NuGet packages:
+### AsyncAPI.NET
+[](https://www.nuget.org/packages/AsyncAPI.NET/)
+[](https://www.nuget.org/packages/AsyncAPI.NET/)
-[](https://www.nuget.org/packages/AsyncAPI.NET.Readers/)
-[](https://www.nuget.org/packages/AsyncAPI.NET/)
+### AsyncAPI.Readers
+[](https://www.nuget.org/packages/AsyncAPI.NET.Readers/)
+[](https://www.nuget.org/packages/AsyncAPI.NET.Readers/)
+### AsyncAPI.Bindings
+[](https://www.nuget.org/packages/AsyncAPI.NET.Bindings/)
+[](https://www.nuget.org/packages/AsyncAPI.NET.Bindings/)
## Example Usage
Main classes to know:
@@ -71,6 +78,16 @@ var stream = await httpClient.GetStreamAsync("master/examples/streetlights-kafka
var asyncApiDocument = new AsyncApiStreamReader().Read(stream, out var diagnostic);
```
+### Bindings
+To add support for reading bindings, simply add the bindings you wish to support, to the `Bindings` collection of `AsyncApiReaderSettings`.
+There is a nifty helper to add different types of bindings, or like in the example `All` of them.
+
+```csharp
+var settings = new AsyncApiReaderSettings();
+settings.Bindings = BindingsCollection.All;
+var asyncApiDocument = new AsyncApiStringReader(settings).Read(stream, out var diagnostic);
+```
+
## Attribution
* [OpenAPI.Net](https://github.com/microsoft/OpenAPI.NET) - [MIT License](https://github.com/microsoft/OpenAPI.NET/blob/vnext/LICENSE)
diff --git a/media/logo.png b/media/logo.png
new file mode 100644
index 00000000..1a25d72c
Binary files /dev/null and b/media/logo.png differ
diff --git a/release.config.js b/release.config.js
index 7c6ba358..7cf37e87 100644
--- a/release.config.js
+++ b/release.config.js
@@ -1,5 +1,5 @@
module.exports = {
- branches: "main",
+ branches: ["main", "vnext"],
plugins: [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPChannelBinding.cs
new file mode 100644
index 00000000..ebfed688
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPChannelBinding.cs
@@ -0,0 +1,86 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.AMQP
+{
+ using System;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for AMQP channel settings.
+ ///
+ public class AMQPChannelBinding : ChannelBinding
+ {
+ ///
+ /// Defines what type of channel is it. Can be either queue or routingKey.
+ ///
+ public ChannelType Is { get; set; }
+
+ ///
+ /// When is=routingKey, this object defines the exchange properties.
+ ///
+ public Exchange Exchange { get; set; }
+
+ ///
+ /// When is=queue, this object defines the queue properties.
+ ///
+ public Queue Queue { get; set; }
+
+ public override string BindingKey => "amqp";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "is", (a, n) => { a.Is = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "exchange", (a, n) => { a.Exchange = n.ParseMap(ExchangeFixedFields); } },
+ { "queue", (a, n) => { a.Queue = n.ParseMap(QueueFixedFields); } },
+ };
+
+ private static FixedFieldMap ExchangeFixedFields = new()
+ {
+ { "name", (a, n) => { a.Name = n.GetScalarValue(); } },
+ { "durable", (a, n) => { a.Durable = n.GetBooleanValue(); } },
+ { "type", (a, n) => { a.Type = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "autoDelete", (a, n) => { a.AutoDelete = n.GetBooleanValue(); } },
+ { "vhost", (a, n) => { a.Vhost = n.GetScalarValue(); } },
+ };
+
+ private static FixedFieldMap QueueFixedFields = new()
+ {
+ { "name", (a, n) => { a.Name = n.GetScalarValue(); } },
+ { "durable", (a, n) => { a.Durable = n.GetBooleanValue(); } },
+ { "exclusive", (a, n) => { a.Exclusive = n.GetBooleanValue(); } },
+ { "autoDelete", (a, n) => { a.AutoDelete = n.GetBooleanValue(); } },
+ { "vhost", (a, n) => { a.Vhost = n.GetScalarValue(); } },
+ };
+
+ ///
+ /// Serialize to AsyncAPI V2 document without using reference.
+ ///
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("is", this.Is.GetDisplayName());
+ switch (this.Is)
+ {
+ case ChannelType.RoutingKey:
+ writer.WriteOptionalObject("exchange", this.Exchange, (w, t) => t.Serialize(w));
+ break;
+ case ChannelType.Queue:
+ writer.WriteOptionalObject("queue", this.Queue, (w, t) => t.Serialize(w));
+ break;
+ }
+
+ writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPMessageBinding.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPMessageBinding.cs
new file mode 100644
index 00000000..73a68049
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPMessageBinding.cs
@@ -0,0 +1,51 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.AMQP
+{
+ using System;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for AMQP messages.
+ ///
+ public class AMQPMessageBinding : MessageBinding
+ {
+ ///
+ /// A MIME encoding for the message content.
+ ///
+ public string ContentEncoding { get; set; }
+
+ ///
+ /// Application-specific message type.
+ ///
+ public string MessageType { get; set; }
+
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+
+ writer.WriteOptionalProperty("contentEncoding", this.ContentEncoding);
+ writer.WriteOptionalProperty("messageType", this.MessageType);
+ writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+
+ writer.WriteEndObject();
+ }
+
+ public override string BindingKey => "amqp";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "contentEncoding", (a, n) => { a.ContentEncoding = n.GetScalarValue(); } },
+ { "messageType", (a, n) => { a.MessageType = n.GetScalarValue(); } },
+ };
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPOperationBinding.cs
new file mode 100644
index 00000000..86dc74ef
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPOperationBinding.cs
@@ -0,0 +1,103 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.AMQP
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for AMQP operations.
+ ///
+ public class AMQPOperationBinding : OperationBinding
+ {
+ ///
+ /// TTL (Time-To-Live) for the message. It MUST be greater than or equal to zero.
+ ///
+ public uint? Expiration { get; set; }
+
+ ///
+ /// Identifies the user who has sent the message.
+ ///
+ public string UserId { get; set; }
+
+ ///
+ /// The routing keys the message should be routed to at the time of publishing.
+ ///
+ public List Cc { get; set; } = new List();
+
+ ///
+ /// A priority for the message.
+ ///
+ public int? Priority { get; set; }
+
+ ///
+ /// Delivery mode of the message. Its value MUST be either 1 (transient) or 2 (persistent).
+ ///
+ public DeliveryMode? DeliveryMode { get; set; }
+
+ ///
+ /// Whether the message is mandatory or not.
+ ///
+ public bool? Mandatory { get; set; }
+
+ ///
+ /// Like cc but consumers will not receive this information.
+ ///
+ public List Bcc { get; set; } = new List();
+
+ ///
+ /// Whether the message should include a timestamp or not.
+ ///
+ public bool? Timestamp { get; set; }
+
+ ///
+ /// Whether the consumer should ack the message or not.
+ ///
+ public bool? Ack { get; set; }
+
+ public override string BindingKey => "amqp";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "expiration", (a, n) => { a.Expiration = (uint?)n.GetIntegerValueOrDefault(); } },
+ { "userId", (a, n) => { a.UserId = n.GetScalarValueOrDefault(); } },
+ { "cc", (a, n) => { a.Cc = n.CreateSimpleList(s => s.GetScalarValue()); } },
+ { "priority", (a, n) => { a.Priority = n.GetIntegerValueOrDefault(); } },
+ { "deliveryMode", (a, n) => { a.DeliveryMode = (DeliveryMode?)n.GetIntegerValueOrDefault(); } },
+ { "mandatory", (a, n) => { a.Mandatory = n.GetBooleanValueOrDefault(); } },
+ { "bcc", (a, n) => { a.Bcc = n.CreateSimpleList(s => s.GetScalarValue()); } },
+ { "timestamp", (a, n) => { a.Timestamp = n.GetBooleanValueOrDefault(); } },
+ { "ack", (a, n) => { a.Ack = n.GetBooleanValueOrDefault(); } },
+ };
+
+ ///
+ /// Serialize to AsyncAPI V2 document without using reference.
+ ///
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalProperty("expiration", (int)this.Expiration);
+ writer.WriteOptionalProperty("userId", this.UserId);
+ writer.WriteOptionalCollection("cc", this.Cc, (w, s) => w.WriteValue(s));
+ writer.WriteOptionalProperty("priority", this.Priority);
+ writer.WriteOptionalProperty("deliveryMode", (int?)this.DeliveryMode);
+ writer.WriteOptionalProperty("mandatory", this.Mandatory);
+ writer.WriteOptionalCollection("bcc", this.Bcc, (w, s) => w.WriteValue(s));
+ writer.WriteOptionalProperty("timestamp", this.Timestamp);
+ writer.WriteOptionalProperty("ack", this.Ack);
+ writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/ChannelType.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/ChannelType.cs
new file mode 100644
index 00000000..a817ea49
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/AMQP/ChannelType.cs
@@ -0,0 +1,15 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.AMQP
+{
+ using LEGO.AsyncAPI.Attributes;
+
+ public enum ChannelType
+ {
+ [Display("routingKey")]
+ RoutingKey = 0,
+
+ [Display("queue")]
+ Queue,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/DeliveryMode.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/DeliveryMode.cs
new file mode 100644
index 00000000..77b855b5
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/AMQP/DeliveryMode.cs
@@ -0,0 +1,15 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.AMQP
+{
+ using LEGO.AsyncAPI.Attributes;
+
+ public enum DeliveryMode
+ {
+ [Display("transient")]
+ Transient = 1,
+
+ [Display("persistent")]
+ Persistent = 2,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/Exchange.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/Exchange.cs
new file mode 100644
index 00000000..66815b3c
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/AMQP/Exchange.cs
@@ -0,0 +1,50 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.AMQP
+{
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Represents an exchange configuration.
+ ///
+ public class Exchange : IAsyncApiElement
+ {
+ ///
+ /// The name of the exchange. It MUST NOT exceed 255 characters long.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// The type of the exchange. Can be either topic, direct, fanout, default, or headers.
+ ///
+ public ExchangeType Type { get; set; }
+
+ ///
+ /// Whether the exchange should survive broker restarts or not.
+ ///
+ public bool Durable { get; set; }
+
+ ///
+ /// Whether the exchange should be deleted when the last queue is unbound from it.
+ ///
+ public bool AutoDelete { get; set; }
+
+ ///
+ /// The virtual host of the exchange. Defaults to /.
+ ///
+ public string Vhost { get; set; } = "/";
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty(AsyncApiConstants.Name, this.Name);
+ writer.WriteRequiredProperty(AsyncApiConstants.Type, this.Type.GetDisplayName());
+ writer.WriteRequiredProperty("durable", this.Durable);
+ writer.WriteRequiredProperty("autoDelete", this.AutoDelete);
+ writer.WriteRequiredProperty("vhost", this.Vhost);
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/ExchangeType.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/ExchangeType.cs
new file mode 100644
index 00000000..1cfde013
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/AMQP/ExchangeType.cs
@@ -0,0 +1,24 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.AMQP
+{
+ using LEGO.AsyncAPI.Attributes;
+
+ public enum ExchangeType
+ {
+ [Display("default")]
+ Default = 0,
+
+ [Display("topic")]
+ Topic,
+
+ [Display("direct")]
+ Direct,
+
+ [Display("fanout")]
+ Fanout,
+
+ [Display("headers")]
+ Headers,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/Queue.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/Queue.cs
new file mode 100644
index 00000000..a3cf25d3
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/AMQP/Queue.cs
@@ -0,0 +1,50 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.AMQP
+{
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Represents a queue configuration.
+ ///
+ public class Queue : IAsyncApiElement
+ {
+ ///
+ /// The name of the queue. It MUST NOT exceed 255 characters long.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Whether the queue should survive broker restarts or not.
+ ///
+ public bool Durable { get; set; }
+
+ ///
+ /// Whether the queue should be used only by one connection or not.
+ ///
+ public bool Exclusive { get; set; }
+
+ ///
+ /// Whether the queue should be deleted when the last consumer unsubscribes.
+ ///
+ public bool AutoDelete { get; set; }
+
+ ///
+ /// The virtual host of the queue. Defaults to /.
+ ///
+ public string Vhost { get; set; } = "/";
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty(AsyncApiConstants.Name, this.Name);
+ writer.WriteRequiredProperty("durable", this.Durable);
+ writer.WriteRequiredProperty("exclusive", this.Exclusive);
+ writer.WriteRequiredProperty("autoDelete", this.AutoDelete);
+ writer.WriteRequiredProperty("vhost", this.Vhost);
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/Binding.cs b/src/LEGO.AsyncAPI.Bindings/Binding.cs
new file mode 100644
index 00000000..e7c57400
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Binding.cs
@@ -0,0 +1,14 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings
+{
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers.Interface;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public abstract class Binding : AsyncApiBinding, IBindingParser
+ where T : IBinding, new()
+ {
+ public abstract T LoadBinding(PropertyNode node);
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/BindingHelpers.cs b/src/LEGO.AsyncAPI.Bindings/BindingHelpers.cs
new file mode 100644
index 00000000..424afc9e
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/BindingHelpers.cs
@@ -0,0 +1,49 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings
+{
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public static class BindingHelpers
+ {
+ public static T ParseMap(this ParseNode node, FixedFieldMap fixedFieldMap)
+ where T : new()
+ {
+ var mapNode = node.CheckMapNode(node.Context.GetLocation());
+ if (mapNode == null)
+ {
+ return default(T);
+ }
+
+ var instance = new T();
+
+ foreach (var propertyNode in mapNode)
+ {
+ propertyNode.ParseField(instance, fixedFieldMap, null);
+ }
+
+ return instance;
+ }
+
+ public static T ParseMapWithExtensions(this ParseNode node, FixedFieldMap fixedFieldMap)
+ where T : IAsyncApiExtensible, new()
+ {
+ var mapNode = node.CheckMapNode(node.Context.GetLocation());
+ if (mapNode == null)
+ {
+ return default(T);
+ }
+
+ var instance = new T();
+
+ foreach (var propertyNode in mapNode)
+ {
+ propertyNode.ParseField(instance, fixedFieldMap, ExtensionHelpers.GetExtensionsFieldMap());
+ }
+
+ return instance;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/BindingsCollection.cs b/src/LEGO.AsyncAPI.Bindings/BindingsCollection.cs
new file mode 100644
index 00000000..4fd5560f
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/BindingsCollection.cs
@@ -0,0 +1,111 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+namespace LEGO.AsyncAPI.Bindings
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Bindings.AMQP;
+ using LEGO.AsyncAPI.Bindings.Http;
+ using LEGO.AsyncAPI.Bindings.Kafka;
+ using LEGO.AsyncAPI.Bindings.MQTT;
+ using LEGO.AsyncAPI.Bindings.Pulsar;
+ using LEGO.AsyncAPI.Bindings.Sns;
+ using LEGO.AsyncAPI.Bindings.Sqs;
+ using LEGO.AsyncAPI.Bindings.WebSockets;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers.Interface;
+
+ public static class BindingsCollection
+ {
+ public static TCollection Add(
+ this TCollection destination,
+ IEnumerable source)
+ where TCollection : ICollection
+ {
+ if (destination == null)
+ {
+ throw new ArgumentNullException(nameof(destination));
+ }
+
+ if (source == null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ if (destination is List list)
+ {
+ list.AddRange(source);
+ return destination;
+ }
+
+ foreach (var item in source)
+ {
+ destination.Add(item);
+ }
+
+ return destination;
+ }
+
+ public static IEnumerable> All => new List>
+ {
+ Pulsar,
+ Kafka,
+ Http,
+ Websockets,
+ Sqs,
+ Sns,
+ AMQP,
+ MQTT,
+ };
+
+ public static IEnumerable> Http => new List>
+ {
+ new HttpOperationBinding(),
+ new HttpMessageBinding(),
+ };
+
+ public static IEnumerable> Websockets => new List>
+ {
+ new WebSocketsChannelBinding(),
+ };
+
+ public static IEnumerable> Kafka => new List>
+ {
+ new KafkaServerBinding(),
+ new KafkaChannelBinding(),
+ new KafkaOperationBinding(),
+ new KafkaMessageBinding(),
+ };
+
+ public static IEnumerable> Pulsar => new List>
+ {
+ new PulsarServerBinding(),
+ new PulsarChannelBinding(),
+ };
+
+ public static IEnumerable> Sqs => new List>
+ {
+ new SqsChannelBinding(),
+ new SqsOperationBinding(),
+ };
+
+ public static IEnumerable> Sns => new List>
+ {
+ new SnsChannelBinding(),
+ new SnsOperationBinding(),
+ };
+
+ public static IEnumerable> AMQP => new List>
+ {
+ new AMQPChannelBinding(),
+ new AMQPOperationBinding(),
+ new AMQPMessageBinding(),
+ };
+
+ public static IEnumerable> MQTT => new List>
+ {
+ new MQTTServerBinding(),
+ new MQTTOperationBinding(),
+ new MQTTMessageBinding(),
+ };
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/ChannelBinding{T}.cs b/src/LEGO.AsyncAPI.Bindings/ChannelBinding{T}.cs
new file mode 100644
index 00000000..d792809c
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/ChannelBinding{T}.cs
@@ -0,0 +1,16 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings
+{
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public abstract class ChannelBinding : Binding, IChannelBinding
+ where T : IChannelBinding, new()
+ {
+ protected abstract FixedFieldMap FixedFieldMap { get; }
+
+ public override T LoadBinding(PropertyNode node) => BindingDeserializer.LoadBinding("ChannelBinding", node.Value, this.FixedFieldMap);
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/Http/HttpMessageBinding.cs b/src/LEGO.AsyncAPI.Bindings/Http/HttpMessageBinding.cs
new file mode 100644
index 00000000..7a5731ef
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Http/HttpMessageBinding.cs
@@ -0,0 +1,48 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Http
+{
+ using System;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for http messaging channels.
+ ///
+ public class HttpMessageBinding : MessageBinding
+ {
+ ///
+ /// A Schema object containing the definitions for HTTP-specific headers. This schema MUST be of type object and have a properties key.
+ ///
+ public AsyncApiSchema Headers { get; set; }
+
+ ///
+ /// Serialize to AsyncAPI V2 document without using reference.
+ ///
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+
+ writer.WriteOptionalObject(AsyncApiConstants.Headers, this.Headers, (w, h) => h.SerializeV2(w));
+ writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+
+ writer.WriteEndObject();
+ }
+
+ public override string BindingKey => "http";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "headers", (a, n) => { a.Headers = JsonSchemaDeserializer.LoadSchema(n); } },
+ };
+ }
+}
diff --git a/src/LEGO.AsyncAPI/Models/Bindings/Http/HttpOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/Http/HttpOperationBinding.cs
similarity index 55%
rename from src/LEGO.AsyncAPI/Models/Bindings/Http/HttpOperationBinding.cs
rename to src/LEGO.AsyncAPI.Bindings/Http/HttpOperationBinding.cs
index 27a91798..f70858c2 100644
--- a/src/LEGO.AsyncAPI/Models/Bindings/Http/HttpOperationBinding.cs
+++ b/src/LEGO.AsyncAPI.Bindings/Http/HttpOperationBinding.cs
@@ -1,21 +1,32 @@
// Copyright (c) The LEGO Group. All rights reserved.
-namespace LEGO.AsyncAPI.Models.Bindings.Http
+namespace LEGO.AsyncAPI.Bindings.Http
{
using System;
- using System.Collections.Generic;
- using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Attributes;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;
///
/// Binding class for http operations.
///
- public class HttpOperationBinding : IOperationBinding
+ public class HttpOperationBinding : OperationBinding
{
+ public enum HttpOperationType
+ {
+ [Display("request")]
+ Request,
+
+ [Display("response")]
+ Response,
+ }
+
///
/// REQUIRED. Type of operation. Its value MUST be either request or response.
///
- public string Type { get; set; }
+ public HttpOperationType? Type { get; set; }
///
/// When type is request, this is the HTTP method, otherwise it MUST be ignored. Its value MUST be one of GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, CONNECT, and TRACE.
@@ -27,15 +38,10 @@ public class HttpOperationBinding : IOperationBinding
///
public AsyncApiSchema Query { get; set; }
- ///
- /// The version of this binding. If omitted, "latest" MUST be assumed.
- ///
- public string BindingVersion { get; set; }
-
///
/// Serialize to AsyncAPI V2 document without using reference.
///
- public void SerializeV2WithoutReference(IAsyncApiWriter writer)
+ public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
@@ -44,37 +50,22 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer)
writer.WriteStartObject();
- writer.WriteRequiredProperty(AsyncApiConstants.Type, this.Type);
+ writer.WriteRequiredProperty(AsyncApiConstants.Type, this.Type.GetDisplayName());
writer.WriteOptionalProperty(AsyncApiConstants.Method, this.Method);
writer.WriteOptionalObject(AsyncApiConstants.Query, this.Query, (w, h) => h.SerializeV2(w));
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
-
+ writer.WriteExtensions(this.Extensions);
writer.WriteEndObject();
}
- public void SerializeV2(IAsyncApiWriter writer)
+ protected override FixedFieldMap FixedFieldMap => new()
{
- if (writer is null)
- {
- throw new ArgumentNullException(nameof(writer));
- }
-
- if (this.Reference != null && !writer.GetSettings().ShouldInlineReference(this.Reference))
- {
- this.Reference.SerializeV2(writer);
- return;
- }
-
- this.SerializeV2WithoutReference(writer);
- }
-
- ///
- public IDictionary Extensions { get; set; } = new Dictionary();
-
- public bool UnresolvedReference { get; set; }
-
- public AsyncApiReference Reference { get; set; }
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "type", (a, n) => { a.Type = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "method", (a, n) => { a.Method = n.GetScalarValue(); } },
+ { "query", (a, n) => { a.Query = JsonSchemaDeserializer.LoadSchema(n); } },
+ };
- BindingType IBinding.Type => BindingType.Http;
+ public override string BindingKey => "http";
}
}
diff --git a/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaChannelBinding.cs
new file mode 100644
index 00000000..90b7c6ff
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaChannelBinding.cs
@@ -0,0 +1,80 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Kafka
+{
+ using System;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for Kafka channel settings.
+ ///
+ public class KafkaChannelBinding : ChannelBinding
+ {
+ ///
+ /// Kafka topic name if different from channel name.
+ ///
+ public string Topic { get; set; }
+
+ ///
+ /// Number of partitions configured on this topic (useful to know how many parallel consumers you may run).
+ ///
+ public int? Partitions { get; set; }
+
+ ///
+ /// Number of replicas configured on this topic.
+ ///
+ public int? Replicas { get; set; }
+
+ ///
+ /// Topic configuration properties that are relevant for the API.
+ ///
+ public TopicConfigurationObject TopicConfiguration { get; set; }
+
+ public override string BindingKey => "kafka";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "topic", (a, n) => { a.Topic = n.GetScalarValue(); } },
+ { "partitions", (a, n) => { a.Partitions = n.GetIntegerValue(); } },
+ { "topicConfiguration", (a, n) => { a.TopicConfiguration = n.ParseMap(kafkaChannelTopicConfigurationObjectFixedFields); } },
+ { "replicas", (a, n) => { a.Replicas = n.GetIntegerValue(); } },
+ };
+
+ private static FixedFieldMap kafkaChannelTopicConfigurationObjectFixedFields = new()
+ {
+ { "cleanup.policy", (a, n) => { a.CleanupPolicy = n.CreateSimpleList(s => s.GetScalarValue()); } },
+ { "retention.ms", (a, n) => { a.RetentionMilliseconds = n.GetLongValue(); } },
+ { "retention.bytes", (a, n) => { a.RetentionBytes = n.GetLongValue(); } },
+ { "delete.retention.ms", (a, n) => { a.DeleteRetentionMilliseconds = n.GetLongValue(); } },
+ { "max.message.bytes", (a, n) => { a.MaxMessageBytes = n.GetIntegerValue(); } },
+ { "confluent.key.schema.validation", (a, n) => { a.ConfluentKeySchemaValidation = n.GetBooleanValue(); } },
+ { "confluent.key.subject.name.strategy", (a, n) => { a.ConfluentKeySubjectName = n.GetScalarValue(); } },
+ { "confluent.value.schema.validation", (a, n) => { a.ConfluentValueSchemaValidation = n.GetBooleanValue(); } },
+ { "confluent.value.subject.name.strategy", (a, n) => { a.ConfluentValueSubjectName = n.GetScalarValue(); } },
+ };
+
+ ///
+ /// Serialize to AsyncAPI V2 document without using reference.
+ ///
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalProperty(AsyncApiConstants.Topic, this.Topic);
+ writer.WriteOptionalProperty(AsyncApiConstants.Partitions, this.Partitions);
+ writer.WriteOptionalProperty(AsyncApiConstants.Replicas, this.Replicas);
+ writer.WriteOptionalObject(AsyncApiConstants.TopicConfiguration, this.TopicConfiguration, (w, t) => t.Serialize(w));
+ writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI/Models/Bindings/Kafka/KafkaMessageBinding.cs b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaMessageBinding.cs
similarity index 56%
rename from src/LEGO.AsyncAPI/Models/Bindings/Kafka/KafkaMessageBinding.cs
rename to src/LEGO.AsyncAPI.Bindings/Kafka/KafkaMessageBinding.cs
index 1fd4bb90..2f665560 100644
--- a/src/LEGO.AsyncAPI/Models/Bindings/Kafka/KafkaMessageBinding.cs
+++ b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaMessageBinding.cs
@@ -1,16 +1,17 @@
// Copyright (c) The LEGO Group. All rights reserved.
-namespace LEGO.AsyncAPI.Models.Bindings.Kafka
+namespace LEGO.AsyncAPI.Bindings.Kafka
{
using System;
- using System.Collections.Generic;
- using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;
///
/// Binding class for kafka messages.
///
- public class KafkaMessageBinding : IMessageBinding
+ public class KafkaMessageBinding : MessageBinding
{
///
/// The message key. NOTE: You can also use the reference object way.
@@ -35,22 +36,8 @@ public class KafkaMessageBinding : IMessageBinding
///
/// The version of this binding. If omitted, "latest" MUST be assumed.
///
- public string BindingVersion { get; set; }
- ///
- /// Indicates if object is populated with data or is just a reference to the data.
- ///
- public bool UnresolvedReference { get; set; }
-
- ///
- /// Reference object.
- ///
- public AsyncApiReference Reference { get; set; }
-
- ///
- /// Serialize to AsyncAPI V2 document without using reference.
- ///
- public void SerializeV2WithoutReference(IAsyncApiWriter writer)
+ public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
@@ -64,6 +51,7 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer)
writer.WriteOptionalProperty(AsyncApiConstants.SchemaIdPayloadEncoding, this.SchemaIdPayloadEncoding);
writer.WriteOptionalProperty(AsyncApiConstants.SchemaLookupStrategy, this.SchemaLookupStrategy);
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
writer.WriteEndObject();
}
@@ -72,29 +60,17 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer)
/// Serializes the v2.
///
/// The writer.
- /// writer
- public void SerializeV2(IAsyncApiWriter writer)
- {
- if (writer is null)
- {
- throw new ArgumentNullException(nameof(writer));
- }
-
- if (this.Reference != null && !writer.GetSettings().ShouldInlineReference(this.Reference))
- {
- this.Reference.SerializeV2(writer);
- return;
- }
+ /// writer.
- this.SerializeV2WithoutReference(writer);
- }
+ public override string BindingKey => "kafka";
- ///
- /// Gets or sets this object MAY be extended with Specification Extensions.
- /// To protect the API from leaking the underlying JSON library, the extension data extraction is handled by a customer resolver.
- ///
- public IDictionary Extensions { get; set; } = new Dictionary();
-
- public BindingType Type => BindingType.Kafka;
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "key", (a, n) => { a.Key = JsonSchemaDeserializer.LoadSchema(n); } },
+ { "schemaIdLocation", (a, n) => { a.SchemaIdLocation = n.GetScalarValue(); } },
+ { "schemaIdPayloadEncoding", (a, n) => { a.SchemaIdPayloadEncoding = n.GetScalarValue(); } },
+ { "schemaLookupStrategy", (a, n) => { a.SchemaLookupStrategy = n.GetScalarValue(); } },
+ };
}
}
diff --git a/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaOperationBinding.cs
new file mode 100644
index 00000000..53db7ae0
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaOperationBinding.cs
@@ -0,0 +1,53 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Kafka
+{
+ using System;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for Kafka operations.
+ ///
+ public class KafkaOperationBinding : OperationBinding
+ {
+ ///
+ /// Id of the consumer group.
+ ///
+ public AsyncApiSchema GroupId { get; set; }
+
+ ///
+ /// Id of the consumer inside a consumer group.
+ ///
+ public AsyncApiSchema ClientId { get; set; }
+
+ public override string BindingKey => "kafka";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "groupId", (a, n) => { a.GroupId = JsonSchemaDeserializer.LoadSchema(n); } },
+ { "clientId", (a, n) => { a.ClientId = JsonSchemaDeserializer.LoadSchema(n); } },
+ };
+
+ ///
+ /// Serialize to AsyncAPI V2 document without using reference.
+ ///
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalObject(AsyncApiConstants.GroupId, this.GroupId, (w, h) => h.SerializeV2(w));
+ writer.WriteOptionalObject(AsyncApiConstants.ClientId, this.ClientId, (w, h) => h.SerializeV2(w));
+ writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI/Models/Bindings/Kafka/KafkaServerBinding.cs b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaServerBinding.cs
similarity index 51%
rename from src/LEGO.AsyncAPI/Models/Bindings/Kafka/KafkaServerBinding.cs
rename to src/LEGO.AsyncAPI.Bindings/Kafka/KafkaServerBinding.cs
index bd9d6b19..c679d46b 100644
--- a/src/LEGO.AsyncAPI/Models/Bindings/Kafka/KafkaServerBinding.cs
+++ b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaServerBinding.cs
@@ -1,44 +1,40 @@
// Copyright (c) The LEGO Group. All rights reserved.
-namespace LEGO.AsyncAPI.Models.Bindings.Kafka
+namespace LEGO.AsyncAPI.Bindings.Kafka
{
using System;
- using System.Collections.Generic;
- using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;
///
/// Binding class for Kafka server settings.
///
- public class KafkaServerBinding : IServerBinding
+ public class KafkaServerBinding : ServerBinding
{
///
- /// API URL for the Schema Registry used when producing Kafka messages (if a Schema Registry was used)
+ /// API URL for the Schema Registry used when producing Kafka messages (if a Schema Registry was used).
///
public string SchemaRegistryUrl { get; set; }
///
- /// The vendor of Schema Registry and Kafka serdes library that should be used (e.g. apicurio, confluent, ibm, or karapace)
+ /// The vendor of Schema Registry and Kafka serdes library that should be used (e.g. apicurio, confluent, ibm, or karapace).
///
public string SchemaRegistryVendor { get; set; }
- ///
- /// The version of this binding.
- ///
- public string BindingVersion { get; set; }
-
- public BindingType Type => BindingType.Kafka;
-
- public bool UnresolvedReference { get; set; }
-
- public AsyncApiReference Reference { get; set; }
+ public override string BindingKey => "kafka";
- public IDictionary Extensions { get; set; } = new Dictionary();
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "schemaRegistryUrl", (a, n) => { a.SchemaRegistryUrl = n.GetScalarValue(); } },
+ { "schemaRegistryVendor", (a, n) => { a.SchemaRegistryVendor = n.GetScalarValue(); } },
+ };
///
/// Serialize to AsyncAPI V2 document without using reference.
///
- public void SerializeV2WithoutReference(IAsyncApiWriter writer)
+ public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
@@ -49,24 +45,8 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer)
writer.WriteOptionalProperty(AsyncApiConstants.SchemaRegistryUrl, this.SchemaRegistryUrl);
writer.WriteOptionalProperty(AsyncApiConstants.SchemaRegistryVendor, this.SchemaRegistryVendor);
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
-
+ writer.WriteExtensions(this.Extensions);
writer.WriteEndObject();
}
-
- public void SerializeV2(IAsyncApiWriter writer)
- {
- if (writer is null)
- {
- throw new ArgumentNullException(nameof(writer));
- }
-
- if (this.Reference != null && !writer.GetSettings().ShouldInlineReference(this.Reference))
- {
- this.Reference.SerializeV2(writer);
- return;
- }
-
- this.SerializeV2WithoutReference(writer);
- }
}
}
diff --git a/src/LEGO.AsyncAPI.Bindings/Kafka/TopicConfigurationObject.cs b/src/LEGO.AsyncAPI.Bindings/Kafka/TopicConfigurationObject.cs
new file mode 100644
index 00000000..cbf7c955
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Kafka/TopicConfigurationObject.cs
@@ -0,0 +1,78 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Kafka
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class TopicConfigurationObject : IAsyncApiElement
+ {
+ ///
+ /// The cleanup.policy configuration option.
+ ///
+ public List CleanupPolicy { get; set; }
+
+ ///
+ /// The retention.ms configuration option.
+ ///
+ public long? RetentionMilliseconds { get; set; }
+
+ ///
+ /// The retention.bytes configuration option.
+ ///
+ public long? RetentionBytes { get; set; }
+
+ ///
+ /// The delete.retention.ms configuration option.
+ ///
+ public long? DeleteRetentionMilliseconds { get; set; }
+
+ ///
+ /// The max.message.bytes configuration option.
+ ///
+ public int? MaxMessageBytes { get; set; }
+
+ ///
+ /// The confluent.key.schema.validation configuration option.
+ ///
+ public bool? ConfluentKeySchemaValidation { get; set; }
+
+ ///
+ /// The confluent.key.subject.name.strategy configuration option.
+ ///
+ public string ConfluentKeySubjectName { get; set; }
+
+ ///
+ /// The confluent.value.schema.validation configuration option.
+ ///
+ public bool? ConfluentValueSchemaValidation { get; set; }
+
+ ///
+ /// The confluent.value.subject.name.strategy configuration option.
+ ///
+ public string ConfluentValueSubjectName { get; set; }
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalCollection(AsyncApiConstants.CleanupPolicy, this.CleanupPolicy, (w, s) => w.WriteValue(s));
+ writer.WriteOptionalProperty(AsyncApiConstants.RetentionMilliseconds, this.RetentionMilliseconds);
+ writer.WriteOptionalProperty(AsyncApiConstants.RetentionBytes, this.RetentionBytes);
+ writer.WriteOptionalProperty(AsyncApiConstants.DeleteRetentionMilliseconds, this.DeleteRetentionMilliseconds);
+ writer.WriteOptionalProperty(AsyncApiConstants.MaxMessageBytes, this.MaxMessageBytes);
+ writer.WriteOptionalProperty(AsyncApiConstants.ConfluentKeySchemaValidation, this.ConfluentKeySchemaValidation);
+ writer.WriteOptionalProperty(AsyncApiConstants.ConfluentKeySubjectName, this.ConfluentKeySubjectName);
+ writer.WriteOptionalProperty(AsyncApiConstants.ConfluentValueSchemaValidation, this.ConfluentValueSchemaValidation);
+ writer.WriteOptionalProperty(AsyncApiConstants.ConfluentValueSubjectName, this.ConfluentValueSubjectName);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/LEGO.AsyncAPI.Bindings.csproj b/src/LEGO.AsyncAPI.Bindings/LEGO.AsyncAPI.Bindings.csproj
new file mode 100644
index 00000000..9c0b025e
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/LEGO.AsyncAPI.Bindings.csproj
@@ -0,0 +1,29 @@
+
+
+
+ AsyncAPI.NET Bindings
+ AsyncAPI.NET.Bindings
+ LEGO.AsyncAPI.Bindings
+ LEGO.AsyncAPI.Bindings
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
diff --git a/src/LEGO.AsyncAPI.Bindings/MQTT/LastWill.cs b/src/LEGO.AsyncAPI.Bindings/MQTT/LastWill.cs
new file mode 100644
index 00000000..23118bfa
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/MQTT/LastWill.cs
@@ -0,0 +1,48 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.MQTT
+{
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+ using System;
+
+ public class LastWill : IAsyncApiElement
+ {
+ ///
+ /// The topic where the Last Will and Testament message will be sent.
+ ///
+ public string Topic { get; set; }
+
+ ///
+ /// Defines how hard the broker/client will try to ensure that
+ /// the Last Will and Testament message is received.
+ /// Its value MUST be either 0, 1 or 2.
+ ///
+ public uint? QoS { get; set; }
+
+ ///
+ /// Last Will message.
+ ///
+ public string Message { get; set; }
+
+ ///
+ /// Whether the broker should retain the Last Will and Testament message or not.
+ ///
+ public bool Retain { get; set; }
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("topic", this.Topic);
+ writer.WriteOptionalProperty("qos", (int?)this.QoS);
+ writer.WriteOptionalProperty("message", this.Message);
+ writer.WriteRequiredProperty("retain", this.Retain);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs
new file mode 100644
index 00000000..b48e5ae9
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs
@@ -0,0 +1,65 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.MQTT
+{
+ using System;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for MQTT messages.
+ ///
+ public class MQTTMessageBinding : MessageBinding
+ {
+ ///
+ /// Indicates the format of the payload.
+ /// Either: 0 (zero) for unspecified bytes, or 1 for UTF-8 encoded character data.
+ ///
+ public int? PayloadFormatIndicator { get; set; }
+
+ ///
+ /// Correlation Data is used to identify the request the response message is for.
+ ///
+ public AsyncApiSchema CorrelationData { get; set; }
+
+ ///
+ /// String describing the content type of the message payload.
+ /// This should not conflict with the contentType field of the associated AsyncAPI Message object.
+ ///
+ public string ContentType { get; set; }
+
+ ///
+ /// The topic (channel URI) for a response message.
+ ///
+ public string ResponseTopic { get; set; }
+
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalProperty("payloadFormatIndicator", this.PayloadFormatIndicator);
+ writer.WriteOptionalObject("correlationData", this.CorrelationData, (w, h) => h.SerializeV2(w));
+ writer.WriteOptionalProperty("contentType", this.ContentType);
+ writer.WriteOptionalProperty("responseTopic", this.ResponseTopic);
+ writer.WriteOptionalProperty("bindingVersion", this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+
+ public override string BindingKey => "mqtt";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "payloadFormatIndicator", (a, n) => { a.PayloadFormatIndicator = n.GetIntegerValueOrDefault(); } },
+ { "correlationData", (a, n) => { a.CorrelationData = JsonSchemaDeserializer.LoadSchema(n); } },
+ { "contentType", (a, n) => { a.ContentType = n.GetScalarValue(); } },
+ { "responseTopic", (a, n) => { a.ResponseTopic = n.GetScalarValue(); } },
+ };
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTOperationBinding.cs
new file mode 100644
index 00000000..d3155ecd
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTOperationBinding.cs
@@ -0,0 +1,61 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.MQTT
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for MQTT operations.
+ ///
+ public class MQTTOperationBinding : OperationBinding
+ {
+ ///
+ /// Defines the Quality of Service (QoS) levels for the message flow between client and server.
+ /// Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery).
+ ///
+ public int QoS { get; set; }
+
+ ///
+ /// Whether the broker should retain the message or not.
+ ///
+ public bool Retain { get; set; }
+
+ ///
+ /// Interval in seconds or a Schema Object containing the definition of the lifetime of the message.
+ ///
+ public int? MessageExpiryInterval { get; set; }
+
+ public override string BindingKey => "mqtt";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "qos", (a, n) => { a.QoS = n.GetIntegerValue(); } },
+ { "retain", (a, n) => { a.Retain = n.GetBooleanValue(); } },
+ { "messageExpiryInterval", (a, n) => { a.MessageExpiryInterval = n.GetIntegerValueOrDefault(); } },
+ };
+
+ ///
+ /// Serialize to AsyncAPI V2 document without using reference.
+ ///
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("qos", this.QoS);
+ writer.WriteRequiredProperty("retain", this.Retain);
+ writer.WriteOptionalProperty("messageExpiryInterval", this.MessageExpiryInterval);
+ writer.WriteOptionalProperty("bindingVersion", this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTServerBinding.cs b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTServerBinding.cs
new file mode 100644
index 00000000..03b88b23
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTServerBinding.cs
@@ -0,0 +1,93 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.MQTT
+{
+ using System;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for MQTT channel settings.
+ ///
+ public class MQTTServerBinding : ServerBinding
+ {
+ ///
+ /// The client identifier.
+ ///
+ public string ClientId { get; set; }
+
+ ///
+ /// Whether to create a persistent connection or not.
+ /// When false, the connection will be persistent.
+ /// This is called clean start in MQTTv5.
+ ///
+ public bool? CleanSession { get; set; }
+
+ ///
+ /// Last Will and Testament configuration.
+ ///
+ public LastWill LastWill { get; set; }
+
+ ///
+ /// Interval in seconds of the longest period of time
+ /// the broker and the client can endure without sending a message.
+ ///
+ public int? KeepAlive { get; set; }
+
+ ///
+ /// Interval in seconds the broker maintains a session
+ /// for a disconnected client until this interval expires.
+ ///
+ public int? SessionExpiryInterval { get; set; }
+
+ ///
+ /// Number of bytes representing the maximum packet size
+ /// the client is willing to accept.
+ ///
+ public int? MaximumPacketSize { get; set; }
+
+ public override string BindingKey => "mqtt";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "clientId", (a, n) => { a.ClientId = n.GetScalarValue(); } },
+ { "cleanSession", (a, n) => { a.CleanSession = n.GetBooleanValueOrDefault(); } },
+ { "lastWill", (a, n) => { a.LastWill = n.ParseMap(LastWillFixedFields); } },
+ { "keepAlive", (a, n) => { a.KeepAlive = n.GetIntegerValueOrDefault(); } },
+ { "sessionExpiryInterval", (a, n) => { a.SessionExpiryInterval = n.GetIntegerValueOrDefault(); } },
+ { "maximumPacketSize", (a, n) => { a.MaximumPacketSize = n.GetIntegerValueOrDefault(); } },
+ };
+
+ private static FixedFieldMap LastWillFixedFields = new()
+ {
+ { "topic", (a, n) => { a.Topic = n.GetScalarValue(); } },
+ { "qos", (a, n) => { a.QoS = (uint?)n.GetIntegerValueOrDefault(); } },
+ { "message", (a, n) => { a.Message = n.GetScalarValue(); } },
+ { "retain", (a, n) => { a.Retain = n.GetBooleanValue(); } },
+ };
+
+ ///
+ /// Serialize to AsyncAPI V2 document without using reference.
+ ///
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("clientId", this.ClientId);
+ writer.WriteOptionalProperty("cleanSession", this.CleanSession);
+ writer.WriteOptionalObject("lastWill", this.LastWill, (w, l) => l.Serialize(w));
+ writer.WriteOptionalProperty("keepAlive", this.KeepAlive);
+ writer.WriteOptionalProperty("sessionExpiryInterval", this.SessionExpiryInterval);
+ writer.WriteOptionalProperty("maximumPacketSize", this.MaximumPacketSize);
+ writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/MessageBinding{T}.cs b/src/LEGO.AsyncAPI.Bindings/MessageBinding{T}.cs
new file mode 100644
index 00000000..3e3956f9
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/MessageBinding{T}.cs
@@ -0,0 +1,16 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings
+{
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public abstract class MessageBinding : Binding, IMessageBinding
+ where T : IMessageBinding, new()
+ {
+ protected abstract FixedFieldMap FixedFieldMap { get; }
+
+ public override T LoadBinding(PropertyNode node) => BindingDeserializer.LoadBinding("MessageBinding", node.Value, this.FixedFieldMap);
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/OperationBinding{T}.cs b/src/LEGO.AsyncAPI.Bindings/OperationBinding{T}.cs
new file mode 100644
index 00000000..626250ee
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/OperationBinding{T}.cs
@@ -0,0 +1,16 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings
+{
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public abstract class OperationBinding : Binding, IOperationBinding
+ where T : IOperationBinding, new()
+ {
+ protected abstract FixedFieldMap FixedFieldMap { get; }
+
+ public override T LoadBinding(PropertyNode node) => BindingDeserializer.LoadBinding("OperationBinding", node.Value, this.FixedFieldMap);
+ }
+}
diff --git a/src/LEGO.AsyncAPI/Models/Bindings/Pulsar/Persistence.cs b/src/LEGO.AsyncAPI.Bindings/Pulsar/Persistence.cs
similarity index 100%
rename from src/LEGO.AsyncAPI/Models/Bindings/Pulsar/Persistence.cs
rename to src/LEGO.AsyncAPI.Bindings/Pulsar/Persistence.cs
diff --git a/src/LEGO.AsyncAPI/Models/Bindings/Pulsar/PulsarChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/Pulsar/PulsarChannelBinding.cs
similarity index 57%
rename from src/LEGO.AsyncAPI/Models/Bindings/Pulsar/PulsarChannelBinding.cs
rename to src/LEGO.AsyncAPI.Bindings/Pulsar/PulsarChannelBinding.cs
index 7a4f504f..88435b74 100644
--- a/src/LEGO.AsyncAPI/Models/Bindings/Pulsar/PulsarChannelBinding.cs
+++ b/src/LEGO.AsyncAPI.Bindings/Pulsar/PulsarChannelBinding.cs
@@ -1,16 +1,15 @@
// Copyright (c) The LEGO Group. All rights reserved.
-namespace LEGO.AsyncAPI.Models.Bindings.Pulsar
+namespace LEGO.AsyncAPI.Bindings.Pulsar
{
using System;
using System.Collections.Generic;
- using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Models.Bindings.Pulsar;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;
- ///
- /// Binding class for Pulsar server settings.
- ///
- public class PulsarChannelBinding : IChannelBinding
+ public class PulsarChannelBinding : ChannelBinding
{
///
/// The namespace associated with the topic.
@@ -20,7 +19,7 @@ public class PulsarChannelBinding : IChannelBinding
///
/// persistence of the topic in Pulsar persistent or non-persistent.
///
- public Persistence? Persistence { get; set; }
+ public Persistence Persistence { get; set; }
///
/// Topic compaction threshold given in bytes.
@@ -38,7 +37,7 @@ public class PulsarChannelBinding : IChannelBinding
public RetentionDefinition Retention { get; set; }
///
- /// Message Time-to-live in seconds.
+ /// Message Time-to-live in seconds.
///
public int? TTL { get; set; }
@@ -47,22 +46,9 @@ public class PulsarChannelBinding : IChannelBinding
///
public bool? Deduplication { get; set; }
- ///
- /// The version of this binding.
- public string BindingVersion { get; set; }
-
- public BindingType Type => BindingType.Pulsar;
-
- public bool UnresolvedReference { get; set; }
-
- public AsyncApiReference Reference { get; set; }
-
- public IDictionary Extensions { get; set; } = new Dictionary();
+ public override string BindingKey => "pulsar";
- ///
- /// Serialize to AsyncAPI V2 document without using reference.
- ///
- public void SerializeV2WithoutReference(IAsyncApiWriter writer)
+ public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
@@ -78,24 +64,26 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer)
writer.WriteOptionalProperty(AsyncApiConstants.TTL, this.TTL);
writer.WriteOptionalProperty(AsyncApiConstants.Deduplication, this.Deduplication);
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
-
+ writer.WriteExtensions(this.Extensions);
writer.WriteEndObject();
}
- public void SerializeV2(IAsyncApiWriter writer)
+ protected override FixedFieldMap FixedFieldMap => new()
{
- if (writer is null)
- {
- throw new ArgumentNullException(nameof(writer));
- }
-
- if (this.Reference != null && !writer.GetSettings().ShouldInlineReference(this.Reference))
- {
- this.Reference.SerializeV2(writer);
- return;
- }
-
- this.SerializeV2WithoutReference(writer);
- }
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "namespace", (a, n) => { a.Namespace = n.GetScalarValue(); } },
+ { "persistence", (a, n) => { a.Persistence = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "compaction", (a, n) => { a.Compaction = n.GetIntegerValue(); } },
+ { "retention", (a, n) => { a.Retention = n.ParseMap(this.pulsarServerBindingRetentionFixedFields); } },
+ { "geo-replication", (a, n) => { a.GeoReplication = n.CreateSimpleList(s => s.GetScalarValue()); } },
+ { "ttl", (a, n) => { a.TTL = n.GetIntegerValue(); } },
+ { "deduplication", (a, n) => { a.Deduplication = n.GetBooleanValue(); } },
+ };
+
+ private FixedFieldMap pulsarServerBindingRetentionFixedFields = new()
+ {
+ { "time", (a, n) => { a.Time = n.GetIntegerValue(); } },
+ { "size", (a, n) => { a.Size = n.GetIntegerValue(); } },
+ };
}
}
diff --git a/src/LEGO.AsyncAPI.Bindings/Pulsar/PulsarServerBinding.cs b/src/LEGO.AsyncAPI.Bindings/Pulsar/PulsarServerBinding.cs
new file mode 100644
index 00000000..e767443d
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Pulsar/PulsarServerBinding.cs
@@ -0,0 +1,42 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Pulsar
+{
+ using System;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for Pulsar server settings.
+ ///
+ public class PulsarServerBinding : ServerBinding
+ {
+ ///
+ /// The pulsar tenant. If omitted, "public" must be assumed.
+ ///
+ public string Tenant { get; set; }
+
+ public override string BindingKey => "pulsar";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "tenant", (a, n) => { a.Tenant = n.GetScalarValue(); } },
+ };
+
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalProperty(AsyncApiConstants.Tenant, this.Tenant);
+ writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI/Models/Bindings/Pulsar/RetentionDefinition.cs b/src/LEGO.AsyncAPI.Bindings/Pulsar/RetentionDefinition.cs
similarity index 100%
rename from src/LEGO.AsyncAPI/Models/Bindings/Pulsar/RetentionDefinition.cs
rename to src/LEGO.AsyncAPI.Bindings/Pulsar/RetentionDefinition.cs
diff --git a/src/LEGO.AsyncAPI.Bindings/ServerBinding{T}.cs b/src/LEGO.AsyncAPI.Bindings/ServerBinding{T}.cs
new file mode 100644
index 00000000..6c1c58cf
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/ServerBinding{T}.cs
@@ -0,0 +1,16 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings
+{
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public abstract class ServerBinding : Binding, IServerBinding
+ where T : IServerBinding, new()
+ {
+ protected abstract FixedFieldMap FixedFieldMap { get; }
+
+ public override T LoadBinding(PropertyNode node) => BindingDeserializer.LoadBinding("ServerBinding", node.Value, this.FixedFieldMap);
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Condition.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Condition.cs
new file mode 100644
index 00000000..38b21da9
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/Condition.cs
@@ -0,0 +1,67 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using LEGO.AsyncAPI.Models.Interfaces;
+using LEGO.AsyncAPI.Readers.ParseNodes;
+using LEGO.AsyncAPI.Writers;
+
+public class Condition : IAsyncApiElement
+{
+ public Dictionary> Value { get; private set; }
+
+ public Condition(Dictionary> value)
+ {
+ this.Value = value;
+ }
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ foreach (var conditionValue in this.Value)
+ {
+ writer.WriteRequiredMap(conditionValue.Key, conditionValue.Value, (w, t) => t.Value.Write(w));
+ }
+
+ writer.WriteEndObject();
+ }
+
+ public static Condition Parse(ParseNode node)
+ {
+ switch (node)
+ {
+ case MapNode mapNode:
+ {
+ var conditionValues = new Dictionary>();
+ foreach (var conditionNode in mapNode)
+ {
+ switch (conditionNode.Value)
+ {
+ case MapNode conditionValueNode:
+ conditionValues.Add(conditionNode.Name, new Dictionary(conditionValueNode.Select(x =>
+ new KeyValuePair(x.Name, StringOrStringList.Parse(x.Value)))
+ .ToDictionary(x => x.Key, x => x.Value)));
+ break;
+ default:
+ throw new ArgumentException($"An error occured while parsing a {nameof(Condition)} node. " +
+ $"AWS condition values should be one or more key value pairs.");
+ }
+ }
+
+ return new Condition(conditionValues);
+ }
+
+ default:
+ throw new ArgumentException($"An error occured while parsing a {nameof(Condition)} node. " +
+ $"Node should contain a collection of condition types.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Consumer.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Consumer.cs
new file mode 100644
index 00000000..688c186f
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/Consumer.cs
@@ -0,0 +1,96 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Attributes;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class Consumer : IAsyncApiExtensible
+ {
+ ///
+ /// The protocol that this endpoint will receive messages by.
+ ///
+ public Protocol Protocol { get; set; }
+
+ ///
+ /// The endpoint messages are delivered to.
+ ///
+ public Identifier Endpoint { get; set; }
+
+ ///
+ /// Only receive a subset of messages from the channel, determined by this policy.
+ /// Depending on the FilterPolicyScope, a map of either a message attribute or message body to an array of possible matches. The match may be a simple string for an exact match, but it may also be an object that represents a constraint and values for that constraint.
+ ///
+ public AsyncApiAny FilterPolicy { get; set; }
+
+ ///
+ /// Determines whether the FilterPolicy applies to MessageAttributes or MessageBody.
+ ///
+ public FilterPolicyScope FilterPolicyScope { get; set; }
+
+ ///
+ /// If true AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If false the SNS attributes are included in the body.
+ ///
+ public bool RawMessageDelivery { get; set; }
+
+ ///
+ /// Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.
+ ///
+ public RedrivePolicy RedrivePolicy { get; set; }
+
+ ///
+ /// Policy for retries to HTTP. The parameter is for that SNS Subscription and overrides any policy on the SNS Topic.
+ ///
+ public DeliveryPolicy DeliveryPolicy { get; set; }
+
+ ///
+ /// The display name to use with an SNS subscription.
+ ///
+ public string DisplayName { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("protocol", this.Protocol.GetDisplayName());
+ writer.WriteRequiredObject("endpoint", this.Endpoint, (w, e) => e.Serialize(w));
+ writer.WriteOptionalObject("filterPolicy", this.FilterPolicy, (w, f) => f.Write(w));
+ writer.WriteOptionalProperty("filterPolicyScope", this.FilterPolicyScope.GetDisplayName());
+ writer.WriteRequiredProperty("rawMessageDelivery", this.RawMessageDelivery);
+ writer.WriteOptionalObject("redrivePolicy", this.RedrivePolicy, (w, p) => p.Serialize(w));
+ writer.WriteOptionalObject("deliveryPolicy", this.DeliveryPolicy, (w, p) => p.Serialize(w));
+ writer.WriteOptionalProperty("displayName", this.DisplayName);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+
+ public enum Protocol
+ {
+ [Display("http")] Http,
+ [Display("https")] Https,
+ [Display("email")] Email,
+ [Display("email-json")] EmailJson,
+ [Display("sms")] Sms,
+ [Display("sqs")] Sqs,
+ [Display("application")] Application,
+ [Display("lambda")] Lambda,
+ [Display("firehose")] Firehose,
+ }
+
+ public enum FilterPolicyScope
+ {
+ [Display("MessageAttributes")] MessageAttributes,
+ [Display("MessageBody")] MessageBody,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/DeliveryPolicy.cs b/src/LEGO.AsyncAPI.Bindings/Sns/DeliveryPolicy.cs
new file mode 100644
index 00000000..9ed78b19
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/DeliveryPolicy.cs
@@ -0,0 +1,83 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Attributes;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class DeliveryPolicy : IAsyncApiExtensible
+ {
+ ///
+ /// The minimum delay for a retry in seconds.
+ ///
+ public int? MinDelayTarget { get; set; }
+
+ ///
+ /// The maximum delay for a retry in seconds.
+ ///
+ public int? MaxDelayTarget { get; set; }
+
+ ///
+ /// The total number of retries, including immediate, pre-backoff, backoff, and post-backoff retries.
+ ///
+ public int? NumRetries { get; set; }
+
+ ///
+ /// The number of immediate retries (with no delay).
+ ///
+ public int? NumNoDelayRetries { get; set; }
+
+ ///
+ /// The number of immediate retries (with delay).
+ ///
+ public int? NumMinDelayRetries { get; set; }
+
+ ///
+ /// The number of post-backoff phase retries, with the maximum delay between retries.
+ ///
+ public int? NumMaxDelayRetries { get; set; }
+
+ ///
+ /// The algorithm for backoff between retries.
+ ///
+ public BackoffFunction BackoffFunction { get; set; }
+
+ ///
+ /// The maximum number of deliveries per second, per subscription.
+ ///
+ public int? MaxReceivesPerSecond { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalProperty("minDelayTarget", this.MinDelayTarget);
+ writer.WriteOptionalProperty("maxDelayTarget", this.MaxDelayTarget);
+ writer.WriteOptionalProperty("numRetries", this.NumRetries);
+ writer.WriteOptionalProperty("numNoDelayRetries", this.NumNoDelayRetries);
+ writer.WriteOptionalProperty("numMinDelayRetries", this.NumMinDelayRetries);
+ writer.WriteOptionalProperty("numMaxDelayRetries", this.NumMaxDelayRetries);
+ writer.WriteOptionalProperty("backoffFunction", this.BackoffFunction.GetDisplayName());
+ writer.WriteOptionalProperty("maxReceivesPerSecond", this.MaxReceivesPerSecond);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+
+ public enum BackoffFunction
+ {
+ [Display("arithmetic")] Arithmetic,
+ [Display("exponential")] Exponential,
+ [Display("geometric")] Geometric,
+ [Display("linear")] Linear,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Identifier.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Identifier.cs
new file mode 100644
index 00000000..960c1c54
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/Identifier.cs
@@ -0,0 +1,41 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class Identifier : IAsyncApiExtensible
+ {
+ public string Url { get; set; }
+
+ public string Email { get; set; }
+
+ public string Phone { get; set; }
+
+ public string Arn { get; set; }
+
+ public string Name { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalProperty("url", this.Url);
+ writer.WriteOptionalProperty("email", this.Email);
+ writer.WriteOptionalProperty("phone", this.Phone);
+ writer.WriteOptionalProperty("arn", this.Arn);
+ writer.WriteOptionalProperty("name", this.Name);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Ordering.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Ordering.cs
new file mode 100644
index 00000000..23f69f52
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/Ordering.cs
@@ -0,0 +1,47 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Attributes;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class Ordering : IAsyncApiExtensible
+ {
+ ///
+ /// What type of SNS Topic is this?
+ ///
+ public OrderingType Type { get; set; }
+
+ ///
+ /// True to turn on de-duplication of messages for a channel.
+ ///
+ public bool ContentBasedDeduplication { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("type", this.Type.GetDisplayName());
+ writer.WriteOptionalProperty("contentBasedDeduplication", this.ContentBasedDeduplication);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+
+ public enum OrderingType
+ {
+ [Display("standard")]
+ Standard,
+ [Display("FIFO")]
+ Fifo,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Policy.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Policy.cs
new file mode 100644
index 00000000..a4232e5e
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/Policy.cs
@@ -0,0 +1,32 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class Policy : IAsyncApiExtensible
+ {
+ ///
+ /// An array of statement objects, each of which controls a permission for this topic.
+ ///
+ public List Statements { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalCollection("statements", this.Statements, (w, t) => t.Serialize(w));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Principal.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Principal.cs
new file mode 100644
index 00000000..a803f6c2
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/Principal.cs
@@ -0,0 +1,63 @@
+namespace LEGO.AsyncAPI.Bindings.Sns;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using LEGO.AsyncAPI.Models.Interfaces;
+using LEGO.AsyncAPI.Readers.ParseNodes;
+using LEGO.AsyncAPI.Writers;
+
+public abstract class Principal : IAsyncApiElement
+{
+ public abstract void Serialize(IAsyncApiWriter writer);
+
+ public static Principal Parse(ParseNode node)
+ {
+ switch (node)
+ {
+ case ValueNode:
+ var nodeValue = node.GetScalarValue();
+ if (!IsStarString(nodeValue))
+ {
+ throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
+ $"Principal value without a property name can only be a string value of '*'.");
+ }
+
+ return new PrincipalStar();
+
+ case MapNode mapNode:
+ {
+ var propertyNode = mapNode.First();
+ if (!IsValidPrincipalProperty(propertyNode.Name))
+ {
+ throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
+ $"Node should contain a valid AWS principal property name.");
+ }
+
+ var principalValue = new KeyValuePair(
+ propertyNode.Name,
+ StringOrStringList.Parse(propertyNode.Value));
+
+ return new PrincipalObject(principalValue);
+ }
+
+ default:
+ throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
+ $"Node should contain a string value of '*' or a valid AWS principal property.");
+ }
+ }
+
+ private static bool IsStarString(JsonNode value)
+ {
+ var element = JsonDocument.Parse(value.ToJsonString()).RootElement;
+
+ return element.ValueKind == JsonValueKind.String && element.ValueEquals("*");
+ }
+
+ private static bool IsValidPrincipalProperty(string property)
+ {
+ return new[] { "AWS", "Service" }.Contains(property);
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/PrincipalObject.cs b/src/LEGO.AsyncAPI.Bindings/Sns/PrincipalObject.cs
new file mode 100644
index 00000000..209be8bf
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/PrincipalObject.cs
@@ -0,0 +1,27 @@
+namespace LEGO.AsyncAPI.Bindings.Sns;
+
+using System;
+using System.Collections.Generic;
+using LEGO.AsyncAPI.Writers;
+
+public class PrincipalObject : Principal
+{
+ public KeyValuePair Value { get; private set; }
+
+ public PrincipalObject(KeyValuePair value)
+ {
+ this.Value = value;
+ }
+
+ public override void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredObject(this.Value.Key, this.Value.Value, (w, t) => t.Value.Write(w));
+ writer.WriteEndObject();
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/PrincipalStar.cs b/src/LEGO.AsyncAPI.Bindings/Sns/PrincipalStar.cs
new file mode 100644
index 00000000..c885d252
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/PrincipalStar.cs
@@ -0,0 +1,24 @@
+namespace LEGO.AsyncAPI.Bindings.Sns;
+
+using System;
+using LEGO.AsyncAPI.Writers;
+
+public class PrincipalStar : Principal
+{
+ public string Value { get; private set; }
+
+ public PrincipalStar()
+ {
+ this.Value = "*";
+ }
+
+ public override void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteValue(this.Value);
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/RedrivePolicy.cs b/src/LEGO.AsyncAPI.Bindings/Sns/RedrivePolicy.cs
new file mode 100644
index 00000000..01e6d7e2
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/RedrivePolicy.cs
@@ -0,0 +1,38 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class RedrivePolicy : IAsyncApiExtensible
+ {
+ ///
+ /// Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.
+ ///
+ public Identifier DeadLetterQueue { get; set; }
+
+ ///
+ /// The number of times a message is delivered to the source queue before being moved to the dead-letter queue.
+ ///
+ public int? MaxReceiveCount { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredObject("deadLetterQueue", this.DeadLetterQueue, (w, q) => q.Serialize(w));
+ writer.WriteOptionalProperty("maxReceiveCount", this.MaxReceiveCount);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/SnsChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/Sns/SnsChannelBinding.cs
new file mode 100644
index 00000000..4394cdd1
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/SnsChannelBinding.cs
@@ -0,0 +1,83 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Bindings;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// Binding class for SNS channel settings.
+ ///
+ public class SnsChannelBinding : ChannelBinding
+ {
+ ///
+ /// The name of the topic. Can be different from the channel name to allow flexibility around AWS resource naming limitations.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic.
+ ///
+ public Ordering Ordering { get; set; }
+
+ ///
+ /// The security policy for the SNS Topic.
+ ///
+ public Policy Policy { get; set; }
+
+ ///
+ /// Key-value pairs that represent AWS tags on the topic.
+ ///
+ public Dictionary Tags { get; set; }
+
+ public override string BindingKey => "sns";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "name", (a, n) => { a.Name = n.GetScalarValue(); } },
+ { "ordering", (a, n) => { a.Ordering = n.ParseMapWithExtensions(this.orderingFixedFields); } },
+ { "policy", (a, n) => { a.Policy = n.ParseMapWithExtensions(this.policyFixedFields); } },
+ { "tags", (a, n) => { a.Tags = n.CreateSimpleMap(s => s.GetScalarValue()); } },
+ };
+
+ private FixedFieldMap orderingFixedFields = new()
+ {
+ { "type", (a, n) => { a.Type = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "contentBasedDeduplication", (a, n) => { a.ContentBasedDeduplication = n.GetBooleanValue(); } },
+ };
+
+ private FixedFieldMap policyFixedFields = new()
+ {
+ { "statements", (a, n) => { a.Statements = n.CreateList(s => s.ParseMapWithExtensions(statementFixedFields)); } },
+ };
+
+ private static FixedFieldMap statementFixedFields = new()
+ {
+ { "effect", (a, n) => { a.Effect = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "principal", (a, n) => { a.Principal = Principal.Parse(n); } },
+ { "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } },
+ { "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } },
+ { "condition", (a, n) => { a.Condition = Condition.Parse(n); } },
+ };
+
+ ///
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("name", this.Name);
+ writer.WriteOptionalObject("ordering", this.Ordering, (w, t) => t.Serialize(w));
+ writer.WriteOptionalObject("policy", this.Policy, (w, t) => t.Serialize(w));
+ writer.WriteOptionalMap("tags", this.Tags, (w, t) => w.WriteValue(t));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/SnsOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/Sns/SnsOperationBinding.cs
new file mode 100644
index 00000000..350b7a59
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/SnsOperationBinding.cs
@@ -0,0 +1,93 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// This object contains information about the operation representation in SNS.
+ ///
+ public class SnsOperationBinding : OperationBinding
+ {
+ ///
+ /// Often we can assume that the SNS Topic is the channel name-we provide this field in case the you need to supply the ARN, or the Topic name is not the channel name in the AsyncAPI document.
+ ///
+ public Identifier Topic { get; set; }
+
+ ///
+ /// The protocols that listen to this topic and their endpoints.
+ ///
+ public List Consumers { get; set; }
+
+ ///
+ /// Policy for retries to HTTP. The field is the default for HTTP receivers of the SNS Topic which may be overridden by a specific consumer.
+ ///
+ public DeliveryPolicy DeliveryPolicy { get; set; }
+
+ public override string BindingKey => "sns";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "topic", (a, n) => { a.Topic = n.ParseMapWithExtensions(this.identifierFixFields); } },
+ { "consumers", (a, n) => { a.Consumers = n.CreateList(s => s.ParseMapWithExtensions(this.consumerFixedFields)); } },
+ { "deliveryPolicy", (a, n) => { a.DeliveryPolicy = n.ParseMapWithExtensions(this.deliveryPolicyFixedFields); } },
+ };
+
+ private FixedFieldMap identifierFixFields => new()
+ {
+ { "url", (a, n) => { a.Url = n.GetScalarValue(); } },
+ { "email", (a, n) => { a.Email = n.GetScalarValue(); } },
+ { "phone", (a, n) => { a.Phone = n.GetScalarValue(); } },
+ { "arn", (a, n) => { a.Arn = n.GetScalarValue(); } },
+ { "name", (a, n) => { a.Name = n.GetScalarValue(); } },
+ };
+
+ private FixedFieldMap consumerFixedFields => new()
+ {
+ { "protocol", (a, n) => { a.Protocol = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "endpoint", (a, n) => { a.Endpoint = n.ParseMapWithExtensions(this.identifierFixFields); } },
+ { "filterPolicy", (a, n) => { a.FilterPolicy = n.CreateAny(); } },
+ { "filterPolicyScope", (a, n) => { a.FilterPolicyScope = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "rawMessageDelivery", (a, n) => { a.RawMessageDelivery = n.GetBooleanValue(); } },
+ { "redrivePolicy", (a, n) => { a.RedrivePolicy = n.ParseMapWithExtensions(this.redrivePolicyFixedFields); } },
+ { "deliveryPolicy", (a, n) => { a.DeliveryPolicy = n.ParseMapWithExtensions(this.deliveryPolicyFixedFields); } },
+ { "displayName", (a, n) => { a.DisplayName = n.GetScalarValue(); } },
+ };
+
+ private FixedFieldMap redrivePolicyFixedFields => new()
+ {
+ { "deadLetterQueue", (a, n) => { a.DeadLetterQueue = n.ParseMapWithExtensions(identifierFixFields); } },
+ { "maxReceiveCount", (a, n) => { a.MaxReceiveCount = n.GetIntegerValue(); } },
+ };
+
+ private FixedFieldMap deliveryPolicyFixedFields => new()
+ {
+ { "minDelayTarget", (a, n) => { a.MinDelayTarget = n.GetIntegerValue(); } },
+ { "maxDelayTarget", (a, n) => { a.MaxDelayTarget = n.GetIntegerValue(); } },
+ { "numRetries", (a, n) => { a.NumRetries = n.GetIntegerValue(); } },
+ { "numNoDelayRetries", (a, n) => { a.NumNoDelayRetries = n.GetIntegerValue(); } },
+ { "numMinDelayRetries", (a, n) => { a.NumMinDelayRetries = n.GetIntegerValue(); } },
+ { "numMaxDelayRetries", (a, n) => { a.NumMaxDelayRetries = n.GetIntegerValue(); } },
+ { "backoffFunction", (a, n) => { a.BackoffFunction = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "maxReceivesPerSecond", (a, n) => { a.MaxReceivesPerSecond = n.GetIntegerValue(); } },
+ };
+
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalObject("topic", this.Topic, (w, t) => t.Serialize(w));
+ writer.WriteOptionalCollection("consumers", this.Consumers, (w, c) => c.Serialize(w));
+ writer.WriteOptionalObject("deliveryPolicy", this.DeliveryPolicy, (w, p) => p.Serialize(w));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sns/Statement.cs b/src/LEGO.AsyncAPI.Bindings/Sns/Statement.cs
new file mode 100644
index 00000000..da93cfbf
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sns/Statement.cs
@@ -0,0 +1,65 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+namespace LEGO.AsyncAPI.Bindings.Sns
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Attributes;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class Statement : IAsyncApiExtensible
+ {
+ ///
+ /// Indicates whether the policy allows or denies access.
+ ///
+ public Effect Effect { get; set; }
+
+ ///
+ /// The AWS account(s) or resource ARN(s) that this statement applies to.
+ ///
+ public Principal Principal { get; set; }
+
+ ///
+ /// The SNS permission being allowed or denied e.g. sns:Publish.
+ ///
+ public StringOrStringList Action { get; set; }
+
+ ///
+ /// The resource(s) that this policy applies to.
+ ///
+ public StringOrStringList? Resource { get; set; }
+
+ ///
+ /// Specific circumstances under which the policy grants permission.
+ ///
+ public Condition Condition { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("effect", this.Effect.GetDisplayName());
+ writer.WriteRequiredObject("principal", this.Principal, (w, t) => t.Serialize(w));
+ writer.WriteRequiredObject("action", this.Action, (w, t) => t.Value.Write(w));
+ writer.WriteOptionalObject("resource", this.Resource, (w, t) => t?.Value.Write(w));
+ writer.WriteOptionalObject("condition", this.Condition, (w, t) => t.Serialize(w));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+
+ public enum Effect
+ {
+ [Display("Allow")]
+ Allow,
+ [Display("Deny")]
+ Deny,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/Condition.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/Condition.cs
new file mode 100644
index 00000000..93bdf733
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/Condition.cs
@@ -0,0 +1,67 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using LEGO.AsyncAPI.Models.Interfaces;
+using LEGO.AsyncAPI.Readers.ParseNodes;
+using LEGO.AsyncAPI.Writers;
+
+public class Condition : IAsyncApiElement
+{
+ public Dictionary> Value { get; private set; }
+
+ public Condition(Dictionary> value)
+ {
+ this.Value = value;
+ }
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ foreach (var conditionValue in this.Value)
+ {
+ writer.WriteRequiredMap(conditionValue.Key, conditionValue.Value, (w, t) => t.Value.Write(w));
+ }
+
+ writer.WriteEndObject();
+ }
+
+ public static Condition Parse(ParseNode node)
+ {
+ switch (node)
+ {
+ case MapNode mapNode:
+ {
+ var conditionValues = new Dictionary>();
+ foreach (var conditionNode in mapNode)
+ {
+ switch (conditionNode.Value)
+ {
+ case MapNode conditionValueNode:
+ conditionValues.Add(conditionNode.Name, new Dictionary(conditionValueNode.Select(x =>
+ new KeyValuePair(x.Name, StringOrStringList.Parse(x.Value)))
+ .ToDictionary(x => x.Key, x => x.Value)));
+ break;
+ default:
+ throw new ArgumentException($"An error occured while parsing a {nameof(Condition)} node. " +
+ $"AWS condition values should be one or more key value pairs.");
+ }
+ }
+
+ return new Condition(conditionValues);
+ }
+
+ default:
+ throw new ArgumentException($"An error occured while parsing a {nameof(Condition)} node. " +
+ $"Node should contain a collection of AWS condition types.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/Identifier.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/Identifier.cs
new file mode 100644
index 00000000..6e7aff23
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/Identifier.cs
@@ -0,0 +1,32 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class Identifier : IAsyncApiExtensible
+ {
+ public string Arn { get; set; }
+
+ public string Name { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalProperty("arn", this.Arn);
+ writer.WriteOptionalProperty("name", this.Name);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/Policy.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/Policy.cs
new file mode 100644
index 00000000..2fd9f68b
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/Policy.cs
@@ -0,0 +1,32 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class Policy : IAsyncApiExtensible
+ {
+ ///
+ /// An array of statement objects, each of which controls a permission for this topic.
+ ///
+ public List Statements { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteOptionalCollection("statements", this.Statements, (w, t) => t.Serialize(w));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/Principal.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/Principal.cs
new file mode 100644
index 00000000..2821f952
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/Principal.cs
@@ -0,0 +1,65 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using LEGO.AsyncAPI.Models.Interfaces;
+using LEGO.AsyncAPI.Readers.ParseNodes;
+using LEGO.AsyncAPI.Writers;
+
+public abstract class Principal : IAsyncApiElement
+{
+ public abstract void Serialize(IAsyncApiWriter writer);
+
+ public static Principal Parse(ParseNode node)
+ {
+ switch (node)
+ {
+ case ValueNode:
+ var nodeValue = node.GetScalarValue();
+ if (!IsStarString(nodeValue))
+ {
+ throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
+ $"Principal value without a property name can only be a string value of '*'.");
+ }
+
+ return new PrincipalStar();
+
+ case MapNode mapNode:
+ {
+ var propertyNode = mapNode.First();
+ if (!IsValidPrincipalProperty(propertyNode.Name))
+ {
+ throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
+ $"Node should contain a valid AWS principal property name.");
+ }
+
+ var principalValue = new KeyValuePair(
+ propertyNode.Name,
+ StringOrStringList.Parse(propertyNode.Value));
+
+ return new PrincipalObject(principalValue);
+ }
+
+ default:
+ throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
+ $"Node should contain a string value of '*' or a valid AWS principal property.");
+ }
+ }
+
+ private static bool IsStarString(JsonNode value)
+ {
+ var element = JsonDocument.Parse(value.ToJsonString()).RootElement;
+
+ return element.ValueKind == JsonValueKind.String && element.ValueEquals("*");
+ }
+
+ private static bool IsValidPrincipalProperty(string property)
+ {
+ return new[] { "AWS", "Service" }.Contains(property);
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/PrincipalObject.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/PrincipalObject.cs
new file mode 100644
index 00000000..61e6e546
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/PrincipalObject.cs
@@ -0,0 +1,27 @@
+namespace LEGO.AsyncAPI.Bindings.Sqs;
+
+using System;
+using System.Collections.Generic;
+using LEGO.AsyncAPI.Writers;
+
+public class PrincipalObject : Principal
+{
+ public KeyValuePair Value { get; private set; }
+
+ public PrincipalObject(KeyValuePair value)
+ {
+ this.Value = value;
+ }
+
+ public override void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredObject(this.Value.Key, this.Value.Value, (w, t) => t.Value.Write(w));
+ writer.WriteEndObject();
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/PrincipalStar.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/PrincipalStar.cs
new file mode 100644
index 00000000..1705b966
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/PrincipalStar.cs
@@ -0,0 +1,24 @@
+namespace LEGO.AsyncAPI.Bindings.Sqs;
+
+using System;
+using LEGO.AsyncAPI.Writers;
+
+public class PrincipalStar : Principal
+{
+ public string Value { get; private set; }
+
+ public PrincipalStar()
+ {
+ this.Value = "*";
+ }
+
+ public override void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteValue(this.Value);
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/Queue.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/Queue.cs
new file mode 100644
index 00000000..33166af5
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/Queue.cs
@@ -0,0 +1,105 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+ using LEGO.AsyncAPI.Attributes;
+
+ public class Queue : IAsyncApiExtensible
+ {
+ ///
+ /// The name of the queue. When an SNS Operation Binding Object references an SQS queue by name, the identifier should be the one in this field.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Is this a FIFO queue?
+ ///
+ public bool FifoQueue { get; set; }
+
+ ///
+ /// Specifies whether message deduplication occurs at the message group or queue level. Valid values are messageGroup and queue (default).
+ ///
+ public DeduplicationScope? DeduplicationScope { get; set; }
+
+ ///
+ /// Specifies whether the FIFO queue throughput quota applies to the entire queue or per message group. Valid values are perQueue (default) and perMessageGroupId.
+ ///
+ public FifoThroughputLimit? FifoThroughputLimit { get; set; }
+
+ ///
+ /// The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue.
+ ///
+ public int? DeliveryDelay { get; set; }
+
+ ///
+ /// The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again.
+ ///
+ public int? VisibilityTimeout { get; set; }
+
+ ///
+ /// Determines if the queue uses short polling or long polling. Set to zero the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning.
+ ///
+ public int? ReceiveMessageWaitTime { get; set; }
+
+ ///
+ /// How long to retain a message on the queue in seconds, unless deleted.
+ ///
+ public int? MessageRetentionPeriod { get; set; }
+
+ ///
+ /// Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.
+ ///
+ public RedrivePolicy RedrivePolicy { get; set; }
+
+ ///
+ /// The security policy for the SQS Queue
+ ///
+ public Policy Policy { get; set; }
+
+ ///
+ /// Key-value pairs that represent AWS tags on the topic.
+ ///
+ public Dictionary Tags { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("name", this.Name);
+ writer.WriteOptionalProperty("fifoQueue", this.FifoQueue);
+ writer.WriteOptionalProperty("deduplicationScope", this.DeduplicationScope?.GetDisplayName());
+ writer.WriteOptionalProperty("fifoThroughputLimit", this.FifoThroughputLimit?.GetDisplayName());
+ writer.WriteOptionalProperty("deliveryDelay", this.DeliveryDelay);
+ writer.WriteOptionalProperty("visibilityTimeout", this.VisibilityTimeout);
+ writer.WriteOptionalProperty("receiveMessageWaitTime", this.ReceiveMessageWaitTime);
+ writer.WriteOptionalProperty("messageRetentionPeriod", this.MessageRetentionPeriod);
+ writer.WriteOptionalObject("redrivePolicy", this.RedrivePolicy, (w, p) => p.Serialize(w));
+ writer.WriteOptionalObject("policy", this.Policy, (w, p) => p.Serialize(w));
+ writer.WriteOptionalMap("tags", this.Tags, (w, t) => w.WriteValue(t));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+
+ public enum DeduplicationScope
+ {
+ [Display("queue")] Queue,
+ [Display("messageGroup")] MessageGroup,
+ }
+
+ public enum FifoThroughputLimit
+ {
+ [Display("perQueue")] PerQueue,
+ [Display("perMessageGroupId")] PerMessageGroupId,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/RedrivePolicy.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/RedrivePolicy.cs
new file mode 100644
index 00000000..923d668c
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/RedrivePolicy.cs
@@ -0,0 +1,38 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs
+{
+ using System;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+ using System.Collections.Generic;
+
+ public class RedrivePolicy : IAsyncApiExtensible
+ {
+ ///
+ /// Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.
+ ///
+ public Identifier DeadLetterQueue { get; set; }
+
+ ///
+ /// The number of times a message is delivered to the source queue before being moved to the dead-letter queue.
+ ///
+ public int? MaxReceiveCount { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredObject("deadLetterQueue", this.DeadLetterQueue, (w, q) => q.Serialize(w));
+ writer.WriteOptionalProperty("maxReceiveCount", this.MaxReceiveCount);
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/SqsChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/SqsChannelBinding.cs
new file mode 100644
index 00000000..bd806071
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/SqsChannelBinding.cs
@@ -0,0 +1,87 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs
+{
+ using System;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ ///
+ /// This object contains information about the channel representation in SQS.
+ ///
+ public class SqsChannelBinding : ChannelBinding
+ {
+ ///
+ /// A definition of the queue that will be used as the channel.
+ ///
+ public Queue Queue { get; set; }
+
+ ///
+ /// A definition of the queue that will be used for un-processable messages.
+ ///
+ public Queue DeadLetterQueue { get; set; }
+
+ public override string BindingKey => "sqs";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "queue", (a, n) => { a.Queue = n.ParseMapWithExtensions(this.queueFixedFields); } },
+ { "deadLetterQueue", (a, n) => { a.DeadLetterQueue = n.ParseMapWithExtensions(this.queueFixedFields); } },
+ };
+
+ private FixedFieldMap queueFixedFields => new()
+ {
+ { "name", (a, n) => { a.Name = n.GetScalarValue(); } },
+ { "fifoQueue", (a, n) => { a.FifoQueue = n.GetBooleanValue(); } },
+ { "deduplicationScope", (a, n) => { a.DeduplicationScope = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "fifoThroughputLimit", (a, n) => { a.FifoThroughputLimit = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "deliveryDelay", (a, n) => { a.DeliveryDelay = n.GetIntegerValue(); } },
+ { "visibilityTimeout", (a, n) => { a.VisibilityTimeout = n.GetIntegerValue(); } },
+ { "receiveMessageWaitTime", (a, n) => { a.ReceiveMessageWaitTime = n.GetIntegerValue(); } },
+ { "messageRetentionPeriod", (a, n) => { a.MessageRetentionPeriod = n.GetIntegerValue(); } },
+ { "redrivePolicy", (a, n) => { a.RedrivePolicy = n.ParseMapWithExtensions(this.redrivePolicyFixedFields); } },
+ { "policy", (a, n) => { a.Policy = n.ParseMapWithExtensions(this.policyFixedFields); } },
+ { "tags", (a, n) => { a.Tags = n.CreateSimpleMap(s => s.GetScalarValue()); } },
+ };
+
+ private FixedFieldMap redrivePolicyFixedFields => new()
+ {
+ { "deadLetterQueue", (a, n) => { a.DeadLetterQueue = n.ParseMapWithExtensions(identifierFixFields); } },
+ { "maxReceiveCount", (a, n) => { a.MaxReceiveCount = n.GetIntegerValue(); } },
+ };
+
+ private static FixedFieldMap identifierFixFields => new()
+ {
+ { "arn", (a, n) => { a.Arn = n.GetScalarValue(); } },
+ { "name", (a, n) => { a.Name = n.GetScalarValue(); } },
+ };
+
+ private FixedFieldMap policyFixedFields = new()
+ {
+ { "statements", (a, n) => { a.Statements = n.CreateList(s => s.ParseMapWithExtensions(statementFixedFields)); } },
+ };
+
+ private static FixedFieldMap statementFixedFields = new()
+ {
+ { "effect", (a, n) => { a.Effect = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "principal", (a, n) => { a.Principal = Principal.Parse(n); } },
+ { "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } },
+ { "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } },
+ { "condition", (a, n) => { a.Condition = Condition.Parse(n); } },
+ };
+
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredObject("queue", this.Queue, (w, q) => q.Serialize(w));
+ writer.WriteOptionalObject("deadLetterQueue", this.DeadLetterQueue, (w, q) => q.Serialize(w));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/SqsOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/SqsOperationBinding.cs
new file mode 100644
index 00000000..0beb89b8
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/SqsOperationBinding.cs
@@ -0,0 +1,78 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+ using LEGO.AsyncAPI.Writers;
+
+ public class SqsOperationBinding : OperationBinding
+ {
+ ///
+ /// Queue objects that are either the endpoint for an SNS Operation Binding Object, or the deadLetterQueue of the SQS Operation Binding Object
+ ///
+ public List Queues { get; set; }
+
+ public override string BindingKey => "sqs";
+
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "queues", (a, n) => { a.Queues = n.CreateList(s => s.ParseMapWithExtensions(this.queueFixedFields)); } },
+ };
+
+ private FixedFieldMap queueFixedFields => new()
+ {
+ { "name", (a, n) => { a.Name = n.GetScalarValue(); } },
+ { "fifoQueue", (a, n) => { a.FifoQueue = n.GetBooleanValue(); } },
+ { "deduplicationScope", (a, n) => { a.DeduplicationScope = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "fifoThroughputLimit", (a, n) => { a.FifoThroughputLimit = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "deliveryDelay", (a, n) => { a.DeliveryDelay = n.GetIntegerValue(); } },
+ { "visibilityTimeout", (a, n) => { a.VisibilityTimeout = n.GetIntegerValue(); } },
+ { "receiveMessageWaitTime", (a, n) => { a.ReceiveMessageWaitTime = n.GetIntegerValue(); } },
+ { "messageRetentionPeriod", (a, n) => { a.MessageRetentionPeriod = n.GetIntegerValue(); } },
+ { "redrivePolicy", (a, n) => { a.RedrivePolicy = n.ParseMapWithExtensions(this.redrivePolicyFixedFields); } },
+ { "policy", (a, n) => { a.Policy = n.ParseMapWithExtensions(this.policyFixedFields); } },
+ { "tags", (a, n) => { a.Tags = n.CreateSimpleMap(s => s.GetScalarValue()); } },
+ };
+
+ private FixedFieldMap redrivePolicyFixedFields => new()
+ {
+ { "deadLetterQueue", (a, n) => { a.DeadLetterQueue = n.ParseMapWithExtensions(identifierFixFields); } },
+ { "maxReceiveCount", (a, n) => { a.MaxReceiveCount = n.GetIntegerValue(); } },
+ };
+
+ private static FixedFieldMap identifierFixFields => new()
+ {
+ { "arn", (a, n) => { a.Arn = n.GetScalarValue(); } },
+ { "name", (a, n) => { a.Name = n.GetScalarValue(); } },
+ };
+
+ private FixedFieldMap policyFixedFields = new()
+ {
+ { "statements", (a, n) => { a.Statements = n.CreateList(s => s.ParseMapWithExtensions(statementFixedFields)); } },
+ };
+
+ private static FixedFieldMap statementFixedFields = new()
+ {
+ { "effect", (a, n) => { a.Effect = n.GetScalarValue().GetEnumFromDisplayName(); } },
+ { "principal", (a, n) => { a.Principal = Principal.Parse(n); } },
+ { "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } },
+ { "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } },
+ { "condition", (a, n) => { a.Condition = Condition.Parse(n); } },
+ };
+
+ public override void SerializeProperties(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredCollection("queues", this.Queues, (w, t) => t.Serialize(w));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/Sqs/Statement.cs b/src/LEGO.AsyncAPI.Bindings/Sqs/Statement.cs
new file mode 100644
index 00000000..4a9c5303
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/Sqs/Statement.cs
@@ -0,0 +1,66 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings.Sqs
+{
+ using System;
+ using System.Collections.Generic;
+ using LEGO.AsyncAPI.Attributes;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Writers;
+
+ public class Statement : IAsyncApiExtensible
+ {
+ ///
+ /// Indicates whether the policy allows or denies access.
+ ///
+ public Effect Effect { get; set; }
+
+ ///
+ /// The AWS account(s) or resource ARN(s) that this statement applies to.
+ ///
+ public Principal Principal { get; set; }
+
+ ///
+ /// The SNS permission being allowed or denied e.g. sns:Publish.
+ ///
+ public StringOrStringList Action { get; set; }
+
+ ///
+ /// The resource(s) that this policy applies to.
+ ///
+ public StringOrStringList? Resource { get; set; }
+
+ ///
+ /// Specific circumstances under which the policy grants permission.
+ ///
+ public Condition Condition { get; set; }
+
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
+ public void Serialize(IAsyncApiWriter writer)
+ {
+ if (writer is null)
+ {
+ throw new ArgumentNullException(nameof(writer));
+ }
+
+ writer.WriteStartObject();
+ writer.WriteRequiredProperty("effect", this.Effect.GetDisplayName());
+ writer.WriteRequiredObject("principal", this.Principal, (w, t) => t.Serialize(w));
+ writer.WriteRequiredObject("action", this.Action, (w, t) => t.Value.Write(w));
+ writer.WriteOptionalObject("resource", this.Resource, (w, t) => t?.Value.Write(w));
+ writer.WriteOptionalObject("condition", this.Condition, (w, t) => t.Serialize(w));
+ writer.WriteExtensions(this.Extensions);
+ writer.WriteEndObject();
+ }
+ }
+
+ public enum Effect
+ {
+ [Display("allow")]
+ Allow,
+ [Display("deny")]
+ Deny,
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Bindings/StringOrStringList.cs b/src/LEGO.AsyncAPI.Bindings/StringOrStringList.cs
new file mode 100644
index 00000000..b9946f08
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/StringOrStringList.cs
@@ -0,0 +1,61 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Bindings
+{
+ using System;
+ using System.Linq;
+ using System.Text.Json;
+ using System.Text.Json.Nodes;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public class StringOrStringList : IAsyncApiElement
+ {
+ public StringOrStringList(AsyncApiAny value)
+ {
+ this.Value = value.GetNode() switch
+ {
+ JsonArray array => IsValidStringList(array) ? new AsyncApiAny(array) : throw new ArgumentException($"{nameof(StringOrStringList)} value should only contain string items."),
+ JsonValue jValue => IsString(jValue) ? new AsyncApiAny(jValue) : throw new ArgumentException($"{nameof(StringOrStringList)} should be a string value or a string list."),
+ _ => throw new ArgumentException($"{nameof(StringOrStringList)} should be a string value or a string list."),
+ };
+ }
+
+ public AsyncApiAny Value { get; }
+
+ public static StringOrStringList Parse(ParseNode node)
+ {
+ switch (node)
+ {
+ case ValueNode:
+ return new StringOrStringList(new AsyncApiAny(node.GetScalarValue()));
+ case ListNode listNode:
+ {
+ var jsonArray = new JsonArray();
+ foreach (var item in listNode)
+ {
+ jsonArray.Add(item.GetScalarValue());
+ }
+
+ return new StringOrStringList(new AsyncApiAny(jsonArray));
+ }
+
+ default:
+ throw new ArgumentException($"An error occured while parsing a {nameof(StringOrStringList)} node. " +
+ $"Node should contain a string value or a list of strings.");
+ }
+ }
+
+ private static bool IsString(JsonNode value)
+ {
+ var element = JsonDocument.Parse(value.ToJsonString()).RootElement;
+ return element.ValueKind == JsonValueKind.String;
+ }
+
+ private static bool IsValidStringList(JsonArray array)
+ {
+ return array.All(x => IsString(x));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI/Models/Bindings/WebSockets/WebSocketsChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/WebSockets/WebSocketsChannelBinding.cs
similarity index 57%
rename from src/LEGO.AsyncAPI/Models/Bindings/WebSockets/WebSocketsChannelBinding.cs
rename to src/LEGO.AsyncAPI.Bindings/WebSockets/WebSocketsChannelBinding.cs
index 7aa2e793..c87393bb 100644
--- a/src/LEGO.AsyncAPI/Models/Bindings/WebSockets/WebSocketsChannelBinding.cs
+++ b/src/LEGO.AsyncAPI.Bindings/WebSockets/WebSocketsChannelBinding.cs
@@ -1,13 +1,14 @@
// Copyright (c) The LEGO Group. All rights reserved.
-namespace LEGO.AsyncAPI.Models.Bindings.WebSockets
+namespace LEGO.AsyncAPI.Bindings.WebSockets
{
using System;
- using System.Collections.Generic;
- using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Models;
+ using LEGO.AsyncAPI.Readers;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;
- public class WebSocketsChannelBinding : IChannelBinding
+ public class WebSocketsChannelBinding : ChannelBinding
{
///
/// The HTTP method t use when establishing the connection. Its value MUST be either 'GET' or 'POST'.
@@ -24,18 +25,17 @@ public class WebSocketsChannelBinding : IChannelBinding
///
public AsyncApiSchema Headers { get; set; }
- public string BindingVersion { get; set; }
+ public override string BindingKey => "websockets";
- public bool UnresolvedReference { get; set; }
-
- public AsyncApiReference Reference { get; set; }
-
- public IDictionary Extensions { get; set; } =
- new Dictionary();
-
- public BindingType Type => BindingType.Websockets;
+ protected override FixedFieldMap FixedFieldMap => new()
+ {
+ { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
+ { "method", (a, n) => { a.Method = n.GetScalarValue(); } },
+ { "query", (a, n) => { a.Query = JsonSchemaDeserializer.LoadSchema(n); } },
+ { "headers", (a, n) => { a.Headers = JsonSchemaDeserializer.LoadSchema(n); } },
+ };
- public void SerializeV2WithoutReference(IAsyncApiWriter writer)
+ public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
@@ -48,24 +48,8 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer)
writer.WriteOptionalObject(AsyncApiConstants.Query, this.Query, (w, h) => h.SerializeV2(w));
writer.WriteOptionalObject(AsyncApiConstants.Headers, this.Headers, (w, h) => h.SerializeV2(w));
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
-
+ writer.WriteExtensions(this.Extensions);
writer.WriteEndObject();
}
-
- public void SerializeV2(IAsyncApiWriter writer)
- {
- if (writer is null)
- {
- throw new ArgumentNullException(nameof(writer));
- }
-
- if (this.Reference != null && !writer.GetSettings().ShouldInlineReference(this.Reference))
- {
- this.Reference.SerializeV2(writer);
- return;
- }
-
- this.SerializeV2WithoutReference(writer);
- }
}
-}
\ No newline at end of file
+}
diff --git a/src/LEGO.AsyncAPI.Bindings/stylecop.json b/src/LEGO.AsyncAPI.Bindings/stylecop.json
new file mode 100644
index 00000000..0a8f4661
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Bindings/stylecop.json
@@ -0,0 +1,15 @@
+{
+ // ACTION REQUIRED: This file was automatically added to your project, but it
+ // will not take effect until additional steps are taken to enable it. See the
+ // following page for additional information:
+ //
+ // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md
+
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "The LEGO Group",
+ "xmlHeader": false
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Readers/AsyncApiYamlDocumentReader.cs b/src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs
similarity index 63%
rename from src/LEGO.AsyncAPI.Readers/AsyncApiYamlDocumentReader.cs
rename to src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs
index 655f2847..3a973654 100644
--- a/src/LEGO.AsyncAPI.Readers/AsyncApiYamlDocumentReader.cs
+++ b/src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs
@@ -4,6 +4,8 @@ namespace LEGO.AsyncAPI.Readers
{
using System.Collections.Generic;
using System.Linq;
+ using System.Text.Json.Nodes;
+ using System.Threading;
using System.Threading.Tasks;
using LEGO.AsyncAPI.Exceptions;
using LEGO.AsyncAPI.Extensions;
@@ -11,20 +13,19 @@ namespace LEGO.AsyncAPI.Readers
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Readers.Interface;
using LEGO.AsyncAPI.Validations;
- using YamlDotNet.RepresentationModel;
///
- /// Service class for converting contents of TextReader into AsyncApiDocument instances
+ /// Service class for converting contents of TextReader into AsyncApiDocument instances.
///
- internal class AsyncApiYamlDocumentReader : IAsyncApiReader
+ internal class AsyncApiJsonDocumentReader : IAsyncApiReader
{
private readonly AsyncApiReaderSettings settings;
///
- /// Create stream reader with custom settings if desired.
+ /// Initializes a new instance of the class.
///
- ///
- public AsyncApiYamlDocumentReader(AsyncApiReaderSettings settings = null)
+ /// The settings used to read json.
+ public AsyncApiJsonDocumentReader(AsyncApiReaderSettings settings = null)
{
this.settings = settings ?? new AsyncApiReaderSettings();
}
@@ -33,14 +34,18 @@ public AsyncApiYamlDocumentReader(AsyncApiReaderSettings settings = null)
/// Reads the stream input and parses it into an AsyncApi document.
///
/// TextReader containing AsyncApi description to parse.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created AsyncApiDocument
- public AsyncApiDocument Read(YamlDocument input, out AsyncApiDiagnostic diagnostic)
+ /// Returns diagnostic object containing errors detected during parsing.
+ /// Instance of newly created AsyncApiDocument.
+ public AsyncApiDocument Read(JsonNode input, out AsyncApiDiagnostic diagnostic)
{
diagnostic = new AsyncApiDiagnostic();
- var context = new ParsingContext(diagnostic)
+ var context = new ParsingContext(diagnostic, this.settings)
{
ExtensionParsers = this.settings.ExtensionParsers,
+ ServerBindingParsers = this.settings.Bindings.OfType>().ToDictionary(b => b.BindingKey, b => b),
+ ChannelBindingParsers = this.settings.Bindings.OfType>().ToDictionary(b => b.BindingKey, b => b),
+ OperationBindingParsers = this.settings.Bindings.OfType>().ToDictionary(b => b.BindingKey, b => b),
+ MessageBindingParsers = this.settings.Bindings.OfType>().ToDictionary(b => b.BindingKey, b => b),
};
AsyncApiDocument document = null;
@@ -58,12 +63,12 @@ public AsyncApiDocument Read(YamlDocument input, out AsyncApiDiagnostic diagnost
if (this.settings.RuleSet != null && this.settings.RuleSet.Rules.Count > 0)
{
var asyncApiErrors = document.Validate(this.settings.RuleSet);
- foreach (var item in asyncApiErrors.Where(e => e is AsyncApiValidatorError))
+ foreach (var item in asyncApiErrors.OfType())
{
diagnostic.Errors.Add(item);
}
- foreach (var item in asyncApiErrors.Where(e => e is AsyncApiValidatorWarning))
+ foreach (var item in asyncApiErrors.OfType())
{
diagnostic.Warnings.Add(item);
}
@@ -72,10 +77,10 @@ public AsyncApiDocument Read(YamlDocument input, out AsyncApiDiagnostic diagnost
return document;
}
- public async Task ReadAsync(YamlDocument input)
+ public async Task ReadAsync(JsonNode input, CancellationToken cancellationToken = default)
{
var diagnostic = new AsyncApiDiagnostic();
- var context = new ParsingContext(diagnostic)
+ var context = new ParsingContext(diagnostic, this.settings)
{
ExtensionParsers = this.settings.ExtensionParsers,
};
@@ -95,11 +100,16 @@ public async Task ReadAsync(YamlDocument input)
// Validate the document
if (this.settings.RuleSet != null && this.settings.RuleSet.Rules.Count > 0)
{
- var errors = document.Validate(this.settings.RuleSet);
- foreach (var item in errors)
+ var asyncApiErrors = document.Validate(this.settings.RuleSet);
+ foreach (var item in asyncApiErrors.OfType())
{
diagnostic.Errors.Add(item);
}
+
+ foreach (var item in asyncApiErrors.OfType())
+ {
+ diagnostic.Warnings.Add(item);
+ }
}
return new ReadResult
@@ -109,41 +119,24 @@ public async Task ReadAsync(YamlDocument input)
};
}
- private void ResolveReferences(AsyncApiDiagnostic diagnostic, AsyncApiDocument document)
- {
- var errors = new List();
-
- // Resolve References if requested
- switch (this.settings.ReferenceResolution)
- {
- case ReferenceResolutionSetting.ResolveReferences:
- errors.AddRange(document.ResolveReferences());
- break;
- case ReferenceResolutionSetting.DoNotResolveReferences:
- break;
- }
-
- foreach (var item in errors)
- {
- diagnostic.Errors.Add(item);
- }
- }
-
-
///
/// Reads the stream input and parses the fragment of an AsyncApi description into an AsyncApi Element.
///
/// TextReader containing AsyncApi description to parse.
/// Version of the AsyncApi specification that the fragment conforms to.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created AsyncApiDocument
- public T ReadFragment(YamlDocument input, AsyncApiVersion version, out AsyncApiDiagnostic diagnostic)
+ /// Returns diagnostic object containing errors detected during parsing.
+ /// Instance of newly created AsyncApiDocument.
+ public T ReadFragment(JsonNode input, AsyncApiVersion version, out AsyncApiDiagnostic diagnostic)
where T : IAsyncApiElement
{
diagnostic = new AsyncApiDiagnostic();
- var context = new ParsingContext(diagnostic)
+ var context = new ParsingContext(diagnostic, this.settings)
{
ExtensionParsers = this.settings.ExtensionParsers,
+ ServerBindingParsers = this.settings.Bindings.OfType>().ToDictionary(b => b.BindingKey, b => b),
+ ChannelBindingParsers = this.settings.Bindings.OfType>().ToDictionary(b => b.BindingKey, b => b),
+ OperationBindingParsers = this.settings.Bindings.OfType>().ToDictionary(b => b.BindingKey, b => b),
+ MessageBindingParsers = this.settings.Bindings.OfType>().ToDictionary(b => b.BindingKey, b => b),
};
IAsyncApiElement element = null;
@@ -169,5 +162,26 @@ public T ReadFragment(YamlDocument input, AsyncApiVersion version, out AsyncA
return (T)element;
}
+
+ private void ResolveReferences(AsyncApiDiagnostic diagnostic, AsyncApiDocument document)
+ {
+ var errors = new List();
+
+ // Resolve References if requested
+ switch (this.settings.ReferenceResolution)
+ {
+ case ReferenceResolutionSetting.ResolveReferences:
+ errors.AddRange(document.ResolveReferences());
+ break;
+
+ case ReferenceResolutionSetting.DoNotResolveReferences:
+ break;
+ }
+
+ foreach (var item in errors)
+ {
+ diagnostic.Errors.Add(item);
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs b/src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs
index 21fe1c73..6ca2e129 100644
--- a/src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs
+++ b/src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs
@@ -5,7 +5,9 @@ namespace LEGO.AsyncAPI.Readers
using System;
using System.Collections.Generic;
using System.IO;
+ using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers.Interface;
using LEGO.AsyncAPI.Validations;
public enum ReferenceResolutionSetting
@@ -16,15 +18,15 @@ public enum ReferenceResolutionSetting
DoNotResolveReferences,
///
- /// ResolveAllReferences, effectively inlining them.
+ /// Resolve internal component references and inline them.
///
ResolveReferences,
}
///
- /// Configuration settings to control how AsyncApi documents are parsed
+ /// Configuration settings to control how AsyncApi documents are parsed.
///
- public class AsyncApiReaderSettings
+ public class AsyncApiReaderSettings : AsyncApiSettings
{
///
/// Indicates how references in the source document should be handled.
@@ -35,10 +37,15 @@ public class AsyncApiReaderSettings
///
/// Dictionary of parsers for converting extensions into strongly typed classes.
///
- public Dictionary>
+ public Dictionary>
ExtensionParsers
{ get; set; } =
- new Dictionary>();
+ new Dictionary>();
+
+ public IEnumerable>
+ Bindings
+ { get; set; } =
+ new List>();
///
/// Rules to use for validating AsyncApi specification. If none are provided a default set of rules are applied.
diff --git a/src/LEGO.AsyncAPI.Readers/AsyncApiStreamReader.cs b/src/LEGO.AsyncAPI.Readers/AsyncApiStreamReader.cs
index da04716d..2cbf47ac 100644
--- a/src/LEGO.AsyncAPI.Readers/AsyncApiStreamReader.cs
+++ b/src/LEGO.AsyncAPI.Readers/AsyncApiStreamReader.cs
@@ -3,13 +3,14 @@
namespace LEGO.AsyncAPI.Readers
{
using System.IO;
+ using System.Threading;
using System.Threading.Tasks;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Readers.Interface;
///
- /// Service class for converting streams into AsyncApiDocument instances
+ /// Service class for converting streams into AsyncApiDocument instances.
///
public class AsyncApiStreamReader : IAsyncApiReader
{
@@ -33,7 +34,7 @@ public AsyncApiStreamReader(AsyncApiReaderSettings settings = null)
public AsyncApiDocument Read(Stream input, out AsyncApiDiagnostic diagnostic)
{
var reader = new StreamReader(input);
- var result = new AsyncApiTextReaderReader(this.settings).Read(reader, out diagnostic);
+ var result = new AsyncApiTextReader(this.settings).Read(reader, out diagnostic);
if (!this.settings.LeaveStreamOpen)
{
reader.Dispose();
@@ -46,8 +47,11 @@ public AsyncApiDocument Read(Stream input, out AsyncApiDiagnostic diagnostic)
/// Reads the stream input and parses it into an AsyncApi document.
///
/// Stream containing AsyncApi description to parse.
- /// Instance result containing newly created AsyncApiDocument and diagnostics object from the process
- public async Task ReadAsync(Stream input)
+ /// The cancellation token.
+ ///
+ /// Instance result containing newly created AsyncApiDocument and diagnostics object from the process.
+ ///
+ public async Task ReadAsync(Stream input, CancellationToken cancellationToken)
{
MemoryStream bufferedStream;
if (input is MemoryStream)
@@ -65,7 +69,7 @@ public async Task ReadAsync(Stream input)
var reader = new StreamReader(bufferedStream);
- return await new AsyncApiTextReaderReader(this.settings).ReadAsync(reader);
+ return await new AsyncApiTextReader(this.settings).ReadAsync(reader, cancellationToken);
}
///
@@ -73,14 +77,14 @@ public async Task ReadAsync(Stream input)
///
/// Stream containing AsyncApi description to parse.
/// Version of the AsyncApi specification that the fragment conforms to.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created AsyncApiDocument
+ /// Returns diagnostic object containing errors detected during parsing.
+ /// Instance of newly created AsyncApiDocument.
public T ReadFragment(Stream input, AsyncApiVersion version, out AsyncApiDiagnostic diagnostic)
where T : IAsyncApiReferenceable
{
using (var reader = new StreamReader(input))
{
- return new AsyncApiTextReaderReader(this.settings).ReadFragment(reader, version, out diagnostic);
+ return new AsyncApiTextReader(this.settings).ReadFragment(reader, version, out diagnostic);
}
}
}
diff --git a/src/LEGO.AsyncAPI.Readers/AsyncApiStringReader.cs b/src/LEGO.AsyncAPI.Readers/AsyncApiStringReader.cs
index c6680620..90d3f84b 100644
--- a/src/LEGO.AsyncAPI.Readers/AsyncApiStringReader.cs
+++ b/src/LEGO.AsyncAPI.Readers/AsyncApiStringReader.cs
@@ -8,14 +8,14 @@ namespace LEGO.AsyncAPI.Readers
using LEGO.AsyncAPI.Readers.Interface;
///
- /// Service class for converting strings into AsyncApiDocument instances
+ /// Service class for converting strings into AsyncApiDocument instances.
///
public class AsyncApiStringReader : IAsyncApiReader
{
private readonly AsyncApiReaderSettings settings;
///
- /// Constructor tha allows reader to use non-default settings
+ /// Constructor tha allows reader to use non-default settings.
///
///
public AsyncApiStringReader(AsyncApiReaderSettings settings = null)
@@ -30,7 +30,7 @@ public AsyncApiDocument Read(string input, out AsyncApiDiagnostic diagnostic)
{
using (var reader = new StringReader(input))
{
- return new AsyncApiTextReaderReader(this.settings).Read(reader, out diagnostic);
+ return new AsyncApiTextReader(this.settings).Read(reader, out diagnostic);
}
}
@@ -42,7 +42,7 @@ public T ReadFragment(string input, AsyncApiVersion version, out AsyncApiDiag
{
using (var reader = new StringReader(input))
{
- return new AsyncApiTextReaderReader(this.settings).ReadFragment(reader, version, out diagnostic);
+ return new AsyncApiTextReader(this.settings).ReadFragment(reader, version, out diagnostic);
}
}
}
diff --git a/src/LEGO.AsyncAPI.Readers/AsyncApiTextReader.cs b/src/LEGO.AsyncAPI.Readers/AsyncApiTextReader.cs
index 51817948..eeece6a7 100644
--- a/src/LEGO.AsyncAPI.Readers/AsyncApiTextReader.cs
+++ b/src/LEGO.AsyncAPI.Readers/AsyncApiTextReader.cs
@@ -4,17 +4,20 @@ namespace LEGO.AsyncAPI.Readers
{
using System.IO;
using System.Linq;
+ using System.Runtime.CompilerServices;
+ using System.Text.Json;
+ using System.Text.Json.Nodes;
+ using System.Threading;
using System.Threading.Tasks;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Readers.Interface;
- using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;
///
- /// Service class for converting contents of TextReader into AsyncApiDocument instances
+ /// Service class for converting contents of TextReader into AsyncApiDocument instances.
///
- public class AsyncApiTextReaderReader : IAsyncApiReader
+ public class AsyncApiTextReader : IAsyncApiReader
{
private readonly AsyncApiReaderSettings settings;
@@ -22,7 +25,7 @@ public class AsyncApiTextReaderReader : IAsyncApiReader
///
- public AsyncApiTextReaderReader(AsyncApiReaderSettings settings = null)
+ public AsyncApiTextReader(AsyncApiReaderSettings settings = null)
{
this.settings = settings ?? new AsyncApiReaderSettings();
}
@@ -31,45 +34,48 @@ public AsyncApiTextReaderReader(AsyncApiReaderSettings settings = null)
/// Reads the stream input and parses it into an AsyncApi document.
///
/// TextReader containing AsyncApi description to parse.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created AsyncApiDocument
+ /// Returns diagnostic object containing errors detected during parsing.
+ /// Instance of newly created AsyncApiDocument.
public AsyncApiDocument Read(TextReader input, out AsyncApiDiagnostic diagnostic)
{
- YamlDocument yamlDocument;
+ JsonNode jsonNode;
// Parse the YAML/JSON text in the TextReader into the YamlDocument
try
{
- yamlDocument = LoadYamlDocument(input);
+ jsonNode = LoadYamlDocument(input, this.settings);
}
- catch (YamlException ex)
+ catch (JsonException ex)
{
diagnostic = new AsyncApiDiagnostic();
- diagnostic.Errors.Add(new AsyncApiError($"#line={ex.Start.Line}", ex.Message));
+ diagnostic.Errors.Add(new AsyncApiError($"#line={ex.LineNumber}", ex.Message));
return new AsyncApiDocument();
}
- return new AsyncApiYamlDocumentReader(this.settings).Read(yamlDocument, out diagnostic);
+ return new AsyncApiJsonDocumentReader(this.settings).Read(jsonNode, out diagnostic);
}
///
- /// Reads the content of the TextReader. If there are references to external documents then they will be read asynchronously.
+ /// Reads the content of the TextReader.
///
/// TextReader containing AsyncApi description to parse.
- /// A ReadResult instance that contains the resulting AsyncApiDocument and a diagnostics instance.
- public async Task ReadAsync(TextReader input)
+ /// The cancellation token.
+ ///
+ /// A ReadResult instance that contains the resulting AsyncApiDocument and a diagnostics instance.
+ ///
+ public async Task ReadAsync(TextReader input, CancellationToken cancellationToken)
{
- YamlDocument yamlDocument;
+ JsonNode jsonNode;
// Parse the YAML/JSON text in the TextReader into the YamlDocument
try
{
- yamlDocument = LoadYamlDocument(input);
+ jsonNode = LoadYamlDocument(input, this.settings);
}
- catch (YamlException ex)
+ catch (JsonException ex)
{
var diagnostic = new AsyncApiDiagnostic();
- diagnostic.Errors.Add(new AsyncApiError($"#line={ex.Start.Line}", ex.Message));
+ diagnostic.Errors.Add(new AsyncApiError($"#line={ex.LineNumber}", ex.Message));
return new ReadResult
{
AsyncApiDocument = null,
@@ -77,7 +83,7 @@ public async Task ReadAsync(TextReader input)
};
}
- return await new AsyncApiYamlDocumentReader(this.settings).ReadAsync(yamlDocument);
+ return await new AsyncApiJsonDocumentReader(this.settings).ReadAsync(jsonNode, cancellationToken);
}
///
@@ -85,39 +91,39 @@ public async Task ReadAsync(TextReader input)
///
/// TextReader containing AsyncApi description to parse.
/// Version of the AsyncApi specification that the fragment conforms to.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created AsyncApiDocument
+ /// Returns diagnostic object containing errors detected during parsing.
+ /// Instance of newly created AsyncApiDocument.
public T ReadFragment(TextReader input, AsyncApiVersion version, out AsyncApiDiagnostic diagnostic)
where T : IAsyncApiElement
{
- YamlDocument yamlDocument;
+ JsonNode jsonNode;
// Parse the YAML/JSON
try
{
- yamlDocument = LoadYamlDocument(input);
+ jsonNode = LoadYamlDocument(input, this.settings);
}
- catch (YamlException ex)
+ catch (JsonException ex)
{
diagnostic = new AsyncApiDiagnostic();
- diagnostic.Errors.Add(new AsyncApiError($"#line={ex.Start.Line}", ex.Message));
+ diagnostic.Errors.Add(new AsyncApiError($"#line={ex.LineNumber}", ex.Message));
return default;
}
- return new AsyncApiYamlDocumentReader(this.settings).ReadFragment(yamlDocument, version,
+ return new AsyncApiJsonDocumentReader(this.settings).ReadFragment(jsonNode, version,
out diagnostic);
}
///
- /// Helper method to turn streams into YamlDocument
+ /// Helper method to turn streams into YamlDocument.
///
- /// Stream containing YAML formatted text
- /// Instance of a YamlDocument
- static YamlDocument LoadYamlDocument(TextReader input)
+ /// Stream containing YAML formatted text.
+ /// Instance of a YamlDocument.
+ static JsonNode LoadYamlDocument(TextReader input, AsyncApiReaderSettings settings)
{
var yamlStream = new YamlStream();
yamlStream.Load(input);
- return yamlStream.Documents.First();
+ return yamlStream.Documents.First().ToJsonNode(settings);
}
}
}
diff --git a/src/LEGO.AsyncAPI.Readers/BindingDeserializer.cs b/src/LEGO.AsyncAPI.Readers/BindingDeserializer.cs
new file mode 100644
index 00000000..5744985d
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Readers/BindingDeserializer.cs
@@ -0,0 +1,31 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Readers
+{
+ using LEGO.AsyncAPI.Extensions;
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public class BindingDeserializer
+ {
+ public static T LoadBinding(string nodeName, ParseNode node, FixedFieldMap fieldMap)
+ where T : IBinding, new()
+ {
+ var mapNode = node.CheckMapNode(nodeName);
+ var binding = new T();
+
+ AsyncApiV2Deserializer.ParseMap(mapNode, binding, fieldMap, BindingPatternExtensionFields());
+
+ return binding;
+ }
+
+ private static PatternFieldMap BindingPatternExtensionFields()
+ where T : IBinding, new()
+ {
+ return new()
+ {
+ { s => s.StartsWith("x-"), (a, p, n) => a.AddExtension(p, AsyncApiV2Deserializer.LoadExtension(p, n)) },
+ };
+ }
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiHttpBindingsDeserializer.cs b/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiHttpBindingsDeserializer.cs
deleted file mode 100644
index 72c2579b..00000000
--- a/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiHttpBindingsDeserializer.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) The LEGO Group. All rights reserved.
-
-namespace LEGO.AsyncAPI.Readers
-{
- using LEGO.AsyncAPI.Models.Bindings.Http;
- using LEGO.AsyncAPI.Readers.ParseNodes;
-
- internal static partial class AsyncApiV2Deserializer
- {
- private static FixedFieldMap httpMessageBindingFixedFields = new()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "headers", (a, n) => { a.Headers = LoadSchema(n); } },
- };
-
- private static FixedFieldMap httpOperationBindingFixedFields = new()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "type", (a, n) => { a.Type = n.GetScalarValue(); } },
- { "method", (a, n) => { a.Method = n.GetScalarValue(); } },
- { "query", (a, n) => { a.Query = LoadSchema(n); } },
- };
-
- }
-}
diff --git a/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiKafkaBindingsDeserializer.cs b/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiKafkaBindingsDeserializer.cs
deleted file mode 100644
index 0d80eb8f..00000000
--- a/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiKafkaBindingsDeserializer.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) The LEGO Group. All rights reserved.
-
-namespace LEGO.AsyncAPI.Readers
-{
- using LEGO.AsyncAPI.Models.Bindings.Kafka;
- using LEGO.AsyncAPI.Readers.ParseNodes;
-
- internal static partial class AsyncApiV2Deserializer
- {
- private static FixedFieldMap kafkaServerBindingFixedFields = new()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "schemaRegistryUrl", (a, n) => { a.SchemaRegistryUrl = n.GetScalarValue(); } },
- { "schemaRegistryVendor", (a, n) => { a.SchemaRegistryVendor = n.GetScalarValue(); } },
- };
-
- private static FixedFieldMap kafkaChannelBindingFixedFields = new()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "topic", (a, n) => { a.Topic = n.GetScalarValue(); } },
- { "partitions", (a, n) => { a.Partitions = n.GetIntegerValue(); } },
- { "topicConfiguration", (a, n) => { a.TopicConfiguration = LoadTopicConfiguration(n); } },
- { "replicas", (a, n) => { a.Replicas = n.GetIntegerValue(); } },
- };
-
- private static FixedFieldMap kafkaChannelTopicConfigurationObjectFixedFields = new()
- {
- { "cleanup.policy", (a, n) => { a.CleanupPolicy = n.CreateSimpleList(s => s.GetScalarValue()); } },
- { "retention.ms", (a, n) => { a.RetentionMiliseconds = n.GetIntegerValue(); } },
- { "retention.bytes", (a, n) => { a.RetentionBytes = n.GetIntegerValue(); } },
- { "delete.retention.ms", (a, n) => { a.DeleteRetentionMiliseconds = n.GetIntegerValue(); } },
- { "max.message.bytes", (a, n) => { a.MaxMessageBytes = n.GetIntegerValue(); } },
- };
-
- private static FixedFieldMap kafkaOperationBindingFixedFields = new()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "groupId", (a, n) => { a.GroupId = LoadSchema(n); } },
- { "clientId", (a, n) => { a.ClientId = LoadSchema(n); } },
- };
-
- private static FixedFieldMap kafkaMessageBindingFixedFields = new()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "key", (a, n) => { a.Key = LoadSchema(n); } },
- { "schemaIdLocation", (a, n) => { a.SchemaIdLocation = n.GetScalarValue(); } },
- { "schemaIdPayloadEncoding", (a, n) => { a.SchemaIdPayloadEncoding = n.GetScalarValue(); } },
- { "schemaLookupStrategy", (a, n) => { a.SchemaLookupStrategy = n.GetScalarValue(); } },
- };
-
- private static TopicConfigurationObject LoadTopicConfiguration(ParseNode node)
- {
- var mapNode = node.CheckMapNode("topicConfiguration");
- var retention = new TopicConfigurationObject();
- ParseMap(mapNode, retention, kafkaChannelTopicConfigurationObjectFixedFields, null);
- return retention;
- }
- }
-}
diff --git a/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiPulsarBindingsDeserializer.cs b/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiPulsarBindingsDeserializer.cs
deleted file mode 100644
index 6250a064..00000000
--- a/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiPulsarBindingsDeserializer.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) The LEGO Group. All rights reserved.
-
-namespace LEGO.AsyncAPI.Readers
-{
- using LEGO.AsyncAPI.Models.Bindings.Pulsar;
- using LEGO.AsyncAPI.Readers.ParseNodes;
- using LEGO.AsyncAPI.Writers;
-
- internal static partial class AsyncApiV2Deserializer
- {
- private static FixedFieldMap pulsarServerBindingFixedFields = new ()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "tenant", (a, n) => { a.Tenant = n.GetScalarValue(); } },
- };
-
- private static FixedFieldMap pulsarChannelBindingFixedFields = new ()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "namespace", (a, n) => { a.Namespace = n.GetScalarValue(); } },
- { "persistence", (a, n) => { a.Persistence = n.GetScalarValue().GetEnumFromDisplayName(); } },
- { "compaction", (a, n) => { a.Compaction = n.GetIntegerValue(); } },
- { "retention", (a, n) => { a.Retention = LoadRetention(n); } },
- { "geo-replication", (a, n) => { a.GeoReplication = n.CreateSimpleList(s => s.GetScalarValue()); } },
- { "ttl", (a, n) => { a.TTL = n.GetIntegerValue(); } },
- { "deduplication", (a, n) => { a.Deduplication = n.GetBooleanValue(); } },
- };
-
- private static FixedFieldMap pulsarServerBindingRetentionFixedFields = new ()
- {
- { "time", (a, n) => { a.Time = n.GetIntegerValue(); } },
- { "size", (a, n) => { a.Size = n.GetIntegerValue(); } },
- };
-
- private static RetentionDefinition LoadRetention(ParseNode node)
- {
- var mapNode = node.CheckMapNode("retention");
- var retention = new RetentionDefinition();
- ParseMap(mapNode, retention, pulsarServerBindingRetentionFixedFields, null);
- return retention;
- }
- }
-}
diff --git a/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiWebSocketsBindingsDeserializer.cs b/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiWebSocketsBindingsDeserializer.cs
deleted file mode 100644
index 4d4af870..00000000
--- a/src/LEGO.AsyncAPI.Readers/Bindings/AsyncApiWebSocketsBindingsDeserializer.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) The LEGO Group. All rights reserved.
-
-namespace LEGO.AsyncAPI.Readers
-{
- using LEGO.AsyncAPI.Readers.ParseNodes;
- using Models.Bindings.WebSockets;
-
- internal static partial class AsyncApiV2Deserializer
- {
- private static FixedFieldMap webSocketsChannelBindingFixedFields = new()
- {
- { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
- { "method", (a, n) => { a.Method = n.GetScalarValue(); } },
- { "query", (a, n) => { a.Query = LoadSchema(n); } },
- { "headers", (a, n) => { a.Headers = LoadSchema(n); } },
- };
- }
-}
diff --git a/src/LEGO.AsyncAPI.Readers/Exceptions/AsyncApiReaderException.cs b/src/LEGO.AsyncAPI.Readers/Exceptions/AsyncApiReaderException.cs
index c58ccf1c..61ae4124 100644
--- a/src/LEGO.AsyncAPI.Readers/Exceptions/AsyncApiReaderException.cs
+++ b/src/LEGO.AsyncAPI.Readers/Exceptions/AsyncApiReaderException.cs
@@ -4,31 +4,28 @@ namespace LEGO.AsyncAPI.Readers.Exceptions
{
using System;
using LEGO.AsyncAPI.Exceptions;
- using YamlDotNet.RepresentationModel;
[Serializable]
public class AsyncApiReaderException : AsyncApiException
{
- public AsyncApiReaderException() { }
+ public AsyncApiReaderException()
+ {
+ }
public AsyncApiReaderException(string message)
- : base(message) { }
-
- public AsyncApiReaderException(string message, ParsingContext context)
: base(message)
{
- this.Pointer = context.GetLocation();
}
- public AsyncApiReaderException(string message, YamlNode node)
+ public AsyncApiReaderException(string message, ParsingContext context)
: base(message)
{
- // This only includes line because using a char range causes tests to break due to CR/LF & LF differences
- // See https://tools.ietf.org/html/rfc5147 for syntax
- this.Pointer = $"#line={node.Start.Line}";
+ this.Pointer = context.GetLocation();
}
public AsyncApiReaderException(string message, Exception innerException)
- : base(message, innerException) { }
+ : base(message, innerException)
+ {
+ }
}
}
diff --git a/src/LEGO.AsyncAPI.Readers/Exceptions/AsyncApiUnsupportedSpecVersionException.cs b/src/LEGO.AsyncAPI.Readers/Exceptions/AsyncApiUnsupportedSpecVersionException.cs
index ac183421..d68da4bf 100644
--- a/src/LEGO.AsyncAPI.Readers/Exceptions/AsyncApiUnsupportedSpecVersionException.cs
+++ b/src/LEGO.AsyncAPI.Readers/Exceptions/AsyncApiUnsupportedSpecVersionException.cs
@@ -11,12 +11,13 @@ namespace LEGO.AsyncAPI.Readers.Exceptions
[Serializable]
public class AsyncApiUnsupportedSpecVersionException : Exception
{
- const string MessagePattern = "AsyncApi specification version '{0}' is not supported.";
+ private const string MessagePattern = "AsyncApi specification version '{0}' is not supported.";
///
- /// Initializes the class with a specification version.
+ /// Initializes a new instance of the class.
///
/// Version that caused this exception to be thrown.
+ /// The settings used for reading and writing.
public AsyncApiUnsupportedSpecVersionException(string specificationVersion)
: base(string.Format(CultureInfo.InvariantCulture, MessagePattern, specificationVersion))
{
@@ -24,10 +25,11 @@ public AsyncApiUnsupportedSpecVersionException(string specificationVersion)
}
///
- /// Initializes the class with a specification version and
+ /// Initializes a new instance of the class.
/// inner exception.
///
/// Version that caused this exception to be thrown.
+ /// The setting used for reading and writing
/// Inner exception that caused this exception to be thrown.
public AsyncApiUnsupportedSpecVersionException(string specificationVersion, Exception innerException)
: base(string.Format(CultureInfo.InvariantCulture, MessagePattern, specificationVersion), innerException)
diff --git a/src/LEGO.AsyncAPI.Readers/Interface/IAsyncApiReader.cs b/src/LEGO.AsyncAPI.Readers/Interface/IAsyncApiReader.cs
index 6938ea88..ef2fb45f 100644
--- a/src/LEGO.AsyncAPI.Readers/Interface/IAsyncApiReader.cs
+++ b/src/LEGO.AsyncAPI.Readers/Interface/IAsyncApiReader.cs
@@ -4,7 +4,8 @@ namespace LEGO.AsyncAPI.Readers.Interface
{
using LEGO.AsyncAPI.Models;
- public interface IAsyncApiReader where TDiagnostic : IDiagnostic
+ public interface IAsyncApiReader
+ where TDiagnostic : IDiagnostic
{
AsyncApiDocument Read(TInput input, out TDiagnostic diagnostic);
}
diff --git a/src/LEGO.AsyncAPI.Readers/Interface/IAsyncApiVersionService.cs b/src/LEGO.AsyncAPI.Readers/Interface/IAsyncApiVersionService.cs
index 61922eef..c2345ac1 100644
--- a/src/LEGO.AsyncAPI.Readers/Interface/IAsyncApiVersionService.cs
+++ b/src/LEGO.AsyncAPI.Readers/Interface/IAsyncApiVersionService.cs
@@ -10,7 +10,8 @@ internal interface IAsyncApiVersionService
{
AsyncApiReference ConvertToAsyncApiReference(string reference, ReferenceType? type);
- T LoadElement(ParseNode node) where T : IAsyncApiElement;
+ T LoadElement(ParseNode node)
+ where T : IAsyncApiElement;
AsyncApiDocument LoadDocument(RootNode rootNode);
}
diff --git a/src/LEGO.AsyncAPI.Readers/Interface/IBindingParser{T}.cs b/src/LEGO.AsyncAPI.Readers/Interface/IBindingParser{T}.cs
new file mode 100644
index 00000000..9c83fe4d
--- /dev/null
+++ b/src/LEGO.AsyncAPI.Readers/Interface/IBindingParser{T}.cs
@@ -0,0 +1,12 @@
+// Copyright (c) The LEGO Group. All rights reserved.
+
+namespace LEGO.AsyncAPI.Readers.Interface
+{
+ using LEGO.AsyncAPI.Models.Interfaces;
+ using LEGO.AsyncAPI.Readers.ParseNodes;
+
+ public interface IBindingParser : IBinding
+ {
+ T LoadBinding(PropertyNode node);
+ }
+}
diff --git a/src/LEGO.AsyncAPI.Readers/LEGO.AsyncAPI.Readers.csproj b/src/LEGO.AsyncAPI.Readers/LEGO.AsyncAPI.Readers.csproj
index d1e8bd74..53071ca0 100644
--- a/src/LEGO.AsyncAPI.Readers/LEGO.AsyncAPI.Readers.csproj
+++ b/src/LEGO.AsyncAPI.Readers/LEGO.AsyncAPI.Readers.csproj
@@ -1,18 +1,11 @@
-
+
- net6.0
- disable
disable
- The LEGO Group
- https://github.com/LEGO/AsyncAPI.NET
- README.md
- AsyncAPI.NET Readers for JSON and YAML documents
- asyncapi .net openapi documentation
- AsyncAPI.NET.Readers
- LEGO.AsyncAPI.Readers
- LEGO.AsyncAPI.Readers
- https://github.com/LEGO/AsyncAPI.NET
+ AsyncAPI.NET Readers for JSON and YAML documents
+ AsyncAPI.NET.Readers
+ LEGO.AsyncAPI.Readers
+ LEGO.AsyncAPI.Readers
@@ -24,7 +17,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -34,14 +27,12 @@
+
-
- True
- \
-
+
-
+
diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyFieldMapParameter.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyFieldMapParameter.cs
index 5b2073ed..76e9008a 100644
--- a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyFieldMapParameter.cs
+++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyFieldMapParameter.cs
@@ -4,13 +4,12 @@ namespace LEGO.AsyncAPI.Readers.ParseNodes
{
using System;
using LEGO.AsyncAPI.Models;
- using LEGO.AsyncAPI.Models.Interfaces;
internal class AnyFieldMapParameter
{
public AnyFieldMapParameter(
- Func propertyGetter,
- Action propertySetter,
+ Func propertyGetter,
+ Action propertySetter,
Func schemaGetter)
{
this.PropertyGetter = propertyGetter;
@@ -18,9 +17,9 @@ public AnyFieldMapParameter(
this.SchemaGetter = schemaGetter;
}
- public Func PropertyGetter { get; }
+ public Func PropertyGetter { get; }
- public Action PropertySetter { get; }
+ public Action PropertySetter { get; }
public Func SchemaGetter { get; }
}
diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapProperty.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapParameter{T}.cs
similarity index 56%
rename from src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapProperty.cs
rename to src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapParameter{T}.cs
index 13c44f33..ee1af993 100644
--- a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapProperty.cs
+++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapParameter{T}.cs
@@ -1,18 +1,16 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
+// Copyright (c) The LEGO Group. All rights reserved.
namespace LEGO.AsyncAPI.Readers.ParseNodes
{
using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Models;
- using LEGO.AsyncAPI.Models.Interfaces;
internal class AnyListFieldMapParameter
{
public AnyListFieldMapParameter(
- Func> propertyGetter,
- Action> propertySetter,
+ Func> propertyGetter,
+ Action> propertySetter,
Func schemaGetter)
{
this.PropertyGetter = propertyGetter;
@@ -20,9 +18,9 @@ public AnyListFieldMapParameter(
this.SchemaGetter = schemaGetter;
}
- public Func> PropertyGetter { get; }
+ public Func> PropertyGetter { get; }
- public Action> PropertySetter { get; }
+ public Action> PropertySetter { get; }
public Func SchemaGetter { get; }
}
diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyMapFieldMapParameter{T,U}.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyMapFieldMapParameter{T,U}.cs
index 8b852453..2399fe31 100644
--- a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyMapFieldMapParameter{T,U}.cs
+++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyMapFieldMapParameter{T,U}.cs
@@ -5,14 +5,13 @@ namespace LEGO.AsyncAPI.Readers.ParseNodes
using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Models;
- using LEGO.AsyncAPI.Models.Interfaces;
internal class AnyMapFieldMapParameter
{
public AnyMapFieldMapParameter(
Func> propertyMapGetter,
- Func propertyGetter,
- Action propertySetter,
+ Func propertyGetter,
+ Action propertySetter,
Func schemaGetter)
{
this.PropertyMapGetter = propertyMapGetter;
@@ -23,9 +22,9 @@ public AnyMapFieldMapParameter(
public Func> PropertyMapGetter { get; }
- public Func PropertyGetter { get; }
+ public Func PropertyGetter { get; }
- public Action PropertySetter { get; }
+ public Action PropertySetter { get; }
public Func SchemaGetter { get; }
}
diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/AsyncApiAnyConverter.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/AsyncApiAnyConverter.cs
deleted file mode 100644
index ae73281e..00000000
--- a/src/LEGO.AsyncAPI.Readers/ParseNodes/AsyncApiAnyConverter.cs
+++ /dev/null
@@ -1,248 +0,0 @@
-// Copyright (c) The LEGO Group. All rights reserved.
-
-namespace LEGO.AsyncAPI.Readers.ParseNodes
-{
- using System;
- using System.Globalization;
- using System.Linq;
- using System.Text;
- using LEGO.AsyncAPI.Models;
- using LEGO.AsyncAPI.Models.Any;
- using LEGO.AsyncAPI.Models.Interfaces;
-
- internal static class AsyncApiAnyConverter
- {
- public static IAsyncApiAny GetSpecificAsyncApiAny(IAsyncApiAny asyncApiAny, AsyncApiSchema schema = null)
- {
- if (asyncApiAny is AsyncApiArray asyncApiArray)
- {
- var newArray = new AsyncApiArray();
- foreach (var element in asyncApiArray)
- {
- newArray.Add(GetSpecificAsyncApiAny(element, schema?.Items));
- }
-
- return newArray;
- }
-
- if (asyncApiAny is AsyncApiObject asyncApiObject)
- {
- var newObject = new AsyncApiObject();
-
- foreach (var key in asyncApiObject.Keys.ToList())
- {
- if (schema?.Properties != null && schema.Properties.TryGetValue(key, out var property))
- {
- newObject[key] = GetSpecificAsyncApiAny(asyncApiObject[key], property);
- }
- else
- {
- newObject[key] = GetSpecificAsyncApiAny(asyncApiObject[key], schema?.AdditionalProperties);
- }
- }
-
- return newObject;
- }
-
- if (!(asyncApiAny is AsyncApiString))
- {
- return asyncApiAny;
- }
-
- var value = ((AsyncApiString)asyncApiAny).Value;
- var type = schema?.Type;
- var format = schema?.Format;
-
- if (((AsyncApiString)asyncApiAny).IsExplicit())
- {
- if (schema == null)
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
- {
- return new AsyncApiDateTime(dateTimeValue);
- }
- }
- else if (type.Contains(SchemaType.String))
- {
- if (format == "byte")
- {
- try
- {
- return new AsyncApiByte(Convert.FromBase64String(value));
- }
- catch (FormatException)
- { }
- }
-
- if (format == "binary")
- {
- try
- {
- return new AsyncApiBinary(Encoding.UTF8.GetBytes(value));
- }
- catch (EncoderFallbackException)
- { }
- }
-
- if (format == "date")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
- {
- return new AsyncApiDate(dateValue.Date);
- }
- }
-
- if (format == "date-time")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
- {
- return new AsyncApiDateTime(dateTimeValue);
- }
- }
- }
-
- return asyncApiAny;
- }
-
- if (value == null || value == "null")
- {
- return new AsyncApiNull();
- }
-
- if (schema?.Type == null)
- {
- if (value == "true")
- {
- return new AsyncApiBoolean(true);
- }
-
- if (value == "false")
- {
- return new AsyncApiBoolean(false);
- }
-
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
- {
- return new AsyncApiInteger(intValue);
- }
-
- if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
- {
- return new AsyncApiLong(longValue);
- }
-
- if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
- {
- return new AsyncApiDouble(doubleValue);
- }
-
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
- {
- return new AsyncApiDateTime(dateTimeValue);
- }
- }
- else
- {
- if (type.Contains(SchemaType.Integer) && format == "int32")
- {
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
- {
- return new AsyncApiInteger(intValue);
- }
- }
-
- if (type.Contains(SchemaType.Integer) && format == "int64")
- {
- if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
- {
- return new AsyncApiLong(longValue);
- }
- }
-
- if (type.Contains(SchemaType.Integer))
- {
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
- {
- return new AsyncApiInteger(intValue);
- }
- }
-
- if (type.Contains(SchemaType.Number) && format == "float")
- {
- if (float.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var floatValue))
- {
- return new AsyncApiFloat(floatValue);
- }
- }
-
- if (type.Contains(SchemaType.Number) && format == "double")
- {
- if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
- {
- return new AsyncApiDouble(doubleValue);
- }
- }
-
- if (type.Contains(SchemaType.Number))
- {
- if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
- {
- return new AsyncApiDouble(doubleValue);
- }
- }
-
- if (type.Contains(SchemaType.String) && format == "byte")
- {
- try
- {
- return new AsyncApiByte(Convert.FromBase64String(value));
- }
- catch (FormatException)
- { }
- }
-
- // binary
- if (type.Contains(SchemaType.String) && format == "binary")
- {
- try
- {
- return new AsyncApiBinary(Encoding.UTF8.GetBytes(value));
- }
- catch (EncoderFallbackException)
- { }
- }
-
- if (type.Contains(SchemaType.String) && format == "date")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
- {
- return new AsyncApiDate(dateValue.Date);
- }
- }
-
- if (type.Contains(SchemaType.String) && format == "date-time")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
- {
- return new AsyncApiDateTime(dateTimeValue);
- }
- }
-
- if (type.Contains(SchemaType.String))
- {
- return asyncApiAny;
- }
-
- if (type.Contains(SchemaType.Boolean))
- {
- if (bool.TryParse(value, out var booleanValue))
- {
- return new AsyncApiBoolean(booleanValue);
- }
- }
- }
-
- return asyncApiAny;
- }
- }
-}
diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/FixedFieldMap.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/FixedFieldMap.cs
index efb046dd..316a927a 100644
--- a/src/LEGO.AsyncAPI.Readers/ParseNodes/FixedFieldMap.cs
+++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/FixedFieldMap.cs
@@ -5,7 +5,7 @@ namespace LEGO.AsyncAPI.Readers.ParseNodes
using System;
using System.Collections.Generic;
- internal class FixedFieldMap : Dictionary>
+ public class FixedFieldMap : Dictionary>
{
}
-}
\ No newline at end of file
+}
diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/JsonPointerExtensions.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/JsonPointerExtensions.cs
index 2cb6302c..acf5857e 100644
--- a/src/LEGO.AsyncAPI.Readers/ParseNodes/JsonPointerExtensions.cs
+++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/JsonPointerExtensions.cs
@@ -3,38 +3,31 @@
namespace LEGO.AsyncAPI.Readers.ParseNodes
{
using System;
- using YamlDotNet.RepresentationModel;
+ using System.Text.Json.Nodes;
public static class JsonPointerExtensions
{
- public static YamlNode Find(this JsonPointer currentPointer, YamlNode baseYamlNode)
+ public static JsonNode Find(this JsonPointer currentPointer, JsonNode baseJsonNode)
{
if (currentPointer.Tokens.Length == 0)
{
- return baseYamlNode;
+ return baseJsonNode;
}
try
{
- var pointer = baseYamlNode;
+ var pointer = baseJsonNode;
foreach (var token in currentPointer.Tokens)
{
- var sequence = pointer as YamlSequenceNode;
+ var sequence = pointer as JsonArray;
- if (sequence != null)
+ if (sequence != null && int.TryParse(token, out var tokenValue))
{
- pointer = sequence.Children[Convert.ToInt32(token)];
+ pointer = sequence[tokenValue];
}
- else
+ else if (pointer is JsonObject map && !map.TryGetPropertyValue(token, out pointer))
{
- var map = pointer as YamlMappingNode;
- if (map != null)
- {
- if (!map.Children.TryGetValue(new YamlScalarNode(token), out pointer))
- {
- return null;
- }
- }
+ return null;
}
}
diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/ListNode.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/ListNode.cs
index c402936e..cce1d406 100644
--- a/src/LEGO.AsyncAPI.Readers/ParseNodes/ListNode.cs
+++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/ListNode.cs
@@ -6,16 +6,15 @@ namespace LEGO.AsyncAPI.Readers.ParseNodes
using System.Collections;
using System.Collections.Generic;
using System.Linq;
- using LEGO.AsyncAPI.Models.Any;
- using LEGO.AsyncAPI.Models.Interfaces;
+ using System.Text.Json.Nodes;
+ using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Readers.Exceptions;
- using YamlDotNet.RepresentationModel;
- internal class ListNode : ParseNode, IEnumerable
+ public class ListNode : ParseNode, IEnumerable
{
- private readonly YamlSequenceNode nodeList;
+ private readonly JsonArray nodeList;
- public ListNode(ParsingContext context, YamlSequenceNode sequenceNode)
+ public ListNode(ParsingContext context, JsonArray sequenceNode)
: base(
context)
{
@@ -27,15 +26,15 @@ public override List CreateList(Func map)
if (this.nodeList == null)
{
throw new AsyncApiReaderException(
- $"Expected list at line {this.nodeList.Start.Line} while parsing {typeof(T).Name}", this.nodeList);
+ $"Expected list while parsing {typeof(T).Name}");
}
- return this.nodeList.Select(n => map(new MapNode(this.Context, n as YamlMappingNode)))
+ return this.nodeList.Select(n => map(new MapNode(this.Context, n as JsonObject)))
.Where(i => i != null)
.ToList();
}
- public override List CreateListOfAny()
+ public override List CreateListOfAny()
{
return this.nodeList.Select(n => ParseNode.Create(this.Context, n).CreateAny())
.Where(i => i != null)
@@ -47,7 +46,7 @@ public override List CreateSimpleList(Func map)
if (this.nodeList == null)
{
throw new AsyncApiReaderException(
- $"Expected list at line {this.nodeList.Start.Line} while parsing {typeof(T).Name}", this.nodeList);
+ $"Expected list while parsing {typeof(T).Name}");
}
return this.nodeList.Select(n => map(new ValueNode(this.Context, n))).ToList();
@@ -63,15 +62,9 @@ IEnumerator IEnumerable.GetEnumerator()
return this.GetEnumerator();
}
- public override IAsyncApiAny CreateAny()
+ public override AsyncApiAny CreateAny()
{
- var array = new AsyncApiArray();
- foreach (var node in this)
- {
- array.Add(node.CreateAny());
- }
-
- return array;
+ return new AsyncApiAny(this.nodeList);
}
}
}
diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/MapNode.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/MapNode.cs
index 41da8d03..b087c875 100644
--- a/src/LEGO.AsyncAPI.Readers/ParseNodes/MapNode.cs
+++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/MapNode.cs
@@ -6,37 +6,36 @@ namespace LEGO.AsyncAPI.Readers.ParseNodes
using System.Collections;
using System.Collections.Generic;
using System.Linq;
+ using System.Text.Json;
+ using System.Text.Json.Nodes;
+ using LEGO.AsyncAPI.Exceptions;
using LEGO.AsyncAPI.Models;
- using LEGO.AsyncAPI.Models.Any;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Readers.Exceptions;
- using YamlDotNet.RepresentationModel;
- using YamlDotNet.Serialization;
- internal class MapNode : ParseNode, IEnumerable
+ public class MapNode : ParseNode, IEnumerable
{
- private readonly YamlMappingNode node;
+ private readonly JsonObject node;
private readonly List nodes;
- public MapNode(ParsingContext context, string yamlString)
- : this(context, (YamlMappingNode)YamlHelper.ParseYamlString(yamlString))
+ public MapNode(ParsingContext context, string jsonString)
+ : this(context, JsonNode.Parse(jsonString))
{
}
- public MapNode(ParsingContext context, YamlNode node)
+ public MapNode(ParsingContext context, JsonNode node)
: base(
context)
{
- if (!(node is YamlMappingNode mapNode))
+ if (!(node is JsonObject mapNode))
{
throw new AsyncApiReaderException("Expected map.", this.Context);
}
this.node = mapNode;
- this.nodes = this.node.Children
- .Select(kvp => new PropertyNode(this.Context, kvp.Key.GetScalarValue(), kvp.Value))
- .Cast()
+ this.nodes = this.node
+ .Select(node => new PropertyNode(this.Context, node.Key, node.Value))
.ToList();
}
@@ -44,8 +43,7 @@ public PropertyNode this[string key]
{
get
{
- YamlNode node;
- if (this.node.Children.TryGetValue(new YamlScalarNode(key), out node))
+ if (this.node.TryGetPropertyValue(key, out var node))
{
return new PropertyNode(this.Context, key, node);
}
@@ -56,23 +54,23 @@ public PropertyNode this[string key]
public override Dictionary CreateMap(Func map)
{
- var yamlMap = this.node;
- if (yamlMap == null)
+ var jsonMap = this.node;
+ if (jsonMap == null)
{
throw new AsyncApiReaderException($"Expected map while parsing {typeof(T).Name}", this.Context);
}
- var nodes = yamlMap.Select(
+ var nodes = jsonMap.Select(
n =>
{
- var key = n.Key.GetScalarValue();
+ var key = n.Key;
T value;
try
{
this.Context.StartObject(key);
- value = n.Value as YamlMappingNode == null
- ? default(T)
- : map(new MapNode(this.Context, n.Value as YamlMappingNode));
+ value = n.Value is JsonObject
+ ? map(new MapNode(this.Context, n.Value))
+ : default(T);
}
finally
{
@@ -81,83 +79,35 @@ public override Dictionary CreateMap(Func map)
return new
{
- key = key,
- value = value,
+ key,
+ value,
};
});
return nodes.ToDictionary(k => k.key, v => v.value);
}
- public override Dictionary CreateBindingMapWithReference(
- ReferenceType referenceType,
- Func map)
- {
- var yamlMap = this.node;
- if (yamlMap == null)
- {
- throw new AsyncApiReaderException($"Expected map while parsing {typeof(T).Name}", this.Context);
- }
-
- var nodes = yamlMap.Select(
- n =>
- {
- var key = n.Key.GetScalarValue();
- (string key, T value) entry;
- try
- {
- this.Context.StartObject(key);
- entry = (
- key: key,
- value: map(new PropertyNode(this.Context, key, n.Value))
- );
-
- if (entry.value == null)
- {
- return default;
- }
-
- if (entry.value.Reference == null)
- {
- entry.value.Reference = new AsyncApiReference()
- {
- Type = referenceType,
- Id = entry.key,
- };
- }
- }
- finally
- {
- this.Context.EndObject();
- }
-
- return entry;
- }
- );
- return nodes.Where(n => n != default).ToDictionary(k => k.key, v => v.value);
- }
-
public override Dictionary CreateMapWithReference(
ReferenceType referenceType,
Func map)
{
- var yamlMap = this.node;
- if (yamlMap == null)
+ var jsonMap = this.node;
+ if (jsonMap == null)
{
throw new AsyncApiReaderException($"Expected map while parsing {typeof(T).Name}", this.Context);
}
- var nodes = yamlMap.Select(
+ var nodes = jsonMap.Select(
n =>
{
- var key = n.Key.GetScalarValue();
+ var key = n.Key;
(string key, T value) entry;
try
{
this.Context.StartObject(key);
entry = (
- key: key,
- value: map(new MapNode(this.Context, (YamlMappingNode)n.Value))
+ key,
+ value: map(new MapNode(this.Context, n.Value))
);
if (entry.value == null)
{
@@ -186,26 +136,26 @@ public override Dictionary CreateMapWithReference(
public override Dictionary CreateSimpleMap(Func map)
{
- var yamlMap = this.node;
- if (yamlMap == null)
+ var jsonMap = this.node;
+ if (jsonMap == null)
{
throw new AsyncApiReaderException($"Expected map while parsing {typeof(T).Name}", this.Context);
}
- var nodes = yamlMap.Select(
+ var nodes = jsonMap.Select(
n =>
{
- var key = n.Key.GetScalarValue();
+ var key = n.Key;
try
{
this.Context.StartObject(key);
- YamlScalarNode scalarNode = n.Value as YamlScalarNode;
+ JsonValue scalarNode = n.Value as JsonValue;
if (scalarNode == null)
{
throw new AsyncApiReaderException($"Expected scalar while parsing {typeof(T).Name}", this.Context);
}
- return (key, value: map(new ValueNode(this.Context, (YamlScalarNode)n.Value)));
+ return (key, value: map(new ValueNode(this.Context, n.Value)));
}
finally
{
@@ -227,8 +177,7 @@ IEnumerator IEnumerable.GetEnumerator()
public override string GetRaw()
{
- var x = new SerializerBuilder().JsonCompatible().Build();
- return x.Serialize(this.node);
+ return JsonSerializer.Serialize(this.node);
}
public T GetReferencedObject(ReferenceType referenceType, string referenceId)
@@ -243,36 +192,32 @@ public T GetReferencedObject(ReferenceType referenceType, string referenceId)
public string GetReferencePointer()
{
- YamlNode refNode;
-
- if (!this.node.Children.TryGetValue(new YamlScalarNode("$ref"), out refNode))
+ if (!this.node.TryGetPropertyValue("$ref", out JsonNode refNode))
{
return null;
}
- return refNode.GetScalarValue();
+ return this.ToScalarValue(refNode);
}
public string GetScalarValue(ValueNode key)
{
- var scalarNode = this.node.Children[new YamlScalarNode(key.GetScalarValue())] as YamlScalarNode;
- if (scalarNode == null)
- {
- throw new AsyncApiReaderException($"Expected scalar at line {this.node.Start.Line} for key {key.GetScalarValue()}", this.Context);
- }
+ var scalarNode = this.node[key.GetScalarValue()] is JsonValue jsonValue
+ ? jsonValue
+ : throw new AsyncApiReaderException($"Expected scalar value while parsing {key.GetScalarValue()}", this.Context);
- return scalarNode.Value;
+ return this.ToScalarValue(scalarNode);
}
- public override IAsyncApiAny CreateAny()
+ public override AsyncApiAny CreateAny()
{
- var apiObject = new AsyncApiObject();
- foreach (var node in this)
- {
- apiObject.Add(node.Name, node.Value.CreateAny());
- }
+ return new AsyncApiAny(this.node);
+ }
- return apiObject;
+ private string ToScalarValue(JsonNode node)
+ {
+ var scalarNode = node is JsonValue value ? value : throw new AsyncApiException($"Expected scalar value");
+ return Convert.ToString(scalarNode.GetValue