Skip to content

Commit

Permalink
Revert "fix schema parsing"
Browse files Browse the repository at this point in the history
This reverts commit 0501206.
  • Loading branch information
jonaslagoni committed Oct 6, 2023
1 parent a295e76 commit 08c9751
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 94 deletions.
9 changes: 3 additions & 6 deletions src/custom-operations/anonymous-naming.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { xParserMessageName, xParserSchemaId } from '../constants';
import { traverseAsyncApiDocument } from '../iterator';
import { setExtension, setExtensionOnJson } from '../utils';
import { setExtension } from '../utils';

import type {
AsyncAPIDocumentInterface,
Expand Down Expand Up @@ -59,15 +59,12 @@ function assignUidToComponentSchemas(document: AsyncAPIDocumentInterface) {
setExtension(xParserSchemaId, schema.id(), schema);
});
}

function assignUidToAnonymousSchemas(doc: AsyncAPIDocumentInterface) {
let anonymousSchemaCounter = 0;
function callback(schema: SchemaInterface) {
const json = schema.json() as any;
const isMultiFormatSchema = json.schema !== undefined;
const underlyingSchema = isMultiFormatSchema ? json.schema : json;
if (!schema.id()) {
setExtensionOnJson(xParserSchemaId, `<anonymous-schema-${++anonymousSchemaCounter}>`, underlyingSchema);
setExtension(xParserSchemaId, `<anonymous-schema-${++anonymousSchemaCounter}>`, schema);
}
}
traverseAsyncApiDocument(doc, callback);
Expand Down
19 changes: 8 additions & 11 deletions src/custom-operations/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { applyTraitsV2, applyTraitsV3 } from './apply-traits';
import { resolveCircularRefs } from './resolve-circular-refs';
import { parseSchemasV2, parseSchemasV3 } from './parse-schema';
import { checkCircularRefs } from './check-circular-refs';
import { parseSchemasV2 } from './parse-schema';
import { anonymousNaming } from './anonymous-naming';
import { resolveCircularRefs } from './resolve-circular-refs';

import type { RulesetFunctionContext } from '@stoplight/spectral-core';
import type { Parser } from '../parser';
import type { ParseOptions } from '../parse';
import type { AsyncAPIDocumentInterface } from '../models';
import type { DetailedAsyncAPI } from '../types';
import type { v2, v3 } from '../spec-types';
import { checkCircularRefs } from './check-circular-refs';

export async function customOperations(parser: Parser, document: AsyncAPIDocumentInterface, detailed: DetailedAsyncAPI, inventory: RulesetFunctionContext['documentInventory'], options: ParseOptions): Promise<void> {
switch (detailed.semver.major) {
Expand All @@ -28,7 +28,7 @@ async function operationsV2(parser: Parser, document: AsyncAPIDocumentInterface,
await parseSchemasV2(parser, detailed);
}

// anonymous naming and resolving circular references should be done after custom schemas parsing
// anonymous naming and resolving circular refrences should be done after custom schemas parsing
if (inventory) {
resolveCircularRefs(document, inventory);
}
Expand All @@ -41,12 +41,9 @@ async function operationsV3(parser: Parser, document: AsyncAPIDocumentInterface,
if (options.applyTraits) {
applyTraitsV3(detailed.parsed as v3.AsyncAPIObject);
}
if (options.parseSchemas) {
await parseSchemasV3(parser, detailed);
}
// anonymous naming and resolving circular references should be done after custom schemas parsing
if (inventory) {
resolveCircularRefs(document, inventory);
}
// TODO: Support schema parsing in v3
// if (options.parseSchemas) {
// await parseSchemasV2(parser, detailed);
// }
anonymousNaming(document);
}
70 changes: 0 additions & 70 deletions src/custom-operations/parse-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@ const customSchemasPathsV2 = [
'$.components.messages.*',
];

const customSchemasPathsV3 = [
// operations
'$.channels.*.messages.*.payload',
'$.components.channels.*.messages.*.payload',
'$.components.messages.*.payload',
'$.components.schemas.*',
];

export async function parseSchemasV2(parser: Parser, detailed: DetailedAsyncAPI) {
const defaultSchemaFormat = getDefaultSchemaFormat(detailed.semver.version);
const parseItems: Array<ToParseItem> = [];
Expand Down Expand Up @@ -73,68 +65,6 @@ export async function parseSchemasV2(parser: Parser, detailed: DetailedAsyncAPI)
return Promise.all(parseItems.map(item => parseSchemaV2(parser, item)));
}

export async function parseSchemasV3(parser: Parser, detailed: DetailedAsyncAPI) {
const defaultSchemaFormat = getDefaultSchemaFormat(detailed.semver.version);
const parseItems: Array<ToParseItem> = [];

const visited: Set<unknown> = new Set();
customSchemasPathsV3.forEach(path => {
JSONPath({
path,
json: detailed.parsed,
resultType: 'all',
callback(result) {
const value = result.value;
if (visited.has(value)) {
return;
}
visited.add(value);

const schema = value.schema;
if (!schema) {
return;
}

let schemaFormat = value.schemaFormat;
if (!schemaFormat) {
return;
}
schemaFormat = getSchemaFormat(value.schemaFormat, detailed.semver.version);

parseItems.push({
input: {
asyncapi: detailed,
data: schema,
meta: {
message: value,
},
path: [...splitPath(result.path), 'schema'],
schemaFormat,
defaultSchemaFormat,
},
value,
});
},
});
});

return Promise.all(parseItems.map(item => parseSchemaV3(parser, item)));
}

async function parseSchemaV3(parser: Parser, item: ToParseItem) {
const originalData = item.input.data;
const parsedData = await parseSchema(parser, item.input);
if (item.value?.schema !== undefined) {
item.value.schema = parsedData;
} else {
item.value = parsedData;
}
// save original payload only when data is different (returned by custom parsers)
if (originalData !== parsedData) {
item.value[xParserOriginalPayload] = originalData;
}
}

async function parseSchemaV2(parser: Parser, item: ToParseItem) {
const originalData = item.input.data;
const parsedData = item.value.payload = await parseSchema(parser, item.input);
Expand Down
2 changes: 1 addition & 1 deletion src/models/v3/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class Schema extends BaseModel<v3.MultiFormatSchemaObject, { id?: string,

$schema(): string {
if (typeof this._schemaObject === 'boolean') return 'http://json-schema.org/draft-07/schema#';
return this._schemaObject.$schema ?? 'http://json-schema.org/draft-07/schema#';
return this._schemaObject.$schema || 'http://json-schema.org/draft-07/schema#';
}

additionalItems(): boolean | SchemaInterface {
Expand Down
8 changes: 2 additions & 6 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,9 @@ export function hasHintDiagnostic(diagnostics: ISpectralDiagnostic[]): boolean {

export function setExtension(id: string, value: unknown, model: BaseModel): void {
const modelValue = model.json();
setExtensionOnJson(id, value, modelValue);
}

export function setExtensionOnJson(id: string, value: unknown, model: any): void {
if (typeof model === 'object' && model) {
if (typeof modelValue === 'object' && modelValue) {
id = id.startsWith('x-') ? id : `x-${id}`;
model[String(id)] = value;
modelValue[String(id)] = value;
}
}

Expand Down
130 changes: 130 additions & 0 deletions test/custom-operations/parse-schema.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { AsyncAPIDocumentV2 } from '../../src/models';
import { Parser } from '../../src/parser';

import type { v2 } from '../../src/spec-types';

describe('custom operations - parse schemas', function() {
const parser = new Parser();

it('should parse valid schema format', async function() {
const documentRaw = {
asyncapi: '2.0.0',
info: {
title: 'Valid AsyncApi document',
version: '1.0',
},
channels: {
channel: {
publish: {
operationId: 'operationId',
message: {
schemaFormat: 'application/vnd.aai.asyncapi;version=2.0.0',
payload: {
type: 'object',
}
}
}
}
}
};
const { document, diagnostics } = await parser.parse(documentRaw);

expect(document).toBeInstanceOf(AsyncAPIDocumentV2);
expect(diagnostics.length > 0).toEqual(true);

expect((document?.json()?.channels?.channel?.publish?.message as v2.MessageObject)?.payload).toEqual({ type: 'object', 'x-parser-schema-id': '<anonymous-schema-1>' });
});

it('should parse valid default schema format', async function() {
const documentRaw = {
asyncapi: '2.0.0',
info: {
title: 'Valid AsyncApi document',
version: '1.0',
},
channels: {
channel: {
publish: {
operationId: 'operationId',
message: {
payload: {
type: 'object',
}
}
}
}
}
};
const { document, diagnostics } = await parser.parse(documentRaw);

expect(document).toBeInstanceOf(AsyncAPIDocumentV2);
expect(diagnostics.length > 0).toEqual(true);

expect((document?.json()?.channels?.channel?.publish?.message as v2.MessageObject)?.payload).toEqual({ type: 'object', 'x-parser-schema-id': '<anonymous-schema-1>' });
});

it('should preserve this same references', async function() {
const documentRaw = {
asyncapi: '2.0.0',
info: {
title: 'Valid AsyncApi document',
version: '1.0',
},
channels: {
channel: {
publish: {
operationId: 'operationId',
message: {
$ref: '#/components/messages/message'
}
}
}
},
components: {
messages: {
message: {
payload: {
type: 'object',
}
}
}
}
};
const { document, diagnostics } = await parser.parse(documentRaw);

expect(document).toBeInstanceOf(AsyncAPIDocumentV2);
expect(diagnostics.length > 0).toEqual(true);

expect((document?.json()?.channels?.channel?.publish?.message as v2.MessageObject)?.payload).toEqual({ type: 'object', 'x-parser-schema-id': '<anonymous-schema-1>' });
expect((document?.json().components?.messages?.message as v2.MessageObject)?.payload).toEqual({ type: 'object', 'x-parser-schema-id': '<anonymous-schema-1>' });
// check if logic preserves references
expect((document?.json()?.channels?.channel?.publish?.message as v2.MessageObject)?.payload === (document?.json().components?.messages?.message as v2.MessageObject)?.payload).toEqual(true);
});

it('should parse invalid schema format', async function() {
const documentRaw = {
asyncapi: '2.0.0',
info: {
title: 'Valid AsyncApi document',
version: '1.0',
},
channels: {
channel: {
publish: {
operationId: 'operationId',
message: {
schemaFormat: 'not existing',
payload: {
type: 'object',
}
}
}
}
}
};
const { document, diagnostics } = await parser.parse(documentRaw);

expect(document).toBeUndefined();
expect(diagnostics.length > 0).toEqual(true);
});
});

0 comments on commit 08c9751

Please sign in to comment.