Skip to content

Commit

Permalink
feat: enable v3 support (#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonaslagoni authored Oct 9, 2023
1 parent 1d9feff commit 269fb37
Show file tree
Hide file tree
Showing 15 changed files with 21,057 additions and 18,087 deletions.
25 changes: 25 additions & 0 deletions components/Asyncapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Info } from './Info';
import { Servers } from './Servers';
import { Operations } from './Operations';
import { FrontMatter } from './FrontMatter';
import { TableOfContents } from './TableOfContents';

// eslint-disable-next-line no-unused-vars
import { AsyncAPIDocumentInterface } from '@asyncapi/parser';

/**
* @param {{asyncapi: AsyncAPIDocumentInterface, params: any}} param0
*/
export function Asyncapi({ asyncapi, params }) {
return (
<>
{params.frontMatter && <FrontMatter asyncapi={asyncapi} params={params} />}
<Info asyncapi={asyncapi} params={params} />
{params.toc !== 'false' && <TableOfContents asyncapi={asyncapi} />}

<Servers asyncapi={asyncapi} />
<Operations asyncapi={asyncapi} />
</>
);
}

210 changes: 174 additions & 36 deletions components/Operations.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,61 @@
import { Text } from '@asyncapi/generator-react-sdk';

import { Bindings } from './Bindings';
import { Extensions } from './Extensions';
import { Message } from './Message';
import { Schema } from './Schema';
import { Security } from './Security';
import { Tags } from './Tags';
import { Header, ListItem, Link } from './common';

import { SchemaHelpers } from '../helpers/schema';
import { FormatHelpers } from '../helpers/format';

// eslint-disable-next-line no-unused-vars
import { AsyncAPIDocumentInterface, OperationInterface, ChannelInterface } from '@asyncapi/parser';

function isV3({asyncapi}) {
return asyncapi.version().split('.')[0] === '3';
}

