@@ -31,6 +31,7 @@ import { Specification } from '@models/SpecificationFile';
3131import { ParseOptions } from '@asyncapi/parser' ;
3232import { ParserOptions } from '@asyncapi/parser/cjs/parser' ;
3333import { calculateScore } from '@/utils/scoreCalculator' ;
34+ import { Type as AvroType } from 'avsc' ;
3435
3536import { ConfigService } from './config.service' ;
3637
@@ -282,11 +283,66 @@ export class ValidationService extends BaseService {
282283 } ,
283284 ) ;
284285
285- const status = this . determineDiagnosticsStatus ( diagnostics , options ) ;
286+ // Additional diagnostics for Avro payload schemas using avsc
287+ const extraDiagnostics : Diagnostic [ ] = [ ] ;
288+ try {
289+ const docJson : any = document ?. json ? document . json ( ) : undefined ;
290+ if ( docJson && docJson . components && docJson . components . messages ) {
291+ const messages = docJson . components . messages as Record < string , any > ;
292+ for ( const [ msgKey , msgVal ] of Object . entries ( messages ) ) {
293+ const payload = ( msgVal as any ) ?. payload ;
294+ if ( ! payload || typeof payload !== 'object' ) {
295+ continue ;
296+ }
297+ const schemaFormat : string | undefined = payload . schemaFormat || payload . schemaformat ;
298+ if ( ! schemaFormat || typeof schemaFormat !== 'string' ) {
299+ continue ;
300+ }
301+ const isAvro = ( / a p p l i c a t i o n \/ v n d \. a p a c h e \. a v r o \+ ( j s o n | y a m l ) / i) . test ( schemaFormat ) ;
302+ if ( ! isAvro ) {
303+ continue ;
304+ }
305+
306+ const avroSchema = ( payload as any ) . schema ;
307+ if ( ! avroSchema || typeof avroSchema !== 'object' ) {
308+ extraDiagnostics . push ( {
309+ code : 'avro-schema-missing' ,
310+ message : 'Avro payload has schemaFormat set to Avro but no schema provided.' ,
311+ path : [ 'components' , 'messages' , msgKey , 'payload' , 'schema' ] ,
312+ severity : DiagnosticSeverity . Error ,
313+ range : {
314+ start : { line : 0 , character : 0 } ,
315+ end : { line : 0 , character : 0 } ,
316+ } ,
317+ } as unknown as Diagnostic ) ;
318+ continue ;
319+ }
320+ try {
321+ AvroType . forSchema ( avroSchema as any ) ;
322+ } catch ( e : any ) {
323+ extraDiagnostics . push ( {
324+ code : 'avro-schema-invalid' ,
325+ message : e ?. message || 'Invalid Avro schema.' ,
326+ path : [ 'components' , 'messages' , msgKey , 'payload' , 'schema' ] ,
327+ severity : DiagnosticSeverity . Error ,
328+ range : {
329+ start : { line : 0 , character : 0 } ,
330+ end : { line : 0 , character : 0 } ,
331+ } ,
332+ } as unknown as Diagnostic ) ;
333+ }
334+ }
335+ }
336+ } catch {
337+ //Outer catch block will handle the error
338+ }
339+
340+ const allDiagnostics = [ ...diagnostics , ...extraDiagnostics ] ;
341+ const status = this . determineDiagnosticsStatus ( allDiagnostics , options ) ;
286342
287343 const result : ValidationResult = {
288344 status : status as 'valid' | 'invalid' ,
289- diagnostics,
345+ diagnostics : allDiagnostics ,
290346 score : await calculateScore ( document ) ,
291347 document : document ?. json ? document . json ( ) : undefined ,
292348 } ;
0 commit comments