diff --git a/components/Channels.js b/components/Channels.js
deleted file mode 100644
index f17b224d8..000000000
--- a/components/Channels.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import { Text } from "@asyncapi/generator-react-sdk";
-import { SchemaHelpers } from "../helpers/schema";
-
-import { Header } from "./common";
-import { Message } from "./Message";
-import { Schema } from "./Schema";
-
-export function Channels({ asyncapi }) {
- const channels = Object.entries(asyncapi.channels()).map(([channelName, channel]) => (
-
- ));
-
- return (
- <>
-
- {channels}
- >
- );
-}
-
-function Channel({ channelName, channel }) {
- return (
-
-
- {`**${channelName}** Channel`}
-
- {channel.hasDescription() && (
-
- {channel.description()}
-
- )}
- {channel.hasParameters() && (
-
- )}
- {channel.hasPublish() && (
-
- )}
- {channel.hasSubscribe() && (
-
- )}
-
- );
-}
-
-function Parameters({ parameters }) {
- const parametersSchema = SchemaHelpers.parametersToSchema(parameters);
- return (
-
-
-
-
- );
-}
-
-function OperationMessages({ messages }) {
- return (
- <>
- {messages.length > 1 &&
-
- Accepts **one of** the following messages:
-
- }
- {messages.map(msg => (
-
- ))
- }
- >
- )
-}
-
-function Operation({ operation }) {
- const type = operation.isPublish() ? 'publish' : 'subscribe';
- const hasMessages = operation.hasMultipleMessages() || !!operation.message(0);
- return (
-
- {`\`${type}\` Operation`}
- {operation.summary() && (
-
- *{operation.summary()}*
-
- )}
- {operation.hasDescription() && (
-
- {operation.description()}
-
- )}
- {hasMessages && (
-
- )}
-
- );
-}
diff --git a/components/Info.js b/components/Info.js
index 5c0000592..8cd77f5e2 100644
--- a/components/Info.js
+++ b/components/Info.js
@@ -112,9 +112,10 @@ export function Info({ asyncapi, params = {} }) {
)}
{asyncapi.hasTags() && (
-
+ <>
+
-
+ >
)}
);
diff --git a/components/Message.js b/components/Message.js
index 2d3478663..4e52bd236 100644
--- a/components/Message.js
+++ b/components/Message.js
@@ -1,44 +1,105 @@
-import { Text } from "@asyncapi/generator-react-sdk";
+import { IndentationTypes, Text } from "@asyncapi/generator-react-sdk";
import { generateExample, getPayloadExamples, getHeadersExamples } from "@asyncapi/generator-filters";
import { Schema } from "./Schema";
import { Tags } from "./Tags";
-import { Header, CodeBlock, BlockQuote } from "./common";
+import { Header, ListItem, Link, BlockQuote, CodeBlock, NewLine } from "./common";
+
+export function Message({ message }) {
+ if (!message) {
+ return null;
+ }
+
+ const headers = message.headers();
+ const payload = message.payload();
+ const correlationId = message.correlationId();
+ const contentType = message.contentType();
+ const externalDocs = message.externalDocs();
+ const showInfoList = contentType || externalDocs;
+
+ let header = `Message`;
+ if (message.title()) {
+ header += ` ${message.title()}`
+ }
+ if (message.uid()) {
+ header += ` \`${message.uid()}\``
+ }
-export function Message({ message, title = 'Message' }) {
return (
<>
-
+
+
{message.summary() && (
*{message.summary()}*
)}
+
+ {showInfoList ? (
+
+ {contentType && (
+
+ Content type:{' '}
+
+ {contentType}
+
+
+ )}
+ {correlationId && (
+ <>
+
+ Correlation ID: `{correlationId.location()}`
+
+ {correlationId.hasDescription() && (
+ <>
+
+
+ {correlationId.description()}
+
+ >
+ )}
+ >
+ )}
+
+ ) : null}
+
{message.hasDescription() && (
{message.description()}
)}
- {message.headers() && (
+ {externalDocs && (
+
+
+ {externalDocs.hasDescription() ? externalDocs.description() : 'Find more info here.'}
+
+
+ )}
+
+ {headers && (
<>
-
-
+
+
>
)}
- {message.payload() && (
+ {payload && (
<>
-
-
+
+
>
)}
{message.hasTags() && (
<>
-
+
>
)}
@@ -95,7 +156,7 @@ function Example({ examples = [] }) {
return examples.map(ex => (
- {ex.name && **{ex.name}**}
+ {ex.name && _{ex.name}_}
{ex.summary && {ex.summary}}
{JSON.stringify(ex.example, null, 2)}
diff --git a/components/Operations.js b/components/Operations.js
new file mode 100644
index 000000000..736ff9b42
--- /dev/null
+++ b/components/Operations.js
@@ -0,0 +1,159 @@
+import { Text } from "@asyncapi/generator-react-sdk";
+
+import { Message } from "./Message";
+import { Schema } from "./Schema";
+import { Tags } from "./Tags";
+import { Header, ListItem, Link } from "./common";
+
+import { SchemaHelpers } from "../helpers/schema";
+import { FormatHelpers } from "../helpers/format";
+
+export function Operations({ asyncapi }) {
+ const channels = asyncapi.channels();
+ if (!Object.keys(channels).length) {
+ return null;
+ }
+
+ const operationsList = [];
+ Object.entries(channels).forEach(([channelName, channel]) => {
+ if (channel.hasPublish()) {
+ operationsList.push(
+
+ );
+ }
+ if (channel.hasSubscribe()) {
+ operationsList.push(
+
+ );
+ }
+ });
+
+ return (
+ <>
+
+ {operationsList}
+ >
+ );
+}
+
+function Operation({ type, operation, channelName, channel }) {
+ if (!operation || !channel) {
+ return null;
+ }
+
+ const operationId = operation.id();
+ const externalDocs = operation.externalDocs();
+ // check typeof as fallback for older version than `2.2.0`
+ const servers = typeof channel.servers === 'function' && channel.servers();
+ const renderedType = type === 'publish' ? 'PUB' : 'SUB';
+ const showInfoList = operationId || (servers && servers.length);
+
+ return (
+
+
+ {`${renderedType} \`${channelName}\` Operation`}
+
+
+ {operation.summary() && (
+
+ *{operation.summary()}*
+
+ )}
+
+ {showInfoList ? (
+
+ {operationId && Operation ID: `{operationId}`}
+ {servers && servers.length && (
+
+ Available only on servers:{' '}
+ {servers.map(s => {
+ const slug = FormatHelpers.slugify(s);
+ return `[${s}](#${slug}-server)`;
+ }).join(', ')}
+
+ )}
+
+ ) : null}
+
+ {channel.hasDescription() && (
+
+ {channel.description()}
+
+ )}
+ {operation.hasDescription() && (
+
+ {operation.description()}
+
+ )}
+
+ {externalDocs && (
+
+
+ {externalDocs.hasDescription() ? externalDocs.description() : 'Find more info here.'}
+
+
+ )}
+
+ {operation.hasTags() && (
+ <>
+
+
+ >
+ )}
+
+
+
+
+ );
+}
+
+function OperationParameters({ channel }) {
+ const parameters = SchemaHelpers.parametersToSchema(channel.parameters());
+ if (!parameters) {
+ return null;
+ }
+
+ return (
+
+
+
+
+ );
+}
+
+function OperationMessages({ operation }) {
+ const hasMessages = operation.hasMultipleMessages() || !!operation.message(0);
+ if (!hasMessages) {
+ return null;
+ }
+ const messages = operation.messages();
+
+ return (
+ <>
+ {messages.length > 1 && (
+
+ Accepts **one of** the following messages:
+
+ )}
+ {messages.map(msg => (
+
+ ))}
+ >
+ );
+}
diff --git a/components/Schema.js b/components/Schema.js
index cea6c28db..eba2e1b78 100644
--- a/components/Schema.js
+++ b/components/Schema.js
@@ -8,7 +8,7 @@ export function Schema({ schema, schemaName, hideTitle = false }) {
const headers = ['Name', 'Type', 'Description', 'Value', 'Constraints', 'Notes'];
return (
- {hideTitle === false ? : null}
+ {schemaName && hideTitle === false ? : null}
@@ -301,6 +301,12 @@ function schemaNotes({ schema, required = false, dependentRequired = [], isCircu
notes.push(`**required when defined (${dependentRequired.map(v => `\`${v}\``).join(', ')})**`);
}
+ // location for channel parameter
+ const parameterLocation = schema.ext(SchemaHelpers.extParameterLocation);
+ if (parameterLocation) {
+ notes.push(`**parameter location (${parameterLocation})**`);
+ }
+
if (isCircular) notes.push('**circular**');
if (schema.writeOnly()) notes.push('**write-only**');
if (schema.readOnly()) notes.push('**read-only**');
diff --git a/components/TableOfContents.js b/components/TableOfContents.js
index e2a3b0ddd..ef9ae38e6 100644
--- a/components/TableOfContents.js
+++ b/components/TableOfContents.js
@@ -2,24 +2,38 @@ import { Text, Indent, IndentationTypes } from "@asyncapi/generator-react-sdk";
import { Header, Link, ListItem } from "../components/common";
+import { FormatHelpers } from "../helpers/format";
+
export function TableOfContents({ asyncapi }) {
const serversList = Object.keys(asyncapi.servers()).map(serverName => {
return (
- {serverName}
+ {serverName}
);
});
- const channelsList = Object.keys(asyncapi.channels()).map(channelName => {
- return (
-
-
- {channelName}
-
-
- );
+ const operationsList = [];
+ Object.entries(asyncapi.channels()).map(([channelName, channel]) => {
+ if (channel.hasPublish()) {
+ operationsList.push(
+
+
+ PUB {channelName}
+
+
+ );
+ }
+ if (channel.hasSubscribe()) {
+ operationsList.push(
+
+
+ SUB {channelName}
+
+
+ );
+ }
});
return (
@@ -34,52 +48,11 @@ export function TableOfContents({ asyncapi }) {
{serversList.length > 0 && serversList}
{asyncapi.hasChannels() &&
- Channels
+ Operations
}
- {channelsList.length > 0 && channelsList}
+ {operationsList.length > 0 && operationsList}
>
);
}
-
-/**
- * Slugify (change value to appropriate hash) the url part of a markdown link.
- *
- * @param {String} `str` The string to slugify
- * @return {String}
- */
-function slugify(str) {
- str = getTitle(str);
- str = str.toLowerCase();
-
- // `split(...).join(...)` is faster than `replace(..., ...)`
- // for spaces
- str = str.split(' ').join('-');
- // for tabs
- str = str.split(/\t/).join('--');
- // for html tags
- str = str.split(/<\/?[^>]{1,100}>/).join('');
- // for special characters from ASCII (part 1)
- str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>.,;:'"^]/).join('');
- // for special characters from ASCII (part 2)
- str = str.split(/[。?!,、;:【】()〔〕[]﹃﹄“ ”‘’﹁﹂—…-~《》〈〉「」]/).join('');
-
- return str;
-}
-
-/**
- * Get the "title" from a markdown link
- *
- * @param {String} `str` The string to retrieve title
- * @return {String}
- */
-function getTitle(str) {
- // check if in `str` is "title" from a markdown link (use `(` char at the end for easy markdown link checking)
- if (/^\[[^\]]+\]\(/.test(str)) {
- // retrieve "title" from a markdown link
- var m = /^\[([^\]]+)\]/.exec(str);
- if (m) return m[1];
- }
- return str;
-}
diff --git a/helpers/format.js b/helpers/format.js
index ffb12693f..c1806d39d 100644
--- a/helpers/format.js
+++ b/helpers/format.js
@@ -1,4 +1,10 @@
export class FormatHelpers {
+ /**
+ * Wrap input string to markdown's inline code
+ *
+ * @param {String} `value` The string to wrap
+ * @return {String}
+ */
static inlineCode(value) {
if (
value === null ||
@@ -9,4 +15,45 @@ export class FormatHelpers {
) return '';
return `\`${value}\``;
}
+
+ /**
+ * Slugify (change value to appropriate hash) the url part of a markdown link.
+ *
+ * @param {String} `str` The string to slugify
+ * @return {String}
+ */
+ static slugify(str) {
+ str = this.getTitle(str);
+ str = str.toLowerCase();
+
+ // `split(...).join(...)` is faster than `replace(..., ...)`
+ // for spaces
+ str = str.split(' ').join('-');
+ // for tabs
+ str = str.split(/\t/).join('--');
+ // for html tags
+ str = str.split(/<\/?[^>]{1,100}>/).join('');
+ // for special characters from ASCII (part 1)
+ str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>.,;:'"^]/).join('');
+ // for special characters from ASCII (part 2)
+ str = str.split(/[。?!,、;:【】()〔〕[]﹃﹄“ ”‘’﹁﹂—…-~《》〈〉「」]/).join('');
+
+ return str;
+ }
+
+ /**
+ * Get the "title" from a markdown link
+ *
+ * @param {String} `str` The string to retrieve title
+ * @return {String}
+ */
+ static getTitle(str) {
+ // check if in `str` is "title" from a markdown link (use `(` char at the end for easy markdown link checking)
+ if (/^\[[^\]]+\]\(/.test(str)) {
+ // retrieve "title" from a markdown link
+ var m = /^\[([^\]]+)\]/.exec(str);
+ if (m) return m[1];
+ }
+ return str;
+ }
}
diff --git a/helpers/schema.js b/helpers/schema.js
index 5d1e0206b..af2d0ae62 100644
--- a/helpers/schema.js
+++ b/helpers/schema.js
@@ -55,6 +55,7 @@ export class SchemaHelpers {
static extRenderType = 'x-schema-private-render-type';
static extRenderAdditionalInfo = 'x-schema-private-render-additional-info';
static extRawValue = 'x-schema-private-raw-value';
+ static extParameterLocation = 'x-schema-private-parameter-location';
static toSchemaType(schema) {
if (!schema || typeof schema.json !== 'function') {
@@ -207,6 +208,7 @@ export class SchemaHelpers {
obj[paramaterName] = Object.assign({}, parameter.schema().json());
obj[paramaterName].description =
parameter.description() || obj[paramaterName].description;
+ obj[paramaterName][this.extParameterLocation] = parameter.location();
return obj;
},
{},
diff --git a/template/asyncapi.js b/template/asyncapi.js
index 70a15034b..9e36bce15 100644
--- a/template/asyncapi.js
+++ b/template/asyncapi.js
@@ -2,7 +2,7 @@ import { File } from "@asyncapi/generator-react-sdk";
import { Info } from "../components/Info";
import { Servers } from "../components/Servers";
-import { Channels } from "../components/Channels";
+import { Operations } from "../components/Operations";
import { FrontMatter } from "../components/FrontMatter";
import { TableOfContents } from "../components/TableOfContents";
@@ -14,7 +14,7 @@ export default function({ asyncapi, params = {} }) {
{params.toc !== 'false' && }
-
+
);
}
diff --git a/test/components/Info.test.js b/test/components/Info.test.js
index 45d8991d1..6c4feb644 100644
--- a/test/components/Info.test.js
+++ b/test/components/Info.test.js
@@ -76,6 +76,8 @@ The Smartylighting Streetlights API allows you to remotely manage the city light
* Dim a specific streetlight 😎
* Receive real-time information about environmental lighting conditions 📈
+###### Specification tags
+
* root-tag1
[External docs description 1](https://www.asyncapi.com/)
diff --git a/test/components/Message.test.js b/test/components/Message.test.js
new file mode 100644
index 000000000..52ef6d10a
--- /dev/null
+++ b/test/components/Message.test.js
@@ -0,0 +1,340 @@
+import { render } from '@asyncapi/generator-react-sdk';
+
+import { Message } from "../../components/Message";
+import MessageModel from '@asyncapi/parser/lib/models/message';
+
+describe('Message component', () => {
+ it('should render simple message', () => {
+ const message = new MessageModel({
+ "title": "User signup",
+ "name": "UserSignup",
+ "summary": "Action to sign a user up.",
+ "headers": {
+ "type": "object",
+ "properties": {
+ "correlationId": {
+ "description": "Correlation ID set by application",
+ "type": "string"
+ },
+ "applicationInstanceId": {
+ "description": "Unique identifier for a given instance of the publishing application",
+ "type": "string"
+ }
+ }
+ },
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "string"
+ },
+ "signup": {
+ "type": "string"
+ }
+ }
+ },
+ });
+ const expected = `
+#### Message User signup \`UserSignup\`
+
+*Action to sign a user up.*
+
+##### Headers
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+| correlationId | string | Correlation ID set by application | - | - | - |
+| applicationInstanceId | string | Unique identifier for a given instance of the publishing application | - | - | - |
+
+> Examples of headers _(generated)_
+
+\`\`\`json
+{
+ "correlationId": "string",
+ "applicationInstanceId": "string"
+}
+\`\`\`
+
+
+##### Payload
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+| user | string | - | - | - | - |
+| signup | string | - | - | - | - |
+
+> Examples of payload _(generated)_
+
+\`\`\`json
+{
+ "user": "string",
+ "signup": "string"
+}
+\`\`\`
+`;
+
+ const result = render();
+ expect(result.trim()).toEqual(expected.trim());
+ });
+
+ it('should render complete message', () => {
+ const message = new MessageModel({
+ "name": "UserSignup",
+ "title": "User signup",
+ "summary": "Action to sign a user up.",
+ "description": "A longer description",
+ "contentType": "application/json",
+ "tags": [
+ { "name": "user" },
+ { "name": "signup" },
+ { "name": "register" }
+ ],
+ "headers": {
+ "type": "object",
+ "properties": {
+ "correlationId": {
+ "description": "Correlation ID set by application",
+ "type": "string"
+ },
+ "applicationInstanceId": {
+ "description": "Unique identifier for a given instance of the publishing application",
+ "type": "string"
+ }
+ }
+ },
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "string"
+ },
+ "signup": {
+ "type": "string"
+ }
+ }
+ },
+ "correlationId": {
+ "description": "Default Correlation ID",
+ "location": "$message.header#/correlationId"
+ },
+ "examples": [
+ {
+ "name": "SimpleSignup",
+ "summary": "A simple UserSignup example message",
+ "headers": {
+ "correlationId": "my-correlation-id",
+ "applicationInstanceId": "myInstanceId"
+ },
+ "payload": {
+ "user": {
+ "someUserKey": "someUserValue"
+ },
+ "signup": {
+ "someSignupKey": "someSignupValue"
+ }
+ }
+ }
+ ]
+ });
+ const expected = `
+#### Message User signup \`UserSignup\`
+
+*Action to sign a user up.*
+
+* Content type: [application/json](https://www.iana.org/assignments/media-types/application/json)
+* Correlation ID: \`$message.header#/correlationId\`
+
+ Default Correlation ID
+
+A longer description
+
+##### Headers
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+| correlationId | string | Correlation ID set by application | - | - | - |
+| applicationInstanceId | string | Unique identifier for a given instance of the publishing application | - | - | - |
+
+> Examples of headers
+
+_SimpleSignup_
+
+A simple UserSignup example message
+
+\`\`\`json
+{
+ "correlationId": "my-correlation-id",
+ "applicationInstanceId": "myInstanceId"
+}
+\`\`\`
+
+
+##### Payload
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+| user | string | - | - | - | - |
+| signup | string | - | - | - | - |
+
+> Examples of payload
+
+_SimpleSignup_
+
+A simple UserSignup example message
+
+\`\`\`json
+{
+ "user": {
+ "someUserKey": "someUserValue"
+ },
+ "signup": {
+ "someSignupKey": "someSignupValue"
+ }
+}
+\`\`\`
+
+
+###### Message tags
+
+* user
+
+* signup
+
+* register
+`;
+
+ const result = render();
+ expect(result.trim()).toEqual(expected.trim());
+ });
+
+ it('should render multiple messages', () => {
+ const message = new MessageModel({
+ "name": "UserSignup",
+ "title": "User signup",
+ "headers": {
+ "type": "object",
+ },
+ "payload": {
+ "type": "object",
+ },
+ "examples": [
+ {
+ "name": "SimpleSignup",
+ "summary": "A simple UserSignup example message",
+ "headers": {
+ "correlationId": "my-correlation-id",
+ "applicationInstanceId": "myInstanceId"
+ },
+ "payload": {
+ "user": {
+ "someUserKey": "someUserValue"
+ },
+ "signup": {
+ "someSignupKey": "someSignupValue"
+ }
+ }
+ },
+ {
+ "name": "ExtendedSimpleSignup",
+ "summary": "A simple ExtendedSimpleSignup example message",
+ "headers": {
+ "correlationId": "my-correlation-id",
+ },
+ "payload": {
+ "user": {
+ "someUserKey": "foobar"
+ },
+ "signup": {
+ "someSignupKey": "barfoo"
+ }
+ }
+ }
+ ]
+ });
+ const expected = `
+#### Message User signup \`UserSignup\`
+
+##### Headers
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+
+> Examples of headers
+
+_SimpleSignup_
+
+A simple UserSignup example message
+
+\`\`\`json
+{
+ "correlationId": "my-correlation-id",
+ "applicationInstanceId": "myInstanceId"
+}
+\`\`\`
+
+
+_ExtendedSimpleSignup_
+
+A simple ExtendedSimpleSignup example message
+
+\`\`\`json
+{
+ "correlationId": "my-correlation-id"
+}
+\`\`\`
+
+
+##### Payload
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+
+> Examples of payload
+
+_SimpleSignup_
+
+A simple UserSignup example message
+
+\`\`\`json
+{
+ "user": {
+ "someUserKey": "someUserValue"
+ },
+ "signup": {
+ "someSignupKey": "someSignupValue"
+ }
+}
+\`\`\`
+
+
+_ExtendedSimpleSignup_
+
+A simple ExtendedSimpleSignup example message
+
+\`\`\`json
+{
+ "user": {
+ "someUserKey": "foobar"
+ },
+ "signup": {
+ "someSignupKey": "barfoo"
+ }
+}
+\`\`\`
+`;
+
+ const result = render();
+ expect(result.trim()).toEqual(expected.trim());
+ });
+
+ it('should render nothing if message prop is undefined', () => {
+ const result = render();
+ expect(result).toEqual('');
+ });
+});
diff --git a/test/components/Operations.test.js b/test/components/Operations.test.js
new file mode 100644
index 000000000..86fce8488
--- /dev/null
+++ b/test/components/Operations.test.js
@@ -0,0 +1,225 @@
+import { render } from '@asyncapi/generator-react-sdk';
+
+import { Operations } from "../../components/Operations";
+import AsyncAPIDocument from '@asyncapi/parser/lib/models/asyncapi';
+
+describe('Operations component', () => {
+ it('should render operation', () => {
+ const asyncapi = new AsyncAPIDocument({
+ "channels": {
+ "user/signedup": {
+ "description": "This channel is used to exchange messages about users signing up",
+ "servers": [
+ "rabbitmqBrokerInProd",
+ "rabbitmqBrokerInStaging",
+ ],
+ "subscribe": {
+ "operationId": "signedupuser",
+ "externalDocs": {
+ "description": "More info here",
+ "url": "https://example.com"
+ },
+ "tags": [
+ { "name": "user" },
+ { "name": "signup" },
+ { "name": "register" }
+ ],
+ "summary": "A user signed up.",
+ "message": {
+ "description": "A longer description of the message",
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "string"
+ },
+ "signup": {
+ "type": "number"
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ });
+ const expected = `
+## Operations
+
+### SUB \`user/signedup\` Operation
+
+*A user signed up.*
+
+* Operation ID: \`signedupuser\`
+* Available only on servers: [rabbitmqBrokerInProd](#rabbitmqbrokerinprod-server), [rabbitmqBrokerInStaging](#rabbitmqbrokerinstaging-server)
+
+This channel is used to exchange messages about users signing up
+
+[More info here](https://example.com)
+
+###### Operation tags
+
+* user
+
+* signup
+
+* register
+
+#### Message \`\`
+
+A longer description of the message
+
+##### Payload
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+| user | string | - | - | - | - |
+| signup | number | - | - | - | - |
+
+> Examples of payload _(generated)_
+
+\`\`\`json
+{
+ "user": "string",
+ "signup": 0
+}
+\`\`\`
+`;
+
+ const result = render();
+ expect(result.trim()).toEqual(expected.trim());
+ });
+
+ it('should render parameters for operation', () => {
+ const asyncapi = new AsyncAPIDocument({
+ "channels": {
+ "user/{userId}/signup/{foobar}": {
+ "parameters": {
+ "userId": {
+ "description": "Id of the user.",
+ "schema": {
+ "type": "string"
+ },
+ "location": "$message.payload#/user/id"
+ },
+ "foobar": {
+ "schema": {
+ "type": "string"
+ },
+ }
+ },
+ "publish": {}
+ }
+ },
+ });
+ const expected = `
+## Operations
+
+### PUB \`user/{userId}/signup/{foobar}\` Operation
+
+#### Parameters
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| userId | string | Id of the user. | - | - | **required**, **parameter location ($message.payload#/user/id)** |
+| foobar | string | - | - | - | **required** |
+`;
+
+ const result = render();
+ expect(result.trim()).toEqual(expected.trim());
+ });
+
+ it('should render multiple messages', () => {
+ const asyncapi = new AsyncAPIDocument({
+ "channels": {
+ "user/{userId}/signup/{foobar}": {
+ "publish": {
+ "message": {
+ "oneOf": [
+ {
+ "description": "A longer description of the message",
+ "payload": {
+ "type": "object",
+ "properties": {
+ "signup": {
+ "type": "number"
+ }
+ }
+ }
+ },
+ {
+ "description": "A longer description of the message",
+ "payload": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "string"
+ },
+ }
+ }
+ },
+ ]
+ }
+ }
+ }
+ },
+ });
+ const expected = `
+## Operations
+
+### PUB \`user/{userId}/signup/{foobar}\` Operation
+
+Accepts **one of** the following messages:
+
+#### Message \`\`
+
+A longer description of the message
+
+##### Payload
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+| signup | number | - | - | - | - |
+
+> Examples of payload _(generated)_
+
+\`\`\`json
+{
+ "signup": 0
+}
+\`\`\`
+
+
+#### Message \`\`
+
+A longer description of the message
+
+##### Payload
+
+| Name | Type | Description | Value | Constraints | Notes |
+|---|---|---|---|---|---|
+| (root) | object | - | - | - | **additional properties are allowed** |
+| user | string | - | - | - | - |
+
+> Examples of payload _(generated)_
+
+\`\`\`json
+{
+ "user": "string"
+}
+\`\`\`
+`;
+
+ const result = render();
+ expect(result.trim()).toEqual(expected.trim());
+ });
+
+ it('should render nothing if operations prop is undefined', () => {
+ const asyncapi = new AsyncAPIDocument({});
+
+ const result = render();
+ expect(result).toEqual('');
+ });
+});
diff --git a/test/components/TableOfContents.test.js b/test/components/TableOfContents.test.js
index 6f20ce83a..0991e414f 100644
--- a/test/components/TableOfContents.test.js
+++ b/test/components/TableOfContents.test.js
@@ -12,8 +12,16 @@ describe('TableOfContents component', () => {
canary: {},
},
channels: {
- testChannel: {},
- 'smartylighting/streetlights/1/0': {},
+ testChannel: {
+ publish: {},
+ subscribe: {},
+ },
+ 'smartylighting/streetlights/1/0': {
+ subscribe: {},
+ },
+ 'smartylighting/streetlights': {
+ publish: {},
+ },
},
});
const expected = `
@@ -23,9 +31,11 @@ describe('TableOfContents component', () => {
* [production](#production-server)
* [testing](#testing-server)
* [canary](#canary-server)
-* [Channels](#channels)
- * [testChannel](#testchannel-channel)
- * [smartylighting/streetlights/1/0](#smartylightingstreetlights10-channel)
+* [Operations](#operations)
+ * [PUB testChannel](#pub-testchannel-operation)
+ * [SUB testChannel](#sub-testchannel-operation)
+ * [SUB smartylighting/streetlights/1/0](#sub-smartylightingstreetlights10-operation)
+ * [PUB smartylighting/streetlights](#pub-smartylightingstreetlights-operation)
`;
const result = render();
diff --git a/test/helpers/schema.test.js b/test/helpers/schema.test.js
index 02b471286..38faca16c 100644
--- a/test/helpers/schema.test.js
+++ b/test/helpers/schema.test.js
@@ -325,10 +325,12 @@ describe('SchemaHelpers', () => {
foo: {
type: 'string',
description: undefined,
+ "x-schema-private-parameter-location": undefined
},
bar: {
type: 'string',
description: 'Some description',
+ "x-schema-private-parameter-location": "$message.payload#/user/id"
},
},
required: ['foo', 'bar'],