/**
* @param {{asyncapi: AsyncAPIDocumentInterface}} param0
*/
export function Operations({ asyncapi }) {
const channels = asyncapi.channels();
if (channels.isEmpty()) {
return null;
}

const operationsList = [];
channels.all().map(channel => {
for (const channel of channels.all()) {
const channelName = channel.address();
channel.operations().all().forEach(operation => {
if (operation.action() === 'publish') {
operationsList.push(
<Operation
key={`pub-${channelName}`}
type='publish'
asyncapi={asyncapi}
operation={operation}
channelName={channelName}
channel={channel}
/>
);
}
if (operation.action() === 'subscribe') {
operationsList.push(
<Operation
key={`sub-${channelName}`}
type='subscribe'
asyncapi={asyncapi}
operation={operation}
channelName={channelName}
channel={channel}
/>
);
const operations = channel.operations().all();
operations.map(operation => {
let type;
if (operation.isSend()) {
if (operation.reply() !== undefined) {
type = 'request';
} else {
type = 'send';
}
} else if (operation.isReceive()) {
if (operation.reply() !== undefined) {
type = 'reply';
} else {
type = 'receive';
}
}
operationsList.push(
<Operation
key={`${operation.action()}-${channelName}`}
type={type}
asyncapi={asyncapi}
operation={operation}
channelName={channelName}
channel={channel}
/>
);
});
});
}

return (
<>
Expand All @@ -57,8 +66,35 @@ export function Operations({ asyncapi }) {
</>
);
}

function Operation({ type, asyncapi, operation, channelName, channel }) { // NOSONAR
function getRenderedTypeForOperation({asyncapi, type}) {
const isv3 = isV3({asyncapi});
if (isv3) {
switch (type) {
case 'request':
return 'REQUEST';
case 'send':
return 'SEND';
case 'reply':
return 'REPLY';
case 'receive':
return 'RECEIVE';
}
}
// For v2, we render the application view still
// Meaning the when you use publish operation it means other publish to your application because your application is subscribing to it.
switch (type) {
case 'send': // This is the publish operation
return 'SUB';
case 'receive': // This is the subscribe operation
return 'PUB';
}
// This case should never happen, if it does this function needs to be changed
return 'UNKNOWN';
}
/**
* @param {{asyncapi: AsyncAPIDocumentInterface, type: string, operation: OperationInterface, channelName: string, channel: ChannelInterface}} param0
*/
function Operation({ asyncapi, type, operation, channelName, channel }) { // NOSONAR
if (!operation || !channel) {
return null;
}
Expand All @@ -68,7 +104,8 @@ function Operation({ type, asyncapi, operation, channelName, channel }) { // NOS
const applyToAllServers = asyncapi.servers().all().length === channel.servers().all().length;
const servers = applyToAllServers ? [] : channel.servers().all();
const security = operation.security();
const renderedType = type === 'publish' ? 'PUB' : 'SUB';
const renderedType = getRenderedTypeForOperation({asyncapi, type});

const showInfoList = operationId || (servers && servers.length);

return (
Expand All @@ -79,7 +116,7 @@ function Operation({ type, asyncapi, operation, channelName, channel }) { // NOS

{operation.summary() && (
<Text newLines={2}>
*{operation.summary()}*
*{operation.summary().trim()}*
</Text>
)}

Expand Down Expand Up @@ -138,11 +175,16 @@ function Operation({ type, asyncapi, operation, channelName, channel }) { // NOS
<Extensions name="Channel extensions" item={channel} />
<Extensions name="Operation extensions" item={operation} />

<OperationMessages operation={operation} />
<OperationMessages operation={operation} asyncapi={asyncapi} type={type} />

<OperationReply operation={operation} />
</Text>
);
}

/**
* @param {{channel: ChannelInterface}} param0
*/
function OperationParameters({ channel }) {
const parameters = SchemaHelpers.parametersToSchema(channel.parameters().all());
if (!parameters) {
Expand All @@ -156,18 +198,36 @@ function OperationParameters({ channel }) {
</Text>
);
}

function OperationMessages({ operation }) {
function getOperationMessageText({asyncapi, type}) {
let messagesText = 'Accepts **one of** the following messages:';
if (isV3({asyncapi})) {
if (type === 'send') {
messagesText = 'Sending **one of** the following messages:';
} else if (type === 'request') {
messagesText = 'Request contains **one of** the following messages:';
} else if (type === 'receive') {
messagesText = 'Receive **one of** the following messages:';
} else if (type === 'reply') {
messagesText = 'Request contains **one of** the following messages:';
}
}
return messagesText;
}
/**
* @param {{operation: OperationInterface, asyncapi: AsyncAPIDocumentInterface, type: string}} param0
*/
function OperationMessages({ asyncapi, operation, type }) {
const messages = operation.messages().all();
if (messages.length === 0) {
return null;
}
const messageText = getOperationMessageText({asyncapi, type});

return (
<>
{messages.length > 1 && (
<Text newLines={2}>
Accepts **one of** the following messages:
{messageText}
</Text>
)}
{messages.map((msg, idx) => (
Expand All @@ -176,3 +236,81 @@ function OperationMessages({ operation }) {
</>
);
}

/**
* @param {{operation: OperationInterface}} param0
*/
function OperationReply({ operation, type }) {
const reply = operation.reply();
if (reply === undefined) {
return null;
}
const explicitChannel = reply.channel();

let typeText;
if (operation.isSend()) {
typeText = 'Request';
} else if (operation.isReceive()) {
typeText = 'Response';
}

let messagesText;
if (type === 'request') {
messagesText = 'Receive **one of** the following messages as a response to the request:';
} else if (type === 'reply') {
messagesText = 'Replying with **one of** the following messages:';
}

return (
<Text>
<Header type={4}>
{`${typeText} information`}
</Header>

{explicitChannel && <ListItem>{type} should be done to channel: `{explicitChannel.address()}`</ListItem>}

<OperationReplyAddress name="Operation reply address" reply={reply} />

<>
{reply.messages().length > 1 && (
<Text newLines={2}>
{messagesText}
</Text>
)}
{reply.messages().length > 1 && reply.messages().map((msg, idx) => (
<Message message={msg} key={`message-${idx}`} />
))}
</>
<Extensions name="Operation reply extensions" item={reply} />
</Text>
);
}

/**
* @param {{reply: OperationReplyInterface}} param0
*/
function OperationReplyAddress({ reply }) {
const address = reply.address();
if (address === undefined) {
return null;
}
const location = address.location();

return (
<Text>
<Header type={4}>
{'Operation reply address information'}
</Header>

{address.hasDescription() && (
<Text newLines={2}>
{address.description()}
</Text>
)}

<ListItem>Operation reply address location: `{location}`</ListItem>

<Extensions name="Operation reply address extensions" item={address} />
</Text>
);
}
6 changes: 6 additions & 0 deletions components/Schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import { SchemaHelpers } from '../helpers/schema';

const headers = ['Name', 'Type', 'Description', 'Value', 'Constraints', 'Notes'];

// eslint-disable-next-line no-unused-vars
import { SchemaInterface } from '@asyncapi/parser';

/**
* @param {{schema: SchemaInterface, schemaName: string, hideTitle: boolean}} param0
*/
export function Schema({ schema, schemaName, hideTitle = false }) {
return (
<Text>
Expand Down
7 changes: 6 additions & 1 deletion helpers/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ export class SchemaHelpers {
return JSON.stringify(value);
}

/**
*
* @param {import('@asyncapi/parser').ChannelParametersInterface} parameters
* @returns
*/
static parametersToSchema(parameters) {
if (parameters.length === 0) {
return;
Expand All @@ -204,7 +209,7 @@ export class SchemaHelpers {
properties: parameters.reduce(
(obj, parameter) => {
const parameterName = parameter.id();
obj[String(parameterName)] = Object.assign({}, parameter.schema().json());
obj[String(parameterName)] = Object.assign({}, parameter.schema() === undefined ? {type: 'string'} : parameter.schema().json());
obj[String(parameterName)].description =
parameter.description() || obj[String(parameterName)].description;
obj[String(parameterName)][this.extParameterLocation] = parameter.location();
Expand Down
Loading

0 comments on commit 269fb37

Please sign in to comment.