lutaml-asyncapi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b75c05f01f5016b7deba173f61e368b03928246dffb6f33fd5a7a097fbd4f960
4
+ data.tar.gz: eafbc41e37f96e3f5298782b3fe9a9c63a031bd7b0bea907f9cea25da67a5d30
5
+ SHA512:
6
+ metadata.gz: 883f8c505425be9ad9425614ccc796c4afd64a59b8f93fe2aebba5ed15725ea4567feb9458f59d95ba94ec12ee544dff82a47dd23076f90e3e0b3d139ef13819
7
+ data.tar.gz: f95b27f78433d007a170fdfef17f77f05e34dbdc7719cf2bfd76272e5d26ea17acbe85db67a2b21132788b10f35640cb7a6756e822b4f32cddf14bc10c827154
data/.rubocop_todo.yml ADDED
@@ -0,0 +1 @@
1
+ # Auto-generated by Cimas; offenses baselined at scaffold time.
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
@@ -0,0 +1,10 @@
1
+ # Code of Conduct
2
+
3
+ "lutaml-jsonschema" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
4
+
5
+ * Participants will be tolerant of opposing views.
6
+ * Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
7
+ * When interpreting the words and actions of others, participants should always assume good intentions.
8
+ * Behaviour which can be reasonably considered harassment will not be tolerated.
9
+
10
+ If you have any concerns about behaviour within this project, please contact us at ["ronald.tse@ribose.com"](mailto:"ronald.tse@ribose.com").
data/LICENSE.md ADDED
@@ -0,0 +1,33 @@
1
+ Licenses & Copyright
2
+ ====================
3
+
4
+ This license file adheres to the formatting guidelines of
5
+ [readable-licenses](https://github.com/nevir/readable-licenses).
6
+
7
+
8
+ Ribose's BSD 2-Clause License
9
+ -----------------------------
10
+
11
+ Copyright (c) 2026, [Ribose Inc](https://www.ribose.com).
12
+ All rights reserved.
13
+
14
+ Redistribution and use in source and binary forms, with or without modification,
15
+ are permitted provided that the following conditions are met:
16
+
17
+ 1. Redistributions of source code must retain the above copyright notice,
18
+ this list of conditions and the following disclaimer.
19
+
20
+ 2. Redistributions in binary form must reproduce the above copyright notice,
21
+ this list of conditions and the following disclaimer in the documentation
22
+ and/or other materials provided with the distribution.
23
+
24
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
28
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/PLAN.md ADDED
@@ -0,0 +1,86 @@
1
+ # PLAN.md — lutaml-asyncapi: AsyncAPI as a model-based standard
2
+
3
+ The event-driven counterpart of the OpenAPI program
4
+ ([metanorma/metanorma-ogc#153](https://github.com/metanorma/metanorma-ogc/issues/153),
5
+ `lutaml/lutaml-openapi`): make the AsyncAPI definition the **primary
6
+ publication** of event-driven / pub-sub API standards, with normative
7
+ documentation driven by the AsyncAPI model.
8
+
9
+ ## Mission
10
+
11
+ Parse **AsyncAPI 2.6, 3.0 and 3.1** documents into a lossless lutaml-model
12
+ object graph (raw-hash fidelity first, typed views on demand), and feed them
13
+ to documentation renderers the way `lutaml-openapi` feeds
14
+ `metanorma-plugin-openapi`.
15
+
16
+ ## Audit basis (2026-10-25)
17
+
18
+ Full spec read: `asyncapi/spec` `spec/asyncapi.md` (v3.1.0, 39 objects),
19
+ meta-schemas `asyncapi/spec-json-schemas` (definitions 1.0.0–3.1.0).
20
+ Corpus: 17 documents in `spec/fixtures` — 15 official 3.1.0 examples,
21
+ `asyncapi-connectedsystems-2.yaml` (2.6.0, 9 embedded publish/subscribe
22
+ operations), `edr-pubsub-asyncapi.yaml` (3.0.0). **All parse; 15/17 round-trip
23
+ losslessly** — `gitter-streaming` and `slack-rtm` are blocked upstream by
24
+ [lutaml/lutaml-model#1013](https://github.com/lutaml/lutaml-model/issues/1013)
25
+ (nested `:hash` attributes silently rename key `text` → `type` and drop
26
+ sibling `description`); they are vendored but excluded from goldens until
27
+ that ships.
28
+
29
+ Corpus facts shaping the model: no `schemaFormat` (Multi Format Schema)
30
+ usage in the wild corpus; bindings sparse (kafka/mqtt/websocket); components
31
+ sections seen in the wild: schemas, messages, parameters, securitySchemes,
32
+ correlationIds, messageTraits, operationTraits (the model must still cover
33
+ the full Components Object inventory: servers, channels, operations, replies,
34
+ replyAddresses, externalDocs, tags, serverBindings, channelBindings,
35
+ operationBindings, messageBindings, serverVariables).
36
+
37
+ ## Repos and org parity
38
+
39
+ | Repo | Org | Role | Setup cloned from |
40
+ |---|---|---|---|
41
+ | `lutaml/lutaml-asyncapi` | lutaml | the model gem (this repo) | lutaml-openapi (generic-rake CI, cimas release train, rubocop baseline, BSD-2-Clause) |
42
+ | `metanorma/metanorma-plugin-asyncapi` | metanorma | the Metanorma plugin (M3) | metanorma-plugin-openapi (preprocessor splice, real sections) |
43
+
44
+ Team access mirrors siblings: staff:admin, developers:push, ci:push,
45
+ express:push, editors:push.
46
+
47
+ ## Architecture
48
+
49
+ ```
50
+ AsyncAPI 2.6 / 3.0 / 3.1 (YAML/JSON)
51
+ │ parse (2.x/3.0 normalized into the 3.x-shaped model; source version kept)
52
+ ▼
53
+ Lutaml::Asyncapi::Document (lossless: mapped roots + map_unmapped)
54
+ │ round-trip goes through to_json —
55
+ │ Serializable#to_hash emits attribute names
56
+ ├─► typed views (channels, operations, messages) on demand
57
+ └─► metanorma-plugin-asyncapi (M3): preprocessor splice — block
58
+ processors can never yield sections (Parser.parse_blocks limit)
59
+ ```
60
+
61
+ ## Milestones
62
+
63
+ - **M0 — model seed (this repo)**: `Lutaml::Asyncapi.parse` (Yeptris
64
+ YAML/JSON by sniffing, version detect), `Document` (3.x shape,
65
+ `map_unmapped` extensions), lossless round-trip goldens from the corpus.
66
+ Done-when: 15/17 goldens green, rubocop clean, CI green.
67
+ - **M1 — full typed model**: typed views for channels/operations/messages/
68
+ components incl. Multi Format Schema, bindings, security schemes; 2.6
69
+ frontend (embedded publish/subscribe → operation view, like Oas30).
70
+ Done-when: every spec object has a typed accessor and a spec.
71
+ - **M2 — validation**: offline meta-schema checks against the vendored
72
+ asyncapi/spec-json-schemas (lutaml-jsonschema precedent, JSON Pointer
73
+ error paths).
74
+ - **M3 — metanorma-plugin-asyncapi**: renderer + preprocessor; OGC
75
+ connected-systems part 2 and EDR pubsub as the acceptance corpus.
76
+ - **M4 — SPA frontend**: single-file human documentation (lutaml-xsd /
77
+ lutaml-jsonschema precedent).
78
+
79
+ ## Standing laws
80
+
81
+ - Losslessness lives on the raw hash; typed views are on-demand.
82
+ - No hand-rolled serialization — lutaml-model mappings only
83
+ (`map`/`map_unmapped`/attribute serializers).
84
+ - No doubles in specs — real documents from the corpus.
85
+ - Round-trip assertions go through `to_json` (see the `to_hash` gotcha).
86
+ - Versions are the owner's decision; releases only on explicit instruction.
data/README.md ADDED
@@ -0,0 +1 @@
1
+ # lutaml-asyncapi
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Asyncapi
5
+ # The root AsyncAPI document object, in the 3.x shape.
6
+ #
7
+ # Losslessness lives on the raw mapping: every section is kept verbatim
8
+ # and unmodeled keywords re-emit on serialization (map_unmapped).
9
+ # Round-trip assertions go through to_json — Serializable#to_hash emits
10
+ # attribute names, not mapped wire names.
11
+ class Document < Lutaml::Model::Serializable
12
+ attribute :asyncapi, :string
13
+ attribute :id, :string
14
+ attribute :info, :hash
15
+ attribute :servers, :hash
16
+ attribute :default_content_type, :string
17
+ attribute :channels, :hash
18
+ attribute :operations, :hash
19
+ attribute :components, :hash
20
+ attribute :tags, :hash, collection: true
21
+ attribute :external_docs, :hash
22
+ attribute :extensions, :hash, default: -> { {} }
23
+
24
+ json do
25
+ map "asyncapi", to: :asyncapi
26
+ map "id", to: :id
27
+ map "info", to: :info
28
+ map "servers", to: :servers
29
+ map "defaultContentType", to: :default_content_type
30
+ map "channels", to: :channels
31
+ map "operations", to: :operations
32
+ map "components", to: :components
33
+ map "tags", to: :tags
34
+ map "externalDocs", to: :external_docs
35
+ map_unmapped to: :extensions
36
+ end
37
+
38
+ # The 2.x dialects embed publish/subscribe in channels and carry
39
+ # root tags/externalDocs; the 3.x model holds them verbatim until
40
+ # the 2.x frontend (PLAN.md M1) normalizes the operation view.
41
+ def dialect
42
+ version = asyncapi.to_s
43
+ case version
44
+ when /\A2\./ then "2.x"
45
+ when /\A3\./ then "3.x"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Asyncapi
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "yeptris/yaml"
5
+ require "lutaml/model"
6
+
7
+ module Lutaml
8
+ # AsyncAPI 2.6/3.0/3.1 as a lossless lutaml-model.
9
+ module Asyncapi
10
+ autoload :Document, "lutaml/asyncapi/document"
11
+
12
+ # Parses an AsyncAPI document (YAML or JSON) into a Document.
13
+ def self.parse(string)
14
+ data = parse_raw(string)
15
+ Document.from_json(JSON.generate(data))
16
+ end
17
+
18
+ def self.parse_raw(string)
19
+ case string
20
+ when /\A\s*{/
21
+ JSON.parse(string)
22
+ else
23
+ Yeptris::YAML.load(string)
24
+ end
25
+ end
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lutaml-asyncapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ribose Inc.
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: json
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: lutaml-model
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.8.122
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.8.122
40
+ - !ruby/object:Gem::Dependency
41
+ name: nokogiri
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: yeptris
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.6.34
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 0.6.34
68
+ description: Parse AsyncAPI 2.6/3.0/3.1 documents into lossless LutaML model objects;
69
+ the model layer for model-based AsyncAPI standards
70
+ email:
71
+ - open.source@ribose.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".rubocop_todo.yml"
77
+ - CHANGELOG.md
78
+ - CODE_OF_CONDUCT.md
79
+ - LICENSE.md
80
+ - PLAN.md
81
+ - README.md
82
+ - Rakefile
83
+ - lib/lutaml/asyncapi.rb
84
+ - lib/lutaml/asyncapi/document.rb
85
+ - lib/lutaml/asyncapi/version.rb
86
+ homepage: https://github.com/lutaml/lutaml-asyncapi
87
+ licenses:
88
+ - BSD-2-Clause
89
+ metadata:
90
+ homepage_uri: https://github.com/lutaml/lutaml-asyncapi
91
+ source_code_uri: https://github.com/lutaml/lutaml-asyncapi
92
+ changelog_uri: https://github.com/lutaml/lutaml-asyncapi/blob/main/CHANGELOG.md
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: 3.2.0
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 3.6.9
108
+ specification_version: 4
109
+ summary: AsyncAPI 2.6/3.0/3.1 as a lossless lutaml-model
110
+ test_files: []