Skip to content

Commit

Permalink
Merge pull request #10 from samchon/features/plugin
Browse files Browse the repository at this point in the history
Fix and enhance `OpenApi` types.
  • Loading branch information
samchon authored Apr 14, 2024
2 parents 09cdbad + 3a541e8 commit cf36269
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 95 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@samchon/openapi",
"version": "0.1.8",
"version": "0.1.13",
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.",
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
Expand Down
37 changes: 23 additions & 14 deletions src/OpenApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { SwaggerV2Converter } from "./internal/SwaggerV2Converter";
* Here is the entire list of differences between OpenAPI v3.1 and emended `OpenApi`.
*
* - Operation
* - Merged {@link OpenApiV3_1.IPathItem.parameters} to {@link OpenApi.IOperation.parameters}
* - Merged {@link OpenApiV3_1.IPath.parameters} to {@link OpenApi.IOperation.parameters}
* - Resolved {@link OpenApi.IJsonSchema.IReference references} of {@link OpenApiV3_1.IOperation} mebers
* - JSON Schema
* - Decomposed mixed type: {@link OpenApiV3_1.IJsonSchema.IMixed}
Expand Down Expand Up @@ -75,10 +75,10 @@ export namespace OpenApi {
servers?: IServer[];
info?: IDocument.IInfo;
components: IComponents;
paths?: Record<string, IPathItem>;
paths?: Record<string, IPath>;
webhooks?: Record<
string,
IJsonSchema.IReference<`#/components/pathItems/${string}`> | IPathItem
IJsonSchema.IReference<`#/components/pathItems/${string}`> | IPath
>;
security?: Record<string, string[]>[];
tags?: IDocument.ITag[];
Expand Down Expand Up @@ -126,18 +126,16 @@ export namespace OpenApi {
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
export type IPathItem = {
export type IPath = {
servers?: IServer[];
summary?: string;
description?: string;
} & Partial<Record<Method, IOperation>>;

export interface IOperation {
operationId?: string;
parameters: Array<IOperation.IParameter>;
requestBody?:
| IOperation.IRequestBody
| IJsonSchema.IReference<`#/components/requestBodies/${string}`>;
parameters?: IOperation.IParameter[];
requestBody?: IOperation.IRequestBody;
responses?: Record<string, IOperation.IResponse>;
servers?: IServer[];
summary?: string;
Expand All @@ -152,28 +150,40 @@ export namespace OpenApi {
in: "path" | "query" | "header" | "cookie";
schema: IJsonSchema;
required?: boolean;
title?: string;
description?: string;
}
export interface IRequestBody {
description?: string;
required?: boolean;
content?: Record<string, IMediaType>;
content?: IContent;
"x-nestia-encrypted"?: boolean;
}
export interface IResponse {
content?: Record<string, IMediaType>;
content?: IContent;
headers?: Record<string, IOperation.IParameter>;
description?: string;
"x-nestia-encrypted"?: boolean;
}

export type IContent = Partial<Record<ContentType, IMediaType>>;
export interface IMediaType {
schema?: IJsonSchema;
}
export type ContentType =
| "text/plain"
| "application/json"
| "application/x-www-form-url-encoded"
| "multipart/form-data"
| "*/*"
| (string & {});
}

/* -----------------------------------------------------------
SCHEMA DEFINITIONS
----------------------------------------------------------- */
export interface IComponents {
schemas: Record<string, IJsonSchema>;
schemas?: Record<string, IJsonSchema>;
securitySchemes?: Record<string, ISecurityScheme>;
}

Expand Down Expand Up @@ -201,8 +211,8 @@ export namespace OpenApi {
/** @type int */ default?: number;
/** @type int */ minimum?: number;
/** @type int */ maximum?: number;
/** @type int */ exclusiveMinimum?: boolean;
/** @type int */ exclusiveMaximum?: boolean;
exclusiveMinimum?: boolean;
exclusiveMaximum?: boolean;
/** @type uint */ multipleOf?: number;
}
export interface INumber extends __ISignificant<"number"> {
Expand All @@ -216,7 +226,6 @@ export namespace OpenApi {
export interface IString extends __ISignificant<"string"> {
contentMediaType?: string;
default?: string;
enum?: string[];
format?:
| "binary"
| "byte"
Expand Down
8 changes: 4 additions & 4 deletions src/OpenApiV3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export namespace OpenApiV3 {
servers?: IServer[];
info?: IDocument.IInfo;
components?: IComponents;
paths?: Record<string, IPathItem>;
paths?: Record<string, IPath>;
security?: Record<string, string[]>[];
tags?: IDocument.ITag[];
}
Expand Down Expand Up @@ -75,7 +75,7 @@ export namespace OpenApiV3 {
/* -----------------------------------------------------------
PATH ITEMS
----------------------------------------------------------- */
export type IPathItem = {
export type IPath = {
parameters?: Array<
| IOperation.IParameter
| IJsonSchema.IReference<`#/components/headers/${string}`>
Expand Down Expand Up @@ -170,8 +170,8 @@ export namespace OpenApiV3 {
/** @type int */ enum?: number[];
/** @type int */ minimum?: number;
/** @type int */ maximum?: number;
/** @type int */ exclusiveMinimum?: boolean;
/** @type int */ exclusiveMaximum?: boolean;
exclusiveMinimum?: boolean;
exclusiveMaximum?: boolean;
/** @type uint */ multipleOf?: number;
}
export interface INumber extends __ISignificant<"number"> {
Expand Down
9 changes: 4 additions & 5 deletions src/OpenApiV3_1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,13 @@ export namespace OpenApiV3_1 {
servers?: IServer[];
info?: IDocument.IInfo;
components?: IComponents;
paths?: Record<string, IPathItem>;
paths?: Record<string, IPath>;
webhooks?: Record<
string,
IJsonSchema.IReference<`#/components/pathItems/${string}`> | IPathItem
IJsonSchema.IReference<`#/components/pathItems/${string}`> | IPath
>;
security?: Record<string, string[]>[];
tags?: IDocument.ITag[];
"x-samchon-emended"?: boolean;
}
export namespace IDocument {
export interface IInfo {
Expand Down Expand Up @@ -82,7 +81,7 @@ export namespace OpenApiV3_1 {
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
export type IPathItem = {
export type IPath = {
parameters?: Array<
| IOperation.IParameter
| IJsonSchema.IReference<`#/components/headers/${string}`>
Expand Down Expand Up @@ -147,7 +146,7 @@ export namespace OpenApiV3_1 {
----------------------------------------------------------- */
export interface IComponents {
schemas?: Record<string, IJsonSchema>;
pathItems?: Record<string, IPathItem>;
pathItems?: Record<string, IPath>;
responses?: Record<string, IOperation.IResponse>;
parameters?: Record<string, IOperation.IParameter>;
requestBodies?: Record<string, IOperation.IRequestBody>;
Expand Down
8 changes: 4 additions & 4 deletions src/SwaggerV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export namespace SwaggerV2 {
responses?: Record<string, IOperation.IResponse>;
securityDefinitions?: Record<string, ISecurityDefinition>;
security?: Record<string, string[]>[];
paths?: Record<string, IPathItem>;
paths?: Record<string, IPath>;
tags?: IDocument.ITag[];
}
export namespace IDocument {
Expand Down Expand Up @@ -68,7 +68,7 @@ export namespace SwaggerV2 {
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
export type IPathItem = {
export type IPath = {
parameters?: Array<
IOperation.IParameter | IJsonSchema.IReference<`#/parameters/${string}`>
>;
Expand Down Expand Up @@ -138,8 +138,8 @@ export namespace SwaggerV2 {
/** @type int */ enum?: number[];
/** @type int */ minimum?: number;
/** @type int */ maximum?: number;
/** @type int */ exclusiveMinimum?: boolean;
/** @type int */ exclusiveMaximum?: boolean;
exclusiveMinimum?: boolean;
exclusiveMaximum?: boolean;
/** @type uint */ multipleOf?: number;
}
export interface INumber extends __ISignificant<"number"> {
Expand Down
48 changes: 27 additions & 21 deletions src/internal/OpenApiV3Converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export namespace OpenApiV3Converter {
----------------------------------------------------------- */
const convertPathItem =
(doc: OpenApiV3.IDocument) =>
(pathItem: OpenApiV3.IPathItem): OpenApi.IPathItem => ({
(pathItem: OpenApiV3.IPath): OpenApi.IPath => ({
...(pathItem as any),
...(pathItem.get
? { get: convertOperation(doc)(pathItem)(pathItem.get) }
Expand Down Expand Up @@ -52,24 +52,28 @@ export namespace OpenApiV3Converter {
});
const convertOperation =
(doc: OpenApiV3.IDocument) =>
(pathItem: OpenApiV3.IPathItem) =>
(pathItem: OpenApiV3.IPath) =>
(input: OpenApiV3.IOperation): OpenApi.IOperation => ({
...input,
parameters: [...(pathItem.parameters ?? []), ...(input.parameters ?? [])]
.map((p) => {
if (!TypeChecker.isReference(p)) return convertParameter(p);
const found: Omit<OpenApiV3.IOperation.IParameter, "in"> | undefined =
p.$ref.startsWith("#/components/headers/")
? doc.components?.headers?.[p.$ref.split("/").pop() ?? ""]
: doc.components?.parameters?.[p.$ref.split("/").pop() ?? ""];
return found !== undefined
? convertParameter({
...found,
in: "header",
parameters:
pathItem.parameters !== undefined && input.parameters !== undefined
? [...(pathItem.parameters ?? []), ...(input.parameters ?? [])]
.map((p) => {
if (!TypeChecker.isReference(p)) return convertParameter(p);
const found:
| Omit<OpenApiV3.IOperation.IParameter, "in">
| undefined = p.$ref.startsWith("#/components/headers/")
? doc.components?.headers?.[p.$ref.split("/").pop() ?? ""]
: doc.components?.parameters?.[p.$ref.split("/").pop() ?? ""];
return found !== undefined
? convertParameter({
...found,
in: "header",
})
: undefined!;
})
: undefined!;
})
.filter((_, v) => v !== undefined),
.filter((_, v) => v !== undefined)
: undefined,
requestBody: input.requestBody
? convertRequestBody(doc)(input.requestBody)
: undefined,
Expand Down Expand Up @@ -185,11 +189,13 @@ export namespace OpenApiV3Converter {
const convertComponents = (
input: OpenApiV3.IComponents,
): OpenApi.IComponents => ({
schemas: Object.fromEntries(
Object.entries(input.schemas ?? {})
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(value)]),
),
schemas: input.schemas
? Object.fromEntries(
Object.entries(input.schemas)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(value)]),
)
: undefined,
securitySchemes: input.securitySchemes,
});
const convertSchema = (input: OpenApiV3.IJsonSchema): OpenApi.IJsonSchema => {
Expand Down
58 changes: 32 additions & 26 deletions src/internal/OpenApiV3_1Converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { OpenApiV3_1 } from "../OpenApiV3_1";

export namespace OpenApiV3_1Converter {
export const convert = (input: OpenApiV3_1.IDocument): OpenApi.IDocument => {
if (input["x-samchon-emended"] === true) return input as OpenApi.IDocument;
if ((input as OpenApi.IDocument)["x-samchon-emended"] === true)
return input as OpenApi.IDocument;
return {
...input,
components: convertComponents(input.components ?? {}),
Expand Down Expand Up @@ -38,18 +39,18 @@ export namespace OpenApiV3_1Converter {
(doc: OpenApiV3_1.IDocument) =>
(
webhook:
| OpenApiV3_1.IPathItem
| OpenApiV3_1.IPath
| OpenApiV3_1.IJsonSchema.IReference<`#/components/pathItems/${string}`>,
): OpenApi.IPathItem | undefined => {
): OpenApi.IPath | undefined => {
if (!TypeChecker.isReference(webhook))
return convertPathItem(doc)(webhook);
const found: OpenApiV3_1.IPathItem | undefined =
const found: OpenApiV3_1.IPath | undefined =
doc.components?.pathItems?.[webhook.$ref.split("/").pop() ?? ""];
return found ? convertPathItem(doc)(found) : undefined;
};
const convertPathItem =
(doc: OpenApiV3_1.IDocument) =>
(pathItem: OpenApiV3_1.IPathItem): OpenApi.IPathItem => ({
(pathItem: OpenApiV3_1.IPath): OpenApi.IPath => ({
...(pathItem as any),
...(pathItem.get
? { get: convertOperation(doc)(pathItem)(pathItem.get) }
Expand Down Expand Up @@ -78,25 +79,28 @@ export namespace OpenApiV3_1Converter {
});
const convertOperation =
(doc: OpenApiV3_1.IDocument) =>
(pathItem: OpenApiV3_1.IPathItem) =>
(pathItem: OpenApiV3_1.IPath) =>
(input: OpenApiV3_1.IOperation): OpenApi.IOperation => ({
...input,
parameters: [...(pathItem.parameters ?? []), ...(input.parameters ?? [])]
.map((p) => {
if (!TypeChecker.isReference(p)) return convertParameter(p);
const found:
| Omit<OpenApiV3_1.IOperation.IParameter, "in">
| undefined = p.$ref.startsWith("#/components/headers/")
? doc.components?.headers?.[p.$ref.split("/").pop() ?? ""]
: doc.components?.parameters?.[p.$ref.split("/").pop() ?? ""];
return found !== undefined
? convertParameter({
...found,
in: "header",
parameters:
pathItem.parameters !== undefined || input.parameters === undefined
? [...(pathItem.parameters ?? []), ...(input.parameters ?? [])]
.map((p) => {
if (!TypeChecker.isReference(p)) return convertParameter(p);
const found:
| Omit<OpenApiV3_1.IOperation.IParameter, "in">
| undefined = p.$ref.startsWith("#/components/headers/")
? doc.components?.headers?.[p.$ref.split("/").pop() ?? ""]
: doc.components?.parameters?.[p.$ref.split("/").pop() ?? ""];
return found !== undefined
? convertParameter({
...found,
in: "header",
})
: undefined!;
})
: undefined!;
})
.filter((_, v) => v !== undefined),
.filter((_, v) => v !== undefined)
: undefined,
requestBody: input.requestBody
? convertRequestBody(doc)(input.requestBody)
: undefined,
Expand Down Expand Up @@ -209,11 +213,13 @@ export namespace OpenApiV3_1Converter {
const convertComponents = (
input: OpenApiV3_1.IComponents,
): OpenApi.IComponents => ({
schemas: Object.fromEntries(
Object.entries(input.schemas ?? {})
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(value)] as const),
),
schemas: input.schemas
? Object.fromEntries(
Object.entries(input.schemas)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSchema(value)] as const),
)
: undefined,
securitySchemes: input.securitySchemes,
});
const convertSchema = (
Expand Down
Loading

0 comments on commit cf36269

Please sign in to comment.