Skip to content

Commit

Permalink
fix: doc.allSchemas() skips now duplicates
Browse files Browse the repository at this point in the history
  • Loading branch information
smoya committed Nov 14, 2023
1 parent 0a765c1 commit fed37d6
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 43 deletions.
25 changes: 25 additions & 0 deletions src/models/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { BaseModel, ModelMetadata } from './base';
import type { DetailedAsyncAPI } from '../types';
import { SchemaInterface } from './schema';
import { SchemaTypesToIterate, traverseAsyncApiDocument } from '../iterator';
import { AsyncAPIDocumentInterface } from './asyncapi';
import { SchemasInterface } from 'models';

export interface Constructor<T> extends Function {
new (...any: any[]): T;
Expand All @@ -12,3 +16,24 @@ export type InferModelMetadata<T> = T extends BaseModel<infer _, infer M> ? M :
export function createModel<T extends BaseModel>(Model: Constructor<T>, value: InferModelData<T>, meta: Omit<ModelMetadata, 'asyncapi'> & { asyncapi?: DetailedAsyncAPI } & InferModelMetadata<T>, parent?: BaseModel): T {
return new Model(value, { ...meta, asyncapi: meta.asyncapi || parent?.meta().asyncapi });
}

export function schemasFromDocument<T extends SchemasInterface>(document: AsyncAPIDocumentInterface, SchemasModel: Constructor<T>, includeComponents: boolean): T {
const jsonInstances: Set<any> = new Set();
const schemas: Set<SchemaInterface> = new Set();

function callback(schema: SchemaInterface) {
// comparing the reference (and not just the value) to the .json() object
if (!jsonInstances.has(schema.json())) {
jsonInstances.add(schema.json());
schemas.add(schema); // unique schemas
}
}

let toIterate = Object.values(SchemaTypesToIterate);
if (!includeComponents) {
toIterate = toIterate.filter(s => s !== SchemaTypesToIterate.Components);
}
traverseAsyncApiDocument(document, callback, toIterate);

return new SchemasModel(Array.from(schemas));
}
22 changes: 3 additions & 19 deletions src/models/v2/asyncapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { SecurityScheme } from './security-scheme';
import { Schemas } from './schemas';

import { extensions } from './mixins';
import { traverseAsyncApiDocument, SchemaTypesToIterate } from '../../iterator';
import { tilde } from '../../utils';
import { schemasFromDocument } from '../utils';

import type { AsyncAPIDocumentInterface } from '../asyncapi';
import type { InfoInterface } from '../info';
Expand Down Expand Up @@ -81,7 +81,7 @@ export class AsyncAPIDocument extends BaseModel<v2.AsyncAPIObject> implements As
}

schemas(): SchemasInterface {
return this.__schemas(false);
return schemasFromDocument(this, Schemas, false);
}

securitySchemes(): SecuritySchemesInterface {
Expand Down Expand Up @@ -130,26 +130,10 @@ export class AsyncAPIDocument extends BaseModel<v2.AsyncAPIObject> implements As
}

allSchemas(): SchemasInterface {
return this.__schemas(true);
return schemasFromDocument(this, Schemas, true);
}

extensions(): ExtensionsInterface {
return extensions(this);
}

private __schemas(withComponents: boolean) {
const schemas: Set<SchemaInterface> = new Set();
function callback(schema: SchemaInterface) {
if (!schemas.has(schema.json())) {
schemas.add(schema);
}
}

let toIterate = Object.values(SchemaTypesToIterate);
if (!withComponents) {
toIterate = toIterate.filter(s => s !== SchemaTypesToIterate.Components);
}
traverseAsyncApiDocument(this, callback, toIterate);
return new Schemas(Array.from(schemas));
}
}
32 changes: 8 additions & 24 deletions src/models/v3/asyncapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Schemas } from './schemas';

import { extensions } from './mixins';
import { tilde } from '../../utils';
import { SchemaTypesToIterate, traverseAsyncApiDocument } from '../../iterator';
import { schemasFromDocument } from '../utils';

