Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable v3 support #360

Merged
merged 30 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
22c2195
add request/reply
jonaslagoni Aug 3, 2023
82dea58
bunch of changes
jonaslagoni Aug 11, 2023
f8bc91f
Merge branch 'master' into v3_update
jonaslagoni Aug 11, 2023
e2f0bc7
additional change
jonaslagoni Aug 11, 2023
1db9ad4
fix code smells
jonaslagoni Aug 11, 2023
8f67957
update dependency
jonaslagoni Aug 11, 2023
165c81a
update react sdk version
jonaslagoni Aug 11, 2023
981481a
update react-sdk dependency
jonaslagoni Aug 11, 2023
83a70f4
update dependency
jonaslagoni Aug 11, 2023
0ca3c9d
Merge branch 'upstream-master' into v3_update
jonaslagoni Aug 11, 2023
3e73a9c
update template
jonaslagoni Sep 11, 2023
34a96d5
switch generator dependency
jonaslagoni Sep 14, 2023
e83cfb4
Merge branch 'upstream-master' into v3_update
jonaslagoni Sep 14, 2023
9b75faf
add better testing
jonaslagoni Sep 28, 2023
a9d9508
add workflow to test with generator
jonaslagoni Sep 28, 2023
16aba7f
update cli
jonaslagoni Sep 28, 2023
792bdc2
Merge branch 'master' into v3_update
jonaslagoni Sep 28, 2023
dd12d90
update generator requirement
jonaslagoni Sep 28, 2023
de08455
Merge branch 'upstream-master' into v3_update
jonaslagoni Oct 4, 2023
fdf3443
update dependency
jonaslagoni Oct 4, 2023
5f66a73
use custom operation for v3
jonaslagoni Oct 5, 2023
d77b5c6
refactor operations
jonaslagoni Oct 6, 2023
b97e8da
refactor test setup
jonaslagoni Oct 6, 2023
6c482df
ignore missing props validation
jonaslagoni Oct 6, 2023
8546ce3
ignore missing props validation
jonaslagoni Oct 6, 2023
e61cc54
ignore missing props validation
jonaslagoni Oct 6, 2023
ddd9eaa
ignore missing props validation
jonaslagoni Oct 6, 2023
a46a7ea
ignore missing props validation
jonaslagoni Oct 6, 2023
d4b7a5b
ignore missing props validation
jonaslagoni Oct 6, 2023
507774b
ignore missing props validation
jonaslagoni Oct 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 }) {
jonaslagoni marked this conversation as resolved.
Show resolved Hide resolved
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