asyncapi-tag 1.0.0__tar.gz

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.
@@ -0,0 +1,6 @@
1
+ MIT License
2
+
3
+ Copyright [2024] [Weesho Lapara]
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: asyncapi-tag
3
+ Version: 1.0.0
4
+ Summary: Render AsyncAPI documents in Markdown with an <asyncapi-tag> element. Python-Markdown extension with a MkDocs plugin.
5
+ Author-email: Weesho Lapara <support@weesholapara.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Weesho-Lapara/asyncapi-tag
8
+ Project-URL: Changelog, https://github.com/Weesho-Lapara/asyncapi-tag/blob/main/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/Weesho-Lapara/asyncapi-tag/issues
10
+ Keywords: asyncapi,markdown,mkdocs,documentation,event-driven,api
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Environment :: Web Environment
13
+ Classifier: Framework :: MkDocs
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Documentation
25
+ Classifier: Topic :: Software Development :: Documentation
26
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
27
+ Requires-Python: >=3.9
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: Markdown>=3.4
31
+ Provides-Extra: mkdocs
32
+ Requires-Dist: mkdocs>=1.5; extra == "mkdocs"
33
+ Provides-Extra: test
34
+ Requires-Dist: mkdocs>=1.5; extra == "test"
35
+ Requires-Dist: pytest>=7; extra == "test"
36
+ Dynamic: license-file
37
+
38
+ # asyncapi-tag
39
+
40
+ Render [AsyncAPI](https://www.asyncapi.com/) documents inside Markdown pages with a single element:
41
+
42
+ ```html
43
+ <asyncapi-tag src="asyncapi.yaml"></asyncapi-tag>
44
+ ```
45
+
46
+ `asyncapi-tag` is a [Python-Markdown](https://python-markdown.github.io/) extension, so it works in
47
+ any tool built on Python-Markdown. It ships with a plugin for [MkDocs](https://www.mkdocs.org/)
48
+ that resolves document paths the same way MkDocs resolves links. Rendering in the browser is done
49
+ by the official [AsyncAPI React component](https://github.com/asyncapi/asyncapi-react), pinned to
50
+ an exact version and loaded with Subresource Integrity. JSON and YAML documents both work.
51
+
52
+ > Formerly published as `mkdocs-asyncapi-tag-plugin`. See [Migrating](#migrating-from-mkdocs-asyncapi-tag-plugin).
53
+
54
+ ## MkDocs
55
+
56
+ ```sh
57
+ pip install asyncapi-tag
58
+ ```
59
+
60
+ ```yaml
61
+ # mkdocs.yml
62
+ plugins:
63
+ - asyncapi-tag
64
+ ```
65
+
66
+ Put your AsyncAPI file anywhere under `docs/` and reference it from a page. Paths are relative to
67
+ the Markdown file, or relative to `docs/` when they start with `/`. Absolute `http(s)://` URLs are
68
+ passed through unchanged.
69
+
70
+ ```markdown
71
+ <!-- docs/api/events.md -->
72
+ # Events API
73
+
74
+ <asyncapi-tag src="events.yaml" sidebar="false"></asyncapi-tag>
75
+ ```
76
+
77
+ A missing document or an invalid attribute is reported as a MkDocs warning, so `mkdocs build
78
+ --strict` fails instead of shipping a broken page.
79
+
80
+ ### Plugin options
81
+
82
+ ```yaml
83
+ plugins:
84
+ - asyncapi-tag:
85
+ load_assets: true # emit the viewer script and stylesheet (default: true)
86
+ viewer_js: https://unpkg.com/@asyncapi/react-component@3.2.1/browser/standalone/index.js
87
+ viewer_js_integrity: sha384-… # set to '' to omit the integrity attribute
88
+ viewer_css: https://unpkg.com/@asyncapi/react-component@3.2.1/styles/default.min.css
89
+ viewer_css_integrity: sha384-…
90
+ ```
91
+
92
+ To self-host the viewer, copy the two files into `docs/` and point the options at them.
93
+ Relative paths are resolved per page like `src` is:
94
+
95
+ ```yaml
96
+ plugins:
97
+ - asyncapi-tag:
98
+ viewer_js: assets/asyncapi/index.js
99
+ viewer_js_integrity: ''
100
+ viewer_css: assets/asyncapi/default.min.css
101
+ viewer_css_integrity: ''
102
+ ```
103
+
104
+ Or set `load_assets: false` and load the files yourself through `extra_javascript` and
105
+ `extra_css`. The page-side runner script is still needed in that case; copy it from
106
+ `asyncapi_tag.assets.RUNNER_JS`.
107
+
108
+ ## Plain Python-Markdown
109
+
110
+ ```python
111
+ import markdown
112
+
113
+ html = markdown.markdown(text, extensions=["asyncapi_tag"])
114
+ ```
115
+
116
+ Extension options (pass them as `extension_configs={"asyncapi_tag": {...}}`):
117
+
118
+ | Option | Default | Description |
119
+ |---|---|---|
120
+ | `viewer_js`, `viewer_css` | pinned unpkg URLs | Where to load the viewer from |
121
+ | `viewer_js_integrity`, `viewer_css_integrity` | matching SRI hashes | Empty string omits the attribute |
122
+ | `load_assets` | `True` | Emit the loader with the first tag on a page |
123
+ | `url_resolver` | identity | Callable mapping `src` (and relative asset URLs) to what the browser fetches |
124
+ | `warn` | `logging` | Callable receiving warning messages |
125
+
126
+ ## Attributes
127
+
128
+ Only `src` is required. Attribute names are case-insensitive. Boolean attributes accept
129
+ `true`/`false`, `1`/`0`, `yes`/`no`, `on`/`off`; a bare attribute means `true`.
130
+
131
+ | Attribute | Values | Default | Effect |
132
+ |---|---|---|---|
133
+ | `src` | path or URL | required | The AsyncAPI document (JSON or YAML) |
134
+ | `id` | string | `asyncapi-tag-N` | HTML id of the container element |
135
+ | `sidebar` | boolean | `true` | Show the navigation sidebar |
136
+ | `info` | boolean | `true` | Show the info section |
137
+ | `servers` | boolean | `true` | Show servers |
138
+ | `operations` | boolean | `true` | Show operations |
139
+ | `messages` | boolean | `true` | Show messages |
140
+ | `schemas` | boolean | `true` | Show schemas |
141
+ | `errors` | boolean | `true` | Show parser errors |
142
+ | `showMessageExamples` | boolean | viewer default | Show examples for standalone messages |
143
+ | `messageExamples` | boolean | `true` | Expand message examples |
144
+ | `showServers` | `byDefault`, `bySpecTags`, `byServersTags` | `byDefault` | How the sidebar groups servers |
145
+ | `showOperations` | `byDefault`, `bySpecTags`, `byOperationsTags` | `byDefault` | How the sidebar groups operations |
146
+ | `useChannelAddressAsIdentifier` | boolean | viewer default | AsyncAPI v3: label operations by channel address |
147
+ | `publishLabel`, `subscribeLabel` | string | `PUB`, `SUB` | Operation labels for AsyncAPI v2 |
148
+ | `sendLabel`, `receiveLabel`, `requestLabel`, `replyLabel` | string | `SEND`, `RECEIVE`, `REQUEST`, `REPLY` | Operation labels for AsyncAPI v3 |
149
+ | `parserOptions` | JSON object | viewer default | Passed to the AsyncAPI parser, e.g. `parserOptions='{"applyTraits": false}'` |
150
+ | `schemaID` | string | container id | The viewer's `schemaID` option |
151
+
152
+ These map onto the React component's
153
+ [configuration](https://github.com/asyncapi/asyncapi-react/blob/master/docs/configuration/config-modification.md).
154
+ Defaults for `sidebar` and `messageExamples` follow earlier releases of this plugin rather than the
155
+ viewer, so existing pages keep their look.
156
+
157
+ ## How it works
158
+
159
+ Each tag becomes a `<div class="asyncapi-tag">` carrying the document URL and the viewer
160
+ configuration as HTML-escaped data attributes. The first tag on a page also emits the viewer's
161
+ stylesheet and script and a short runner script. The runner fetches each document as text, hands it
162
+ to `AsyncApiStandalone.render`, and prints a visible error inside the container if fetching or
163
+ rendering fails. No content from the Markdown source is interpolated into JavaScript.
164
+
165
+ Tags inside fenced or indented code blocks are left alone, so you can document the syntax.
166
+
167
+ Material for MkDocs users with `navigation.instant` enabled are covered: the runner re-scans the
168
+ page on Material's `document$` event.
169
+
170
+ ## Migrating from mkdocs-asyncapi-tag-plugin
171
+
172
+ 1. Replace `mkdocs-asyncapi-tag-plugin` with `asyncapi-tag` in your requirements. The plugin id in
173
+ `mkdocs.yml` is unchanged (`asyncapi-tag`).
174
+ 2. Remove the `asyncapi_file` plugin option. MkDocs already copies every non-Markdown file under
175
+ `docs/` into the site; the option now only prints a deprecation warning.
176
+ 3. Use a path relative to the page (or `/`-prefixed relative to `docs/`) in `src`. Earlier versions
177
+ emitted the build machine's filesystem path, so only `/`-prefixed paths ever worked; those still work.
178
+ 4. String attributes such as `publishLabel="PUBLISH"` and `showServers="bySpecTags"` now take
179
+ effect. Earlier versions silently discarded them.
180
+
181
+ `mkdocs-asyncapi-tag-plugin` 1.0.0 is a deprecated shim that only depends on this package, so
182
+ upgrading it also works, but no further releases will be made under the old name.
183
+
184
+ ## Updating the pinned viewer
185
+
186
+ ```sh
187
+ python scripts/update_viewer.py # latest @asyncapi/react-component
188
+ python scripts/update_viewer.py 3.2.1 # specific version
189
+ ```
190
+
191
+ The script rewrites the version, URLs and SRI hashes in `src/asyncapi_tag/assets.py`.
192
+
193
+ ## Development
194
+
195
+ ```sh
196
+ python -m venv .venv && source .venv/bin/activate
197
+ pip install -e ".[test]"
198
+ pytest
199
+ ```
200
+
201
+ The JavaScript runner is syntax-checked with `node` when it is installed. See `AGENTS.md` for the
202
+ repository layout and release procedure.
203
+
204
+ ## License
205
+
206
+ MIT
@@ -0,0 +1,169 @@
1
+ # asyncapi-tag
2
+
3
+ Render [AsyncAPI](https://www.asyncapi.com/) documents inside Markdown pages with a single element:
4
+
5
+ ```html
6
+ <asyncapi-tag src="asyncapi.yaml"></asyncapi-tag>
7
+ ```
8
+
9
+ `asyncapi-tag` is a [Python-Markdown](https://python-markdown.github.io/) extension, so it works in
10
+ any tool built on Python-Markdown. It ships with a plugin for [MkDocs](https://www.mkdocs.org/)
11
+ that resolves document paths the same way MkDocs resolves links. Rendering in the browser is done
12
+ by the official [AsyncAPI React component](https://github.com/asyncapi/asyncapi-react), pinned to
13
+ an exact version and loaded with Subresource Integrity. JSON and YAML documents both work.
14
+
15
+ > Formerly published as `mkdocs-asyncapi-tag-plugin`. See [Migrating](#migrating-from-mkdocs-asyncapi-tag-plugin).
16
+
17
+ ## MkDocs
18
+
19
+ ```sh
20
+ pip install asyncapi-tag
21
+ ```
22
+
23
+ ```yaml
24
+ # mkdocs.yml
25
+ plugins:
26
+ - asyncapi-tag
27
+ ```
28
+
29
+ Put your AsyncAPI file anywhere under `docs/` and reference it from a page. Paths are relative to
30
+ the Markdown file, or relative to `docs/` when they start with `/`. Absolute `http(s)://` URLs are
31
+ passed through unchanged.
32
+
33
+ ```markdown
34
+ <!-- docs/api/events.md -->
35
+ # Events API
36
+
37
+ <asyncapi-tag src="events.yaml" sidebar="false"></asyncapi-tag>
38
+ ```
39
+
40
+ A missing document or an invalid attribute is reported as a MkDocs warning, so `mkdocs build
41
+ --strict` fails instead of shipping a broken page.
42
+
43
+ ### Plugin options
44
+
45
+ ```yaml
46
+ plugins:
47
+ - asyncapi-tag:
48
+ load_assets: true # emit the viewer script and stylesheet (default: true)
49
+ viewer_js: https://unpkg.com/@asyncapi/react-component@3.2.1/browser/standalone/index.js
50
+ viewer_js_integrity: sha384-… # set to '' to omit the integrity attribute
51
+ viewer_css: https://unpkg.com/@asyncapi/react-component@3.2.1/styles/default.min.css
52
+ viewer_css_integrity: sha384-…
53
+ ```
54
+
55
+ To self-host the viewer, copy the two files into `docs/` and point the options at them.
56
+ Relative paths are resolved per page like `src` is:
57
+
58
+ ```yaml
59
+ plugins:
60
+ - asyncapi-tag:
61
+ viewer_js: assets/asyncapi/index.js
62
+ viewer_js_integrity: ''
63
+ viewer_css: assets/asyncapi/default.min.css
64
+ viewer_css_integrity: ''
65
+ ```
66
+
67
+ Or set `load_assets: false` and load the files yourself through `extra_javascript` and
68
+ `extra_css`. The page-side runner script is still needed in that case; copy it from
69
+ `asyncapi_tag.assets.RUNNER_JS`.
70
+
71
+ ## Plain Python-Markdown
72
+
73
+ ```python
74
+ import markdown
75
+
76
+ html = markdown.markdown(text, extensions=["asyncapi_tag"])
77
+ ```
78
+
79
+ Extension options (pass them as `extension_configs={"asyncapi_tag": {...}}`):
80
+
81
+ | Option | Default | Description |
82
+ |---|---|---|
83
+ | `viewer_js`, `viewer_css` | pinned unpkg URLs | Where to load the viewer from |
84
+ | `viewer_js_integrity`, `viewer_css_integrity` | matching SRI hashes | Empty string omits the attribute |
85
+ | `load_assets` | `True` | Emit the loader with the first tag on a page |
86
+ | `url_resolver` | identity | Callable mapping `src` (and relative asset URLs) to what the browser fetches |
87
+ | `warn` | `logging` | Callable receiving warning messages |
88
+
89
+ ## Attributes
90
+
91
+ Only `src` is required. Attribute names are case-insensitive. Boolean attributes accept
92
+ `true`/`false`, `1`/`0`, `yes`/`no`, `on`/`off`; a bare attribute means `true`.
93
+
94
+ | Attribute | Values | Default | Effect |
95
+ |---|---|---|---|
96
+ | `src` | path or URL | required | The AsyncAPI document (JSON or YAML) |
97
+ | `id` | string | `asyncapi-tag-N` | HTML id of the container element |
98
+ | `sidebar` | boolean | `true` | Show the navigation sidebar |
99
+ | `info` | boolean | `true` | Show the info section |
100
+ | `servers` | boolean | `true` | Show servers |
101
+ | `operations` | boolean | `true` | Show operations |
102
+ | `messages` | boolean | `true` | Show messages |
103
+ | `schemas` | boolean | `true` | Show schemas |
104
+ | `errors` | boolean | `true` | Show parser errors |
105
+ | `showMessageExamples` | boolean | viewer default | Show examples for standalone messages |
106
+ | `messageExamples` | boolean | `true` | Expand message examples |
107
+ | `showServers` | `byDefault`, `bySpecTags`, `byServersTags` | `byDefault` | How the sidebar groups servers |
108
+ | `showOperations` | `byDefault`, `bySpecTags`, `byOperationsTags` | `byDefault` | How the sidebar groups operations |
109
+ | `useChannelAddressAsIdentifier` | boolean | viewer default | AsyncAPI v3: label operations by channel address |
110
+ | `publishLabel`, `subscribeLabel` | string | `PUB`, `SUB` | Operation labels for AsyncAPI v2 |
111
+ | `sendLabel`, `receiveLabel`, `requestLabel`, `replyLabel` | string | `SEND`, `RECEIVE`, `REQUEST`, `REPLY` | Operation labels for AsyncAPI v3 |
112
+ | `parserOptions` | JSON object | viewer default | Passed to the AsyncAPI parser, e.g. `parserOptions='{"applyTraits": false}'` |
113
+ | `schemaID` | string | container id | The viewer's `schemaID` option |
114
+
115
+ These map onto the React component's
116
+ [configuration](https://github.com/asyncapi/asyncapi-react/blob/master/docs/configuration/config-modification.md).
117
+ Defaults for `sidebar` and `messageExamples` follow earlier releases of this plugin rather than the
118
+ viewer, so existing pages keep their look.
119
+
120
+ ## How it works
121
+
122
+ Each tag becomes a `<div class="asyncapi-tag">` carrying the document URL and the viewer
123
+ configuration as HTML-escaped data attributes. The first tag on a page also emits the viewer's
124
+ stylesheet and script and a short runner script. The runner fetches each document as text, hands it
125
+ to `AsyncApiStandalone.render`, and prints a visible error inside the container if fetching or
126
+ rendering fails. No content from the Markdown source is interpolated into JavaScript.
127
+
128
+ Tags inside fenced or indented code blocks are left alone, so you can document the syntax.
129
+
130
+ Material for MkDocs users with `navigation.instant` enabled are covered: the runner re-scans the
131
+ page on Material's `document$` event.
132
+
133
+ ## Migrating from mkdocs-asyncapi-tag-plugin
134
+
135
+ 1. Replace `mkdocs-asyncapi-tag-plugin` with `asyncapi-tag` in your requirements. The plugin id in
136
+ `mkdocs.yml` is unchanged (`asyncapi-tag`).
137
+ 2. Remove the `asyncapi_file` plugin option. MkDocs already copies every non-Markdown file under
138
+ `docs/` into the site; the option now only prints a deprecation warning.
139
+ 3. Use a path relative to the page (or `/`-prefixed relative to `docs/`) in `src`. Earlier versions
140
+ emitted the build machine's filesystem path, so only `/`-prefixed paths ever worked; those still work.
141
+ 4. String attributes such as `publishLabel="PUBLISH"` and `showServers="bySpecTags"` now take
142
+ effect. Earlier versions silently discarded them.
143
+
144
+ `mkdocs-asyncapi-tag-plugin` 1.0.0 is a deprecated shim that only depends on this package, so
145
+ upgrading it also works, but no further releases will be made under the old name.
146
+
147
+ ## Updating the pinned viewer
148
+
149
+ ```sh
150
+ python scripts/update_viewer.py # latest @asyncapi/react-component
151
+ python scripts/update_viewer.py 3.2.1 # specific version
152
+ ```
153
+
154
+ The script rewrites the version, URLs and SRI hashes in `src/asyncapi_tag/assets.py`.
155
+
156
+ ## Development
157
+
158
+ ```sh
159
+ python -m venv .venv && source .venv/bin/activate
160
+ pip install -e ".[test]"
161
+ pytest
162
+ ```
163
+
164
+ The JavaScript runner is syntax-checked with `node` when it is installed. See `AGENTS.md` for the
165
+ repository layout and release procedure.
166
+
167
+ ## License
168
+
169
+ MIT
@@ -0,0 +1,58 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "asyncapi-tag"
7
+ dynamic = ["version"]
8
+ description = "Render AsyncAPI documents in Markdown with an <asyncapi-tag> element. Python-Markdown extension with a MkDocs plugin."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.9"
13
+ authors = [{ name = "Weesho Lapara", email = "support@weesholapara.com" }]
14
+ keywords = ["asyncapi", "markdown", "mkdocs", "documentation", "event-driven", "api"]
15
+ classifiers = [
16
+ "Development Status :: 5 - Production/Stable",
17
+ "Environment :: Web Environment",
18
+ "Framework :: MkDocs",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3 :: Only",
23
+ "Programming Language :: Python :: 3.9",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
29
+ "Topic :: Documentation",
30
+ "Topic :: Software Development :: Documentation",
31
+ "Topic :: Text Processing :: Markup :: Markdown",
32
+ ]
33
+ dependencies = ["Markdown>=3.4"]
34
+
35
+ [project.optional-dependencies]
36
+ mkdocs = ["mkdocs>=1.5"]
37
+ test = ["mkdocs>=1.5", "pytest>=7"]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/Weesho-Lapara/asyncapi-tag"
41
+ Changelog = "https://github.com/Weesho-Lapara/asyncapi-tag/blob/main/CHANGELOG.md"
42
+ Issues = "https://github.com/Weesho-Lapara/asyncapi-tag/issues"
43
+
44
+ [project.entry-points."markdown.extensions"]
45
+ asyncapi_tag = "asyncapi_tag.extension:AsyncAPITagExtension"
46
+
47
+ [project.entry-points."mkdocs.plugins"]
48
+ asyncapi-tag = "asyncapi_tag.mkdocs_plugin:AsyncAPIPlugin"
49
+
50
+ [tool.setuptools.dynamic]
51
+ version = { attr = "asyncapi_tag.__version__" }
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["src"]
55
+
56
+ [tool.pytest.ini_options]
57
+ testpaths = ["tests"]
58
+ addopts = "-ra"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,28 @@
1
+ """Render AsyncAPI documents in Markdown with an ``<asyncapi-tag>`` element.
2
+
3
+ The package is a `Python-Markdown <https://python-markdown.github.io/>`_
4
+ extension (:class:`asyncapi_tag.extension.AsyncAPITagExtension`) and a thin
5
+ MkDocs plugin around it (:class:`asyncapi_tag.mkdocs_plugin.AsyncAPIPlugin`).
6
+ """
7
+
8
+ from asyncapi_tag.assets import (
9
+ VIEWER_CSS_INTEGRITY,
10
+ VIEWER_CSS_URL,
11
+ VIEWER_JS_INTEGRITY,
12
+ VIEWER_JS_URL,
13
+ VIEWER_VERSION,
14
+ )
15
+ from asyncapi_tag.extension import AsyncAPITagExtension, makeExtension
16
+
17
+ __version__ = "1.0.0"
18
+
19
+ __all__ = [
20
+ "AsyncAPITagExtension",
21
+ "makeExtension",
22
+ "VIEWER_VERSION",
23
+ "VIEWER_JS_URL",
24
+ "VIEWER_JS_INTEGRITY",
25
+ "VIEWER_CSS_URL",
26
+ "VIEWER_CSS_INTEGRITY",
27
+ "__version__",
28
+ ]
@@ -0,0 +1,106 @@
1
+ """Pinned viewer assets and the browser-side loader.
2
+
3
+ The viewer is the standalone bundle of ``@asyncapi/react-component``. The
4
+ version, URLs and Subresource Integrity hashes below are updated together
5
+ with ``scripts/update_viewer.py``; do not edit them by hand.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import html
11
+
12
+ # --- managed by scripts/update_viewer.py ------------------------------------
13
+ VIEWER_VERSION = "3.2.1"
14
+ VIEWER_JS_URL = "https://unpkg.com/@asyncapi/react-component@3.2.1/browser/standalone/index.js"
15
+ VIEWER_JS_INTEGRITY = "sha384-wy5bSOazlkSKMGH7XMW6+pK8ho8+rCPr7mTqKdAb/dvfwXAPWCFivgr3C7wJMFAh"
16
+ VIEWER_CSS_URL = "https://unpkg.com/@asyncapi/react-component@3.2.1/styles/default.min.css"
17
+ VIEWER_CSS_INTEGRITY = "sha384-oo9RoQcacP++XdMX6CjTucTvASEORHX3chFik0/V2kHcsHiVboGyWZztGeq/0bum"
18
+ # ---------------------------------------------------------------------------
19
+
20
+ CONTAINER_CLASS = "asyncapi-tag"
21
+
22
+ # Runs once per page. It finds every container the extension emitted, fetches
23
+ # the AsyncAPI document as text (JSON or YAML, the viewer parses both) and
24
+ # renders it. Nothing from the Markdown source is interpolated into this
25
+ # script: per-tag data travels in HTML data attributes, which are HTML-escaped.
26
+ RUNNER_JS = """\
27
+ (function () {
28
+ "use strict";
29
+ var SELECTOR = ".asyncapi-tag[data-asyncapi-src]";
30
+ function showError(el, message) {
31
+ el.textContent = "";
32
+ var p = document.createElement("p");
33
+ p.className = "asyncapi-tag-error";
34
+ p.textContent = "AsyncAPI viewer: " + message;
35
+ el.appendChild(p);
36
+ }
37
+ function render(el) {
38
+ if (el.getAttribute("data-asyncapi-state")) { return; }
39
+ el.setAttribute("data-asyncapi-state", "loading");
40
+ var src = el.getAttribute("data-asyncapi-src");
41
+ var config = {};
42
+ try {
43
+ config = JSON.parse(el.getAttribute("data-asyncapi-config") || "{}");
44
+ } catch (err) {
45
+ showError(el, "invalid configuration (" + err.message + ")");
46
+ return;
47
+ }
48
+ if (!window.AsyncApiStandalone) {
49
+ showError(el, "the viewer script did not load; check the browser console and any Content Security Policy.");
50
+ return;
51
+ }
52
+ fetch(src, { credentials: "same-origin" }).then(function (response) {
53
+ if (!response.ok) {
54
+ throw new Error("could not fetch " + src + " (HTTP " + response.status + ")");
55
+ }
56
+ return response.text();
57
+ }).then(function (text) {
58
+ return window.AsyncApiStandalone.render({ schema: text, config: config }, el);
59
+ }).then(function () {
60
+ el.setAttribute("data-asyncapi-state", "rendered");
61
+ }).catch(function (err) {
62
+ showError(el, err && err.message ? err.message : String(err));
63
+ if (window.console) { console.error("asyncapi-tag:", err); }
64
+ });
65
+ }
66
+ function renderAll() {
67
+ var nodes = document.querySelectorAll(SELECTOR);
68
+ for (var i = 0; i < nodes.length; i++) { render(nodes[i]); }
69
+ }
70
+ renderAll();
71
+ /* Material for MkDocs instant navigation swaps page content without a reload. */
72
+ if (window.document$ && typeof window.document$.subscribe === "function") {
73
+ window.document$.subscribe(renderAll);
74
+ }
75
+ })();
76
+ """
77
+
78
+
79
+ def _attr(name: str, value: str) -> str:
80
+ return f' {name}="{html.escape(value, quote=True)}"'
81
+
82
+
83
+ def loader_html(
84
+ js_url: str,
85
+ css_url: str,
86
+ js_integrity: str = "",
87
+ css_integrity: str = "",
88
+ ) -> str:
89
+ """Return the HTML that loads the viewer and runs it on the page.
90
+
91
+ Integrity attributes are emitted only when a hash is given, so the loader
92
+ also works for self-hosted copies of the viewer.
93
+ """
94
+ parts = []
95
+ if css_url:
96
+ attrs = _attr("rel", "stylesheet") + _attr("href", css_url)
97
+ if css_integrity:
98
+ attrs += _attr("integrity", css_integrity) + _attr("crossorigin", "anonymous")
99
+ parts.append(f"<link{attrs}>")
100
+ if js_url:
101
+ attrs = _attr("src", js_url)
102
+ if js_integrity:
103
+ attrs += _attr("integrity", js_integrity) + _attr("crossorigin", "anonymous")
104
+ parts.append(f"<script{attrs}></script>")
105
+ parts.append(f"<script>{RUNNER_JS}</script>")
106
+ return "\n".join(parts)