@samchon/openapi
Advanced tools
Comparing version 0.3.4 to 0.4.0-dev.20240711
@@ -177,5 +177,8 @@ import { OpenApi } from "./OpenApi"; | ||
/** | ||
* Description comment for the path parameter. | ||
* Original parameter info from the OpenAPI document. | ||
* | ||
* The `parameter` is a function returning the original | ||
* {@link OpenApi.IOperation.IParameter} from the {@link OpenAPI} document. | ||
*/ | ||
description?: string; | ||
parameter: () => OpenApi.IOperation.IParameter<Schema>; | ||
} | ||
@@ -198,2 +201,4 @@ /** | ||
schema: Schema; | ||
title: () => string | undefined; | ||
description: () => string | undefined; | ||
} | ||
@@ -207,2 +212,4 @@ /** | ||
schema: Schema; | ||
title: () => string | undefined; | ||
description: () => string | undefined; | ||
} | ||
@@ -230,2 +237,6 @@ /** | ||
/** | ||
* Description comment for the request/response body. | ||
*/ | ||
description: () => string | undefined; | ||
/** | ||
* Whether the body is encrypted or not. | ||
@@ -240,10 +251,10 @@ */ | ||
/** | ||
* Description comment for the exception. | ||
* Metadata of response body data type. | ||
*/ | ||
description?: string; | ||
schema: Schema; | ||
/** | ||
* Metadata of response body data type. | ||
* Description comment for the exception. | ||
*/ | ||
schema: Schema; | ||
response: () => OpenApi.IOperation.IResponse<Schema>; | ||
} | ||
} |
@@ -10,3 +10,3 @@ "use strict"; | ||
MigrateRouteConverter.convert = (props) => { | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j; | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; | ||
//---- | ||
@@ -56,4 +56,5 @@ // REQUEST AND RESPONSE BODY | ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isArray(p.schema)); | ||
const out = (elem) => (Object.assign(Object.assign({}, elem), { name: type, key: type, title: () => elem.title, description: () => elem.description })); | ||
if (objects.length === 1 && primitives.length === 0) | ||
return objects[0]; | ||
return out(parameters[0]); | ||
else if (objects.length > 1) { | ||
@@ -96,27 +97,29 @@ failures.push(`${type} typed parameters must be only one object type`); | ||
? null | ||
: emplaceReference({ | ||
document: props.document, | ||
name: StringUtil_1.StringUtil.pascal(`I/Api/${props.path}`) + | ||
"." + | ||
StringUtil_1.StringUtil.pascal(`${props.method}/${type}`), | ||
schema: { | ||
type: "object", | ||
properties: Object.fromEntries([ | ||
...new Map(entire | ||
.map((o) => { | ||
var _a; | ||
return Object.entries((_a = o.properties) !== null && _a !== void 0 ? _a : {}).map(([name, schema]) => { | ||
: out({ | ||
schema: emplaceReference({ | ||
document: props.document, | ||
name: StringUtil_1.StringUtil.pascal(`I/Api/${props.path}`) + | ||
"." + | ||
StringUtil_1.StringUtil.pascal(`${props.method}/${type}`), | ||
schema: { | ||
type: "object", | ||
properties: Object.fromEntries([ | ||
...new Map(entire | ||
.map((o) => { | ||
var _a; | ||
return [ | ||
name, | ||
Object.assign(Object.assign({}, schema), { description: (_a = schema.description) !== null && _a !== void 0 ? _a : schema.description }), | ||
]; | ||
}); | ||
}) | ||
.flat()), | ||
]), | ||
required: [ | ||
...new Set(entire.map((o) => { var _a; return (_a = o.required) !== null && _a !== void 0 ? _a : []; }).flat()), | ||
], | ||
}, | ||
return Object.entries((_a = o.properties) !== null && _a !== void 0 ? _a : {}).map(([name, schema]) => { | ||
var _a; | ||
return [ | ||
name, | ||
Object.assign(Object.assign({}, schema), { description: (_a = schema.description) !== null && _a !== void 0 ? _a : schema.description }), | ||
]; | ||
}); | ||
}) | ||
.flat()), | ||
]), | ||
required: [ | ||
...new Set(entire.map((o) => { var _a; return (_a = o.required) !== null && _a !== void 0 ? _a : []; }).flat()), | ||
], | ||
}, | ||
}), | ||
}); | ||
@@ -151,2 +154,20 @@ }); | ||
return failures; | ||
const parameters = ((_h = props.operation.parameters) !== null && _h !== void 0 ? _h : []) | ||
.filter((p) => p.in === "path") | ||
.map((p, i) => ({ | ||
// FILL KEY NAME IF NOT EXISTsS | ||
name: parameterNames[i], | ||
key: (() => { | ||
let key = StringUtil_1.StringUtil.normalize(parameterNames[i]); | ||
if (Escaper_1.Escaper.variable(key)) | ||
return key; | ||
while (true) { | ||
key = "_" + key; | ||
if (!parameterNames.some((s) => s === key)) | ||
return key; | ||
} | ||
})(), | ||
schema: p.schema, | ||
parameter: () => p, | ||
})); | ||
return { | ||
@@ -157,56 +178,47 @@ method: props.method, | ||
accessor: ["@lazy"], | ||
headers: headers | ||
? { | ||
name: "headers", | ||
key: "headers", | ||
schema: headers, | ||
} | ||
: null, | ||
parameters: ((_h = props.operation.parameters) !== null && _h !== void 0 ? _h : []) | ||
parameters: ((_j = props.operation.parameters) !== null && _j !== void 0 ? _j : []) | ||
.filter((p) => p.in === "path") | ||
.map((p, i) => { | ||
var _a; | ||
return ({ | ||
// FILL KEY NAME IF NOT EXISTsS | ||
name: parameterNames[i], | ||
key: (() => { | ||
let key = StringUtil_1.StringUtil.normalize(parameterNames[i]); | ||
if (Escaper_1.Escaper.variable(key)) | ||
.map((p, i) => ({ | ||
// FILL KEY NAME IF NOT EXISTsS | ||
name: parameterNames[i], | ||
key: (() => { | ||
let key = StringUtil_1.StringUtil.normalize(parameterNames[i]); | ||
if (Escaper_1.Escaper.variable(key)) | ||
return key; | ||
while (true) { | ||
key = "_" + key; | ||
if (!parameterNames.some((s) => s === key)) | ||
return key; | ||
while (true) { | ||
key = "_" + key; | ||
if (!parameterNames.some((s) => s === key)) | ||
return key; | ||
} | ||
})(), | ||
schema: Object.assign(Object.assign({}, p.schema), { description: (_a = p.schema.description) !== null && _a !== void 0 ? _a : p.description }), | ||
}); | ||
}), | ||
query: query | ||
? { | ||
name: "query", | ||
key: "query", | ||
schema: query, | ||
} | ||
: null, | ||
} | ||
})(), | ||
schema: p.schema, | ||
parameter: () => p, | ||
})), | ||
headers: headers || null, | ||
query: query || null, | ||
body: body, | ||
success: success, | ||
exceptions: Object.fromEntries(Object.entries((_j = props.operation.responses) !== null && _j !== void 0 ? _j : {}) | ||
exceptions: Object.fromEntries(Object.entries((_k = props.operation.responses) !== null && _k !== void 0 ? _k : {}) | ||
.filter(([key]) => key !== "200" && key !== "201" && key !== "default") | ||
.map(([key, value]) => { | ||
.map(([status, response]) => { | ||
var _a, _b, _c; | ||
return [ | ||
key, | ||
status, | ||
{ | ||
description: value.description, | ||
schema: (_c = (_b = (_a = value.content) === null || _a === void 0 ? void 0 : _a["application/json"]) === null || _b === void 0 ? void 0 : _b.schema) !== null && _c !== void 0 ? _c : {}, | ||
schema: (_c = (_b = (_a = response.content) === null || _a === void 0 ? void 0 : _a["application/json"]) === null || _b === void 0 ? void 0 : _b.schema) !== null && _c !== void 0 ? _c : {}, | ||
response: () => response, | ||
}, | ||
]; | ||
})), | ||
comment: () => writeDescription(props.operation), | ||
comment: () => writeRouteComment({ | ||
operation: props.operation, | ||
parameters, | ||
query: query || null, | ||
body: body || null, | ||
}), | ||
operation: () => props.operation, | ||
}; | ||
}; | ||
const writeDescription = (original) => { | ||
var _a, _b, _c, _d; | ||
const writeRouteComment = (props) => { | ||
var _a, _b, _c, _d, _e, _f; | ||
const commentTags = []; | ||
@@ -217,21 +229,30 @@ const add = (text) => { | ||
}; | ||
let description = (_a = original.description) !== null && _a !== void 0 ? _a : ""; | ||
if (original.summary) { | ||
const emended = original.summary.endsWith(".") | ||
? original.summary | ||
: original.summary + "."; | ||
if (!!description.length && !description.startsWith(original.summary)) | ||
let description = (_a = props.operation.description) !== null && _a !== void 0 ? _a : ""; | ||
if (props.operation.summary) { | ||
const emended = props.operation.summary.endsWith(".") | ||
? props.operation.summary | ||
: props.operation.summary + "."; | ||
if (!!description.length && | ||
!description.startsWith(props.operation.summary)) | ||
description = `${emended}\n${description}`; | ||
} | ||
for (const p of (_b = original.parameters) !== null && _b !== void 0 ? _b : []) | ||
if (p.description) | ||
add(`@param ${p.name} ${p.description}`); | ||
if ((_c = original.requestBody) === null || _c === void 0 ? void 0 : _c.description) | ||
add(`@param body ${original.requestBody.description}`); | ||
for (const security of (_d = original.security) !== null && _d !== void 0 ? _d : []) | ||
description = description | ||
.split("\n") | ||
.map((s) => s.trim()) | ||
.join("\n"); | ||
for (const p of (_b = props.parameters) !== null && _b !== void 0 ? _b : []) { | ||
const param = p.parameter(); | ||
if (param.description || param.title) { | ||
const text = ((_c = param.description) !== null && _c !== void 0 ? _c : param.title); | ||
add(`@param ${p.name} ${writeIndented(text, p.name.length + 8)}`); | ||
} | ||
} | ||
if ((_e = (_d = props.body) === null || _d === void 0 ? void 0 : _d.description()) === null || _e === void 0 ? void 0 : _e.length) | ||
add(`@param body ${writeIndented(props.body.description(), 12)}`); | ||
for (const security of (_f = props.operation.security) !== null && _f !== void 0 ? _f : []) | ||
for (const [name, scopes] of Object.entries(security)) | ||
add(`@security ${[name, ...scopes].join("")}`); | ||
if (original.tags) | ||
original.tags.forEach((name) => add(`@tag ${name}`)); | ||
if (original.deprecated) | ||
if (props.operation.tags) | ||
props.operation.tags.forEach((name) => add(`@tag ${name}`)); | ||
if (props.operation.deprecated) | ||
add("@deprecated"); | ||
@@ -244,2 +265,7 @@ return description.length | ||
}; | ||
const writeIndented = (text, spaces) => text | ||
.split("\n") | ||
.map((s) => s.trim()) | ||
.map((s, i) => (i === 0 ? s : `${" ".repeat(spaces)}${s}`)) | ||
.join("\n"); | ||
const emplaceBodySchema = (from) => (emplacer) => (meta) => { | ||
@@ -264,2 +290,3 @@ if (!(meta === null || meta === void 0 ? void 0 : meta.content)) | ||
"x-nestia-encrypted": meta["x-nestia-encrypted"], | ||
description: () => meta.description, | ||
}; | ||
@@ -279,2 +306,3 @@ } | ||
: {}, | ||
description: () => meta.description, | ||
}; | ||
@@ -289,2 +317,3 @@ } | ||
schema: { type: "string" }, | ||
description: () => meta.description, | ||
}; | ||
@@ -304,2 +333,3 @@ if (from === "request") { | ||
: {}, | ||
description: () => meta.description, | ||
}; | ||
@@ -306,0 +336,0 @@ } |
{ | ||
"name": "@samchon/openapi", | ||
"version": "0.3.4", | ||
"version": "0.4.0-dev.20240711", | ||
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
@@ -40,3 +40,3 @@ # `@samchon/openapi` | ||
Additionally, `@samchon/openapi` provides [`IMigrateDocument`](https://github.com/samchon/openapi/blob/master/src/IMigrateDocument.ts) for OpenAPI generators. | ||
Additionally, `@samchon/openapi` provides [`IMigrateDocument`](https://github.com/samchon/openapi/blob/master/src/IMigrateDocument.ts) for OpenAPI generators. If you're developing TypeScript, [`@nestia/editor`](https://nestia.io/docs/editor) would be the best project utilizing the [`IMigrateDocument`](https://github.com/samchon/openapi/blob/master/src/IMigrateDocument.ts) for the OpenAPI SDK generation. Otherwise, you wanna utilize OpenAPI document for OpenAI function calling, [`@wrtnio/openai-function-schema`](https://github.com/wrtnio/openai-function-schema/) has been prepared for you. | ||
@@ -43,0 +43,0 @@ |
@@ -197,5 +197,8 @@ import { OpenApi } from "./OpenApi"; | ||
/** | ||
* Description comment for the path parameter. | ||
* Original parameter info from the OpenAPI document. | ||
* | ||
* The `parameter` is a function returning the original | ||
* {@link OpenApi.IOperation.IParameter} from the {@link OpenAPI} document. | ||
*/ | ||
description?: string; | ||
parameter: () => OpenApi.IOperation.IParameter<Schema>; | ||
} | ||
@@ -223,2 +226,4 @@ | ||
schema: Schema; | ||
title: () => string | undefined; | ||
description: () => string | undefined; | ||
} | ||
@@ -235,2 +240,4 @@ | ||
schema: Schema; | ||
title: () => string | undefined; | ||
description: () => string | undefined; | ||
} | ||
@@ -269,2 +276,7 @@ | ||
/** | ||
* Description comment for the request/response body. | ||
*/ | ||
description: () => string | undefined; | ||
/** | ||
* Whether the body is encrypted or not. | ||
@@ -282,11 +294,11 @@ */ | ||
/** | ||
* Description comment for the exception. | ||
* Metadata of response body data type. | ||
*/ | ||
description?: string; | ||
schema: Schema; | ||
/** | ||
* Metadata of response body data type. | ||
* Description comment for the exception. | ||
*/ | ||
schema: Schema; | ||
response: () => OpenApi.IOperation.IResponse<Schema>; | ||
} | ||
} |
@@ -85,3 +85,17 @@ import { IMigrateRoute } from "../IMigrateRoute"; | ||
); | ||
if (objects.length === 1 && primitives.length === 0) return objects[0]; | ||
const out = (elem: { | ||
schema: OpenApi.IJsonSchema; | ||
title?: string; | ||
description?: string; | ||
}) => | ||
({ | ||
...elem, | ||
name: type, | ||
key: type, | ||
title: () => elem.title, | ||
description: () => elem.description, | ||
}) satisfies IMigrateRoute.IHeaders; | ||
if (objects.length === 1 && primitives.length === 0) | ||
return out(parameters[0]); | ||
else if (objects.length > 1) { | ||
@@ -131,33 +145,35 @@ failures.push(`${type} typed parameters must be only one object type`); | ||
? null | ||
: emplaceReference({ | ||
document: props.document, | ||
name: | ||
StringUtil.pascal(`I/Api/${props.path}`) + | ||
"." + | ||
StringUtil.pascal(`${props.method}/${type}`), | ||
schema: { | ||
type: "object", | ||
properties: Object.fromEntries([ | ||
...new Map<string, OpenApi.IJsonSchema>( | ||
entire | ||
.map((o) => | ||
Object.entries(o.properties ?? {}).map( | ||
([name, schema]) => | ||
[ | ||
name, | ||
{ | ||
...schema, | ||
description: | ||
schema.description ?? schema.description, | ||
} as OpenApi.IJsonSchema, | ||
] as const, | ||
), | ||
) | ||
.flat(), | ||
), | ||
]), | ||
required: [ | ||
...new Set(entire.map((o) => o.required ?? []).flat()), | ||
], | ||
}, | ||
: out({ | ||
schema: emplaceReference({ | ||
document: props.document, | ||
name: | ||
StringUtil.pascal(`I/Api/${props.path}`) + | ||
"." + | ||
StringUtil.pascal(`${props.method}/${type}`), | ||
schema: { | ||
type: "object", | ||
properties: Object.fromEntries([ | ||
...new Map<string, OpenApi.IJsonSchema>( | ||
entire | ||
.map((o) => | ||
Object.entries(o.properties ?? {}).map( | ||
([name, schema]) => | ||
[ | ||
name, | ||
{ | ||
...schema, | ||
description: | ||
schema.description ?? schema.description, | ||
} as OpenApi.IJsonSchema, | ||
] as const, | ||
), | ||
) | ||
.flat(), | ||
), | ||
]), | ||
required: [ | ||
...new Set(entire.map((o) => o.required ?? []).flat()), | ||
], | ||
}, | ||
}), | ||
}); | ||
@@ -205,2 +221,20 @@ }); | ||
const parameters: IMigrateRoute.IParameter[] = ( | ||
props.operation.parameters ?? [] | ||
) | ||
.filter((p) => p.in === "path") | ||
.map((p, i) => ({ | ||
// FILL KEY NAME IF NOT EXISTsS | ||
name: parameterNames[i], | ||
key: (() => { | ||
let key: string = StringUtil.normalize(parameterNames[i]); | ||
if (Escaper.variable(key)) return key; | ||
while (true) { | ||
key = "_" + key; | ||
if (!parameterNames.some((s) => s === key)) return key; | ||
} | ||
})(), | ||
schema: p.schema, | ||
parameter: () => p, | ||
})); | ||
return { | ||
@@ -211,9 +245,2 @@ method: props.method, | ||
accessor: ["@lazy"], | ||
headers: headers | ||
? { | ||
name: "headers", | ||
key: "headers", | ||
schema: headers, | ||
} | ||
: null, | ||
parameters: (props.operation.parameters ?? []) | ||
@@ -232,14 +259,7 @@ .filter((p) => p.in === "path") | ||
})(), | ||
schema: { | ||
...p!.schema, | ||
description: p!.schema.description ?? p!.description, | ||
}, | ||
schema: p.schema, | ||
parameter: () => p, | ||
})), | ||
query: query | ||
? { | ||
name: "query", | ||
key: "query", | ||
schema: query, | ||
} | ||
: null, | ||
headers: headers || null, | ||
query: query || null, | ||
body: body as IMigrateRoute.IBody | null, | ||
@@ -252,11 +272,17 @@ success: success as IMigrateRoute.IBody | null, | ||
) | ||
.map(([key, value]) => [ | ||
key, | ||
.map(([status, response]) => [ | ||
status, | ||
{ | ||
description: value.description, | ||
schema: value.content?.["application/json"]?.schema ?? {}, | ||
schema: response.content?.["application/json"]?.schema ?? {}, | ||
response: () => response, | ||
}, | ||
]), | ||
), | ||
comment: () => writeDescription(props.operation), | ||
comment: () => | ||
writeRouteComment({ | ||
operation: props.operation, | ||
parameters, | ||
query: query || null, | ||
body: body || null, | ||
}), | ||
operation: () => props.operation, | ||
@@ -266,3 +292,8 @@ }; | ||
const writeDescription = (original: OpenApi.IOperation): string => { | ||
const writeRouteComment = (props: { | ||
operation: OpenApi.IOperation; | ||
parameters: IMigrateRoute.IParameter[]; | ||
query: IMigrateRoute.IQuery | null; | ||
body: IMigrateRoute.IBody | null; | ||
}): string => { | ||
const commentTags: string[] = []; | ||
@@ -273,19 +304,33 @@ const add = (text: string) => { | ||
let description: string = original.description ?? ""; | ||
if (original.summary) { | ||
const emended: string = original.summary.endsWith(".") | ||
? original.summary | ||
: original.summary + "."; | ||
if (!!description.length && !description.startsWith(original.summary)) | ||
let description: string = props.operation.description ?? ""; | ||
if (props.operation.summary) { | ||
const emended: string = props.operation.summary.endsWith(".") | ||
? props.operation.summary | ||
: props.operation.summary + "."; | ||
if ( | ||
!!description.length && | ||
!description.startsWith(props.operation.summary) | ||
) | ||
description = `${emended}\n${description}`; | ||
} | ||
for (const p of original.parameters ?? []) | ||
if (p.description) add(`@param ${p.name} ${p.description}`); | ||
if (original.requestBody?.description) | ||
add(`@param body ${original.requestBody.description}`); | ||
for (const security of original.security ?? []) | ||
description = description | ||
.split("\n") | ||
.map((s) => s.trim()) | ||
.join("\n"); | ||
for (const p of props.parameters ?? []) { | ||
const param = p.parameter(); | ||
if (param.description || param.title) { | ||
const text: string = (param.description ?? param.title)!; | ||
add(`@param ${p.name} ${writeIndented(text, p.name.length + 8)}`); | ||
} | ||
} | ||
if (props.body?.description()?.length) | ||
add(`@param body ${writeIndented(props.body.description()!, 12)}`); | ||
for (const security of props.operation.security ?? []) | ||
for (const [name, scopes] of Object.entries(security)) | ||
add(`@security ${[name, ...scopes].join("")}`); | ||
if (original.tags) original.tags.forEach((name) => add(`@tag ${name}`)); | ||
if (original.deprecated) add("@deprecated"); | ||
if (props.operation.tags) | ||
props.operation.tags.forEach((name) => add(`@tag ${name}`)); | ||
if (props.operation.deprecated) add("@deprecated"); | ||
return description.length | ||
@@ -298,2 +343,9 @@ ? commentTags.length | ||
const writeIndented = (text: string, spaces: number): string => | ||
text | ||
.split("\n") | ||
.map((s) => s.trim()) | ||
.map((s, i) => (i === 0 ? s : `${" ".repeat(spaces)}${s}`)) | ||
.join("\n"); | ||
const emplaceBodySchema = | ||
@@ -334,2 +386,3 @@ (from: "request" | "response") => | ||
"x-nestia-encrypted": meta["x-nestia-encrypted"], | ||
description: () => meta.description, | ||
}; | ||
@@ -352,2 +405,3 @@ } | ||
: {}, | ||
description: () => meta.description, | ||
}; | ||
@@ -363,2 +417,3 @@ } | ||
schema: { type: "string" }, | ||
description: () => meta.description, | ||
}; | ||
@@ -381,2 +436,3 @@ | ||
: {}, | ||
description: () => meta.description, | ||
}; | ||
@@ -383,0 +439,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
707780
11288