import type { AsyncAPIDocumentInterface } from '../asyncapi';
import type { InfoInterface } from '../info';
Expand All @@ -26,12 +26,12 @@ import type { MessageInterface } from '../message';
import type { ComponentsInterface } from '../components';
import type { SecuritySchemesInterface } from '../security-schemes';
import type { ExtensionsInterface } from '../extensions';
import type { SchemaInterface } from '../schema';
import type { SchemasInterface } from '../schemas';
import type { OperationInterface } from '../operation';
import type { ChannelInterface } from '../channel';
import type { ServerInterface } from '../server';

import type { v3 } from '../../spec-types';
import { OperationInterface } from '../operation';
import { ChannelInterface } from '../channel';
import { ServerInterface } from '../server';

export class AsyncAPIDocument extends BaseModel<v3.AsyncAPIObject> implements AsyncAPIDocumentInterface {
version(): string {
Expand Down Expand Up @@ -89,8 +89,8 @@ export class AsyncAPIDocument extends BaseModel<v3.AsyncAPIObject> implements As
return new Messages(messages);
}

schemas() {
return this.__schemas(false);
schemas(): SchemasInterface {
return schemasFromDocument(this, Schemas, false);
}

securitySchemes(): SecuritySchemesInterface {
Expand Down Expand Up @@ -138,26 +138,10 @@ export class AsyncAPIDocument extends BaseModel<v3.AsyncAPIObject> implements As
}

allSchemas(): SchemasInterface {
return this.__schemas(true);
return schemasFromDocument(this, Schemas, true);
}

extensions(): ExtensionsInterface {
return extensions(this);
}

private __schemas(withComponents: boolean) {
const schemas: Set<SchemaInterface> = new Set();
function callback(schema: SchemaInterface) {
if (!schemas.has(schema.json())) {
schemas.add(schema);
}
}

let toIterate = Object.values(SchemaTypesToIterate);
if (!withComponents) {
toIterate = toIterate.filter(s => s !== SchemaTypesToIterate.Components);
}
traverseAsyncApiDocument(this, callback, toIterate);
return new Schemas(Array.from(schemas));
}
}
8 changes: 8 additions & 0 deletions test/models/v2/asyncapi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,14 @@ describe('AsyncAPIDocument model', function() {
const d = new AsyncAPIDocument(doc);
expect(d.allSchemas()).toBeInstanceOf(Schemas);
});

it('should return a collection of schemas (with schemas from components) without duplicates', function() {
const sharedMessage = { payload: {} };
const doc = serializeInput<v2.AsyncAPIObject>({ channels: { 'user/signup': { publish: { message: sharedMessage }, subscribe: { message: { oneOf: [{ payload: {} }, {}] } } }, 'user/logout': { publish: { message: { payload: {} } } } }, components: { messages: { aMessage: sharedMessage } } });
const d = new AsyncAPIDocument(doc);
expect(d.allSchemas()).toBeInstanceOf(Schemas);
expect(d.allSchemas()).toHaveLength(3);
});
});

describe('mixins', function() {
Expand Down
7 changes: 7 additions & 0 deletions test/models/v3/asyncapi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ describe('AsyncAPIDocument model', function() {
const d = new AsyncAPIDocument(doc);
expect(d.allSchemas()).toBeInstanceOf(Schemas);
});
it('should return a collection of schemas (with schemas from components) without duplicates', function() {
const sharedMessage = { payload: {} };
const doc = serializeInput<v3.AsyncAPIObject>({ channels: { userSignup: { address: 'user/signup', messages: { someMessage1: { payload: {}}, someMessage2: sharedMessage } } }, components: { messages: { aMessage: sharedMessage } } });
const d = new AsyncAPIDocument(doc);
expect(d.allSchemas()).toBeInstanceOf(Schemas);
expect(d.allSchemas()).toHaveLength(2);
});
});

describe('.allServers()', function() {
Expand Down

0 comments on commit fed37d6

Please sign in to comment.