Skip to content

Commit 5427244

Browse files
smoyaderberg
authored andcommitted
refactor: interface and implementations for each major spec version (#488)
1 parent 24a6eea commit 5427244

28 files changed

+274
-118
lines changed

src/lint.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { asyncapi as aasRuleset } from "@stoplight/spectral-rulesets";
99

1010
import { toAsyncAPIDocument, normalizeInput, hasWarningDiagnostic, hasErrorDiagnostic } from "./utils";
1111

12-
import type { AsyncAPIDocument } from "./models/asyncapi";
12+
import type { AsyncAPIDocumentInterface } from "./models/asyncapi";
1313
import type { ParserInput, Diagnostic } from "./types";
1414

1515
export interface LintOptions extends IConstructorOpts, IRunOpts {
@@ -31,7 +31,7 @@ export async function lint(asyncapi: ParserInput, options?: LintOptions): Promis
3131
if (toAsyncAPIDocument(asyncapi)) {
3232
return;
3333
}
34-
const document = normalizeInput(asyncapi as Exclude<ParserInput, AsyncAPIDocument>);
34+
const document = normalizeInput(asyncapi as Exclude<ParserInput, AsyncAPIDocumentInterface>);
3535
return (await validate(document, options)).diagnostics;
3636
}
3737

src/models/asyncapi.ts

+21-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1+
import { InfoInterface } from "./info";
12
import { BaseModel } from "./base";
2-
import { Info } from "./info";
3+
import { AsyncAPIDocumentV2 } from "./v2";
4+
import { AsyncAPIDocumentV3 } from "./v3";
35

4-
export class AsyncAPIDocument extends BaseModel {
5-
version(): string {
6-
return this.json("asyncapi");
6+
export interface AsyncAPIDocumentInterface extends BaseModel {
7+
version(): string;
8+
info(): InfoInterface
9+
}
10+
11+
export function newAsyncAPIDocument(json: Record<string, any>): AsyncAPIDocumentInterface {
12+
const version = json['asyncapi']; // Maybe this should be an arg.
13+
if (version == undefined || version == null || version == '') {
14+
throw new Error('Missing AsyncAPI version in document');
715
}
816

9-
info(): Info {
10-
return new Info(this.json("info"));
17+
const major = version.split(".")[0];
18+
switch (major) {
19+
case '2':
20+
return new AsyncAPIDocumentV2(json);
21+
case '3':
22+
return new AsyncAPIDocumentV3(json);
23+
default:
24+
throw new Error(`Unsupported version: ${version}`);
1125
}
12-
}
26+
}

src/models/contact.ts

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
import { BaseModel } from "./base";
22

3-
export class Contact extends BaseModel {
4-
name(): string {
5-
return this.json("name");
6-
}
7-
8-
url(): string {
9-
return this.json("url");
10-
}
11-
12-
email(): string {
13-
return this.json("email");
14-
}
3+
export interface ContactInterface extends BaseModel {
4+
name(): string;
5+
url(): string;
6+
email(): string;
157
}

src/models/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
export * from './v2';
2+
export * from './v3';
13
export * from './asyncapi';
24
export * from './base';
3-
export * from './contact';
45
export * from './info';
5-
export * from './license';
6+
export * from './contact';
7+
export * from './license';

src/models/info.ts

+9-28
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,12 @@
1+
import { ContactInterface } from "./contact";
2+
import { LicenseInterface } from "./license";
13
import { BaseModel } from "./base";
2-
import { Contact } from "./contact";
3-
import { License } from "./license";
44

5-
export class Info extends BaseModel {
6-
title(): string {
7-
return this.json("title");
8-
}
9-
10-
version(): string {
11-
return this.json("version");
12-
}
13-
14-
description(): string {
15-
return this.json("description");
16-
}
17-
18-
termsOfService(): string {
19-
return this.json("termsOfService");
20-
}
21-
22-
contact(): Contact | undefined {
23-
const doc = this.json("contact");
24-
return doc && new Contact(doc);
25-
}
26-
27-
license(): License | undefined {
28-
const doc = this.json("license");
29-
return doc && new License(doc);
30-
}
5+
export interface InfoInterface extends BaseModel {
6+
title(): string;
7+
version(): string;
8+
description(): string;
9+
termsOfService(): string;
10+
contact(): ContactInterface | undefined;
11+
license(): LicenseInterface | undefined;
3112
}

src/models/license.ts

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import { BaseModel } from "./base";
22

3-
export class License extends BaseModel {
4-
name(): string {
5-
return this.json("name");
6-
}
7-
8-
url(): string {
9-
return this.json("url");
10-
}
3+
export interface LicenseInterface extends BaseModel {
4+
name(): string;
5+
url(): string;
116
}

src/models/v2/asyncapi.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { AsyncAPIDocumentInterface } from "../../models";
2+
import { BaseModel } from "../base";
3+
import { Info } from "./info";
4+
5+
export class AsyncAPIDocument extends BaseModel implements AsyncAPIDocumentInterface {
6+
version(): string {
7+
return this.json("asyncapi");
8+
}
9+
10+
info(): Info {
11+
return new Info(this.json("info"));
12+
}
13+
}

src/models/v2/contact.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ContactInterface } from "../../models/contact";
2+
import { BaseModel } from "../base";
3+
4+
export class Contact extends BaseModel implements ContactInterface {
5+
name(): string {
6+
return this.json("name");
7+
}
8+
9+
url(): string {
10+
return this.json("url");
11+
}
12+
13+
email(): string {
14+
return this.json("email");
15+
}
16+
}

src/models/v2/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { AsyncAPIDocument as AsyncAPIDocumentV2 } from './asyncapi';
2+
export { Contact as ContactV2 } from './contact';
3+
export { Info as InfoV2 } from './info';
4+
export { License as LicenseV2 } from './license';

src/models/v2/info.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { InfoInterface } from "../../models/info";
2+
import { BaseModel } from "../base";
3+
import { Contact } from "./contact";
4+
import { License } from "./license";
5+
6+
export class Info extends BaseModel implements InfoInterface {
7+
title(): string {
8+
return this.json("title");
9+
}
10+
11+
version(): string {
12+
return this.json("version");
13+
}
14+
15+
description(): string {
16+
return this.json("description");
17+
}
18+
19+
termsOfService(): string {
20+
return this.json("termsOfService");
21+
}
22+
23+
contact(): Contact | undefined {
24+
const doc = this.json("contact");
25+
return doc && new Contact(doc);
26+
}
27+
28+
license(): License | undefined {
29+
const doc = this.json("license");
30+
return doc && new License(doc);
31+
}
32+
}

src/models/v2/license.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { LicenseInterface } from "../../models/license";
2+
import { BaseModel } from "../base";
3+
4+
export class License extends BaseModel implements LicenseInterface {
5+
name(): string {
6+
return this.json("name");
7+
}
8+
9+
url(): string {
10+
return this.json("url");
11+
}
12+
}

src/models/v3/asyncapi.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { AsyncAPIDocumentInterface } from "../../models/asyncapi";
2+
import { BaseModel } from "../base";
3+
import { Info } from "./info";
4+
5+
export class AsyncAPIDocument extends BaseModel implements AsyncAPIDocumentInterface {
6+
version(): string {
7+
return this.json("asyncapi");
8+
}
9+
10+
info(): Info {
11+
return new Info(this.json("info"));
12+
}
13+
}

src/models/v3/contact.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ContactInterface } from "../../models/contact";
2+
import { BaseModel } from "../base";
3+
4+
export class Contact extends BaseModel implements ContactInterface {
5+
name(): string {
6+
return this.json("name");
7+
}
8+
9+
url(): string {
10+
return this.json("url");
11+
}
12+
13+
email(): string {
14+
return this.json("email");
15+
}
16+
}

src/models/v3/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { AsyncAPIDocument as AsyncAPIDocumentV3 } from './asyncapi';
2+
export { Contact as ContactV3 } from './contact';
3+
export { Info as InfoV3 } from './info';
4+
export { License as LicenseV3 } from './license';

src/models/v3/info.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { InfoInterface } from "../../models/info";
2+
import { BaseModel } from "../base";
3+
import { Contact } from "./contact";
4+
import { License } from "./license";
5+
6+
export class Info extends BaseModel implements InfoInterface {
7+
title(): string {
8+
return this.json("title");
9+
}
10+
11+
version(): string {
12+
return this.json("version");
13+
}
14+
15+
description(): string {
16+
return this.json("description");
17+
}
18+
19+
termsOfService(): string {
20+
return this.json("termsOfService");
21+
}
22+
23+
contact(): Contact | undefined {
24+
const doc = this.json("contact");
25+
return doc && new Contact(doc);
26+
}
27+
28+
license(): License | undefined {
29+
const doc = this.json("license");
30+
return doc && new License(doc);
31+
}
32+
}

src/models/v3/license.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { LicenseInterface } from "../../models/license";
2+
import { BaseModel } from "../base";
3+
4+
export class License extends BaseModel implements LicenseInterface {
5+
name(): string {
6+
return this.json("name");
7+
}
8+
9+
url(): string {
10+
return this.json("url");
11+
}
12+
}

src/parse.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AsyncAPIDocument } from "./models";
1+
import { AsyncAPIDocumentInterface, newAsyncAPIDocument } from "./models";
22
import { normalizeInput, toAsyncAPIDocument } from "./utils";
33
import { validate } from "./lint";
44

@@ -21,7 +21,7 @@ export async function parse(asyncapi: ParserInput, options?: ParseOptions): Prom
2121
}
2222

2323
try {
24-
const document = normalizeInput(asyncapi as Exclude<ParserInput, AsyncAPIDocument>);
24+
const document = normalizeInput(asyncapi as Exclude<ParserInput, AsyncAPIDocumentInterface>);
2525
options = normalizeOptions(options);
2626

2727
const { validated, diagnostics } = await validate(document, options.validateOptions);
@@ -33,7 +33,7 @@ export async function parse(asyncapi: ParserInput, options?: ParseOptions): Prom
3333
};
3434
}
3535

36-
const parsed = new AsyncAPIDocument(validated as Record<string, unknown>);
36+
const parsed = newAsyncAPIDocument(validated as Record<string, unknown>);
3737
return {
3838
source: asyncapi,
3939
parsed,

src/stringify.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AsyncAPIDocument } from './models';
1+
import { AsyncAPIDocumentInterface, newAsyncAPIDocument } from './models';
22

33
import { isAsyncAPIDocument, isParsedDocument, isStringifiedDocument } from './utils';
44
import { xParserSpecStringified } from './constants';
@@ -25,7 +25,7 @@ export function stringify(document: unknown, options: StringifyOptions = {}): st
2525
}, refReplacer(), options.space || 2);
2626
}
2727

28-
export function unstringify(document: unknown): AsyncAPIDocument | undefined {
28+
export function unstringify(document: unknown): AsyncAPIDocumentInterface | undefined {
2929
if (!isStringifiedDocument(document)) {
3030
return;
3131
}
@@ -36,7 +36,7 @@ export function unstringify(document: unknown): AsyncAPIDocument | undefined {
3636
delete (<Record<string, any>>document)[String(xParserSpecStringified)];
3737

3838
traverseStringifiedDoc(document, undefined, document, new Map(), new Map());
39-
return new AsyncAPIDocument(<Record<string, any>>document);
39+
return newAsyncAPIDocument(<Record<string, any>>document);
4040
}
4141

4242
function refReplacer() {

src/types.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { ISpectralDiagnostic } from '@stoplight/spectral-core';
2-
import type { AsyncAPIDocument } from './models/asyncapi';
2+
import type { AsyncAPIDocumentInterface } from './models/asyncapi';
33

44
export type MaybeAsyncAPI = { asyncapi: unknown } & Record<string, unknown>;
5-
export type ParserInput = string | MaybeAsyncAPI | AsyncAPIDocument;
5+
export type ParserInput = string | MaybeAsyncAPI | AsyncAPIDocumentInterface;
66

77
export type Diagnostic = ISpectralDiagnostic;
88

99
export interface ParserOutput {
1010
source: ParserInput;
11-
parsed: AsyncAPIDocument | undefined;
11+
parsed: AsyncAPIDocumentInterface | undefined;
1212
diagnostics: Diagnostic[];
1313
}

0 commit comments

Comments
 (0)