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: make @asyncapi/react-component compatible with vs-asyncapi-preview #1078

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
87 changes: 0 additions & 87 deletions library/src/containers/AsyncApi/AsyncApi.tsx

This file was deleted.

60 changes: 39 additions & 21 deletions library/src/containers/AsyncApi/Standalone.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React, { Component } from 'react';
import { AsyncAPIDocumentInterface } from '@asyncapi/parser';

import { SpecificationHelpers } from '../../helpers';
import { ErrorObject, PropsSchema } from '../../types';
import { Parser, SpecificationHelpers } from '../../helpers';
import {
ErrorObject,
isFetchingSchemaInterface,
PropsSchema,
} from '../../types';
import { ConfigInterface, defaultConfig } from '../../config';

import AsyncApiLayout from './Layout';
Expand All @@ -11,7 +15,6 @@ import { Error } from '../Error/Error';
export interface AsyncApiProps {
schema: PropsSchema;
config?: Partial<ConfigInterface>;
error?: ErrorObject;
}

interface AsyncAPIState {
Expand All @@ -27,33 +30,27 @@ class AsyncApiComponent extends Component<AsyncApiProps, AsyncAPIState> {

constructor(props: AsyncApiProps) {
super(props);

const parsedSpec = SpecificationHelpers.retrieveParsedSpec(props.schema);
if (parsedSpec) {
this.state = { asyncapi: parsedSpec };
}
}

componentDidMount() {
componentDidMount = async () => {
if (!this.state.asyncapi) {
this.updateState(this.props.schema);
await this.parseSchemaAndSetState(this.props.schema);
}
}
};

componentDidUpdate(prevProps: AsyncApiProps) {
componentDidUpdate = async (prevProps: AsyncApiProps) => {
const oldSchema = prevProps.schema;
const newSchema = this.props.schema;

if (oldSchema !== newSchema) {
this.updateState(newSchema);
await this.parseSchemaAndSetState(newSchema);
}
}
};

render() {
const { config, error: propError } = this.props;
const { asyncapi, error: stateError } = this.state;
const { config } = this.props;
const { asyncapi, error } = this.state;

const error = propError ?? stateError;
const concatenatedConfig: ConfigInterface = {
...defaultConfig,
...config,
Expand Down Expand Up @@ -93,13 +90,34 @@ class AsyncApiComponent extends Component<AsyncApiProps, AsyncAPIState> {
);
}

private updateState(schema: PropsSchema) {
private async parseSchemaAndSetState(
schema: PropsSchema,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
parserOptions?: any,
) {
const parsedSpec = SpecificationHelpers.retrieveParsedSpec(schema);
if (!parsedSpec) {
this.setState({ asyncapi: undefined });
if (parsedSpec) {
this.setState({
asyncapi: parsedSpec,
error: undefined,
});
return;
}

if (isFetchingSchemaInterface(schema)) {
const parsedFromUrl = await Parser.parseFromUrl(schema, parserOptions);
this.setState({
asyncapi: parsedFromUrl.asyncapi,
error: parsedFromUrl.error,
});
return;
}
this.setState({ asyncapi: parsedSpec });

const parsed = await Parser.parse(schema, parserOptions);
this.setState({
asyncapi: parsed.asyncapi,
error: parsed.error,
});
}
}

Expand Down
93 changes: 57 additions & 36 deletions library/src/helpers/parser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { Parser as AsyncapiParser, fromURL } from '@asyncapi/parser';
import {
Parser as AsyncapiParser,
Diagnostic,
DiagnosticSeverity,
fromURL,
} from '@asyncapi/parser';
import { OpenAPISchemaParser } from '@asyncapi/openapi-schema-parser';
import { ProtoBuffSchemaParser } from '@asyncapi/protobuf-schema-parser';
import { AvroSchemaParser } from '@asyncapi/avro-schema-parser';
Expand All @@ -20,47 +25,24 @@ asyncapiParser.registerSchemaParser(ProtoBuffSchemaParser());
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class Parser {
static async parse(
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents, @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
content: string | any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
parserOptions?: any,
): Promise<ParserReturn> {
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const parseResult = await asyncapiParser.parse(content, parserOptions);

const error: {
title: string | undefined;
validationErrors: ValidationError[] | undefined;
} = {
title: 'There are errors in your Asyncapi document',
validationErrors: [],
};
const { document, diagnostics } = await asyncapiParser.parse(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
content,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
parserOptions,
);

if (parseResult.document === undefined) {
parseResult.diagnostics.forEach((diagnostic) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (diagnostic.severity == 0) {
const tempObj: ValidationError = {
title: diagnostic.message,
location: {
jsonPointer: '/' + diagnostic.path.join('/'),
startLine: diagnostic.range.start.line,
startColumn: diagnostic.range.start.character,
// as of @asyncapi/parser 3.3.0 offset of 1 correctly shows the error line
startOffset: 1,
endLine: diagnostic.range.end.line,
endColumn: diagnostic.range.end.character,
endOffset: 0,
},
};
error.validationErrors?.push(tempObj);
}
});
throw error;
if (document === undefined) {
throw this.convertDiagnosticToErrorObject(diagnostics, [0]);
}

return { asyncapi: parseResult.document };
return { asyncapi: document };
} catch (err) {
return this.handleError(err as ErrorObject);
}
Expand All @@ -78,14 +60,53 @@ export class Parser {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
arg.requestOptions as any,
);

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const { document } = await fromResult.parse(parserOptions);
return { asyncapi: document };
const { document, diagnostics } = await fromResult.parse(parserOptions);

if (document == undefined) {
// this means there are errors in the document.
// so we gather all the severity 0 diagnostics and throw them as errors
throw this.convertDiagnosticToErrorObject(diagnostics, [0]);
}

return { asyncapi: document, error: undefined };
} catch (err) {
return this.handleError(err as ErrorObject);
}
}

static readonly convertDiagnosticToErrorObject = (
diagnostics: Diagnostic[],
severities: DiagnosticSeverity[],
): ErrorObject => {
const error: ErrorObject = {
title: 'There are errors in your Asyncapi document',
type: 'VALIDATION_ERRORS_TYPE',
validationErrors: [],
};
diagnostics.forEach((diagnostic) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (severities.includes(diagnostic.severity)) {
const tempObj: ValidationError = {
title: diagnostic.message,
location: {
jsonPointer: '/' + diagnostic.path.join('/'),
startLine: diagnostic.range.start.line,
startColumn: diagnostic.range.start.character,
// as of @asyncapi/parser 3.3.0 offset of 1 correctly shows the error line
startOffset: 1,
endLine: diagnostic.range.end.line,
endColumn: diagnostic.range.end.character,
endOffset: 0,
},
};
error.validationErrors?.push(tempObj);
}
});
return error;
};

private static handleError = (err: ErrorObject): ParserReturn => {
if (err.type === VALIDATION_ERRORS_TYPE) {
return {
Expand Down
4 changes: 2 additions & 2 deletions library/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import AsyncApiComponent from './containers/AsyncApi/AsyncApi';
import AsyncApiComponent from './containers/AsyncApi/Standalone';
import AsyncApiComponentWP from './containers/AsyncApi/Standalone';

export { AsyncApiProps } from './containers/AsyncApi/AsyncApi';
export { AsyncApiProps } from './containers/AsyncApi/Standalone';
export { ConfigInterface } from './config/config';
export { FetchingSchemaInterface } from './types';

Expand Down
2 changes: 1 addition & 1 deletion library/src/standalone.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import AsyncApiComponent, {
AsyncApiProps,
} from './containers/AsyncApi/AsyncApi';
} from './containers/AsyncApi/Standalone';

import { createRender, createHydrate } from './standalone-codebase';
import { hljs } from './helpers';
Expand Down
Loading