Skip to content

Commit

Permalink
allow Channel instead of reference for operation.channel in order to …
Browse files Browse the repository at this point in the history
…validate
  • Loading branch information
smoya committed Aug 4, 2023
1 parent 7b4d21c commit 37c28bf
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 11 deletions.
4 changes: 4 additions & 0 deletions src/ruleset/formats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export class Formats extends Map<string, Format> {
return new Formats([...this.entries()].filter(element => {return majorsToInclude.includes(element[0].split('.')[0]);}));
}

excludeByMajorVersions(versionsToExclude: string[]): Formats {
return new Formats([...this.entries()].filter(element => {return !versionsToExclude.includes(element[0].split('.')[0]);}));
}

excludeByVersions(versionsToExclude: string[]): Formats {
return new Formats([...this.entries()].filter(element => {return !versionsToExclude.includes(element[0]);}));
}
Expand Down
26 changes: 17 additions & 9 deletions src/ruleset/functions/documentStructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { schema as schemaFn } from '@stoplight/spectral-functions';
import type { ErrorObject } from 'ajv';
import type { IFunctionResult, Format } from '@stoplight/spectral-core';
import { AsyncAPIFormats } from '../formats';
import { getSemver } from '../../utils';

type AsyncAPIVersions = keyof typeof specs.schemas;
type RawSchema = Record<string, unknown>;

function shouldIgnoreError(error: ErrorObject): boolean {
return (
Expand Down Expand Up @@ -45,23 +47,28 @@ function prepareResults(errors: ErrorObject[]): void {
}
}

function getCopyOfSchema(version: AsyncAPIVersions): Record<string, unknown> {
return JSON.parse(JSON.stringify(specs.schemas[version])) as Record<string, unknown>;
function getCopyOfSchema(version: AsyncAPIVersions): RawSchema {
return JSON.parse(JSON.stringify(specs.schemas[version])) as RawSchema;
}

const serializedSchemas = new Map<AsyncAPIVersions, Record<string, unknown>>();
function getSerializedSchema(version: AsyncAPIVersions): Record<string, unknown> {
const serializedSchemas = new Map<AsyncAPIVersions, RawSchema>();
function getSerializedSchema(version: AsyncAPIVersions, schemaTransformers: SchemaTransformers): RawSchema {
const schema = serializedSchemas.get(version);
if (schema) {
return schema;
}

// Copy to not operate on the original json schema - between imports (in different modules) we operate on this same schema.
const copied = getCopyOfSchema(version) as { definitions: Record<string, unknown> };
const copied = getCopyOfSchema(version) as { definitions: RawSchema };
// Remove the meta schemas because they are already present within Ajv, and it's not possible to add duplicated schemas.
delete copied.definitions['http://json-schema.org/draft-07/schema'];
delete copied.definitions['http://json-schema.org/draft-04/schema'];

const transformer = schemaTransformers[version] || schemaTransformers[String(getSemver(version).major)];
if (transformer) {
transformer(copied);
}

serializedSchemas.set(version, copied);
return copied;
}
Expand All @@ -79,16 +86,17 @@ function filterRefErrors(errors: IFunctionResult[], resolved: boolean) {
return err;
});
}
type SchemaTransformers = Record<string, (schema: RawSchema) => void>

export function getSchema(docFormats: Set<Format>): Record<string, any> | void {
export function getSchema(docFormats: Set<Format>, schemaTransformers: SchemaTransformers): Record<string, any> | void {
for (const [version, format] of AsyncAPIFormats) {
if (docFormats.has(format)) {
return getSerializedSchema(version as AsyncAPIVersions);
return getSerializedSchema(version as AsyncAPIVersions, schemaTransformers);
}
}
}

export const documentStructure = createRulesetFunction<unknown, { resolved: boolean }>(
export const documentStructure = createRulesetFunction<unknown, { resolved: boolean, schemaTransformers: SchemaTransformers}>(
{
input: null,
options: {
Expand All @@ -107,7 +115,7 @@ export const documentStructure = createRulesetFunction<unknown, { resolved: bool
return;
}

const schema = getSchema(formats);
const schema = getSchema(formats, options.schemaTransformers);
if (!schema) {
return;
}
Expand Down
5 changes: 5 additions & 0 deletions src/ruleset/ruleset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export const coreRuleset = {
function: documentStructure,
functionOptions: {
resolved: true,
schemaTransformers: {
3: (schema: Record<string, unknown>) =>
(schema as { definitions: Record<string, any> }).definitions['http://asyncapi.com/definitions/3.0.0/operation.json'].properties.channel.$ref = 'http://asyncapi.com/definitions/3.0.0/channel.json'

},
},
},
},
Expand Down
4 changes: 2 additions & 2 deletions test/custom-operations/apply-traits-v3.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ describe('custom operations - apply traits v3', function() {

const someOperation1 = v3Document?.json()?.operations?.someOperation1;
delete someOperation1?.traits;
expect(someOperation1).toEqual({ description: 'another description' });
expect(someOperation1).toEqual({ action: 'send', channel: {}, description: 'another description' });

const someOperation2 = v3Document?.json()?.operations?.someOperation2;
delete someOperation2?.traits;
expect(someOperation2).toEqual({ description: 'root description' });
expect(someOperation2).toEqual({ action: 'send', channel: {}, description: 'root description' });
});

it('should apply traits to messages (channels)', async function() {
Expand Down
11 changes: 11 additions & 0 deletions test/ruleset/formats.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,15 @@ describe('AsyncAPIFormats collection', () => {
expect(filteredFormats.find(version)).toBeFalsy();
});
});

it('Excludes by major version', () => {
const excludedMajorVersions = ['3'];
const previousLenght = AsyncAPIFormats.formats().length;
const filteredFormats = AsyncAPIFormats.excludeByMajorVersions(excludedMajorVersions);

expect(filteredFormats.size).toEqual(previousLenght - excludedMajorVersions.length);
filteredFormats.forEach((_, version) => {
expect(excludedMajorVersions).not.toContain(String(getSemver(version).major));
});
});
});

0 comments on commit 37c28bf

Please sign in to comment.