@samchon/openapi
Advanced tools
Comparing version 2.0.0-dev.20241107 to 2.0.0-dev.20241108
@@ -7,3 +7,4 @@ import { OpenApi } from "../OpenApi"; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}) => IGeminiSchema | null; | ||
} |
@@ -10,3 +10,4 @@ import { OpenApi } from "../OpenApi"; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}) => ILlmSchema | null; | ||
} |
@@ -79,6 +79,6 @@ "use strict"; | ||
HttpLlmConverter.schema = function (props) { | ||
var resolved = escape({ | ||
var resolved = OpenApiTypeChecker_1.OpenApiTypeChecker.escape({ | ||
components: props.components, | ||
visited: new Set(), | ||
input: props.schema, | ||
schema: props.schema, | ||
recursive: props.recursive, | ||
}); | ||
@@ -108,2 +108,3 @@ if (resolved === null) | ||
schema: s, | ||
recursive: options.recursive, | ||
}); | ||
@@ -194,86 +195,1 @@ }; | ||
}; | ||
var escape = function (props) { | ||
var _a; | ||
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(props.input)) { | ||
// REFERENCE | ||
var name_1 = props.input.$ref.split("#/components/schemas/")[1]; | ||
var target = (_a = props.components.schemas) === null || _a === void 0 ? void 0 : _a[name_1]; | ||
if (!target) | ||
return null; | ||
else if (props.visited.has(name_1)) | ||
return null; | ||
return escape({ | ||
components: props.components, | ||
visited: new Set(__spreadArray(__spreadArray([], __read(props.visited), false), [name_1], false)), | ||
input: target, | ||
}); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(props.input)) { | ||
// ONE-OF | ||
var oneOf = props.input.oneOf.map(function (schema) { | ||
return escape(__assign(__assign({}, props), { input: schema })); | ||
}); | ||
if (oneOf.some(function (v) { return v === null; })) | ||
return null; | ||
return __assign(__assign({}, props.input), { oneOf: flat(oneOf) }); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isObject(props.input)) { | ||
// OBJECT | ||
var properties = props.input.properties | ||
? Object.entries(props.input.properties).map(function (_a) { | ||
var _b = __read(_a, 2), key = _b[0], value = _b[1]; | ||
return [ | ||
key, | ||
escape(__assign(__assign({}, props), { input: value })), | ||
]; | ||
}) | ||
: undefined; | ||
var additionalProperties = props.input.additionalProperties | ||
? typeof props.input.additionalProperties === "object" && | ||
props.input.additionalProperties !== null | ||
? escape(__assign(__assign({}, props), { input: props.input.additionalProperties })) | ||
: props.input.additionalProperties | ||
: undefined; | ||
if (properties && properties.some(function (_a) { | ||
var _b = __read(_a, 2), _k = _b[0], v = _b[1]; | ||
return v === null; | ||
})) | ||
return null; | ||
else if (additionalProperties === null) | ||
return null; | ||
return __assign(__assign({}, props.input), { properties: properties | ||
? Object.fromEntries(properties.filter(function (_a) { | ||
var _b = __read(_a, 2), _k = _b[0], v = _b[1]; | ||
return !!v; | ||
})) | ||
: undefined, additionalProperties: additionalProperties }); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isTuple(props.input)) { | ||
// TUPLE | ||
var prefixItems = props.input.prefixItems.map(function (schema) { | ||
return escape(__assign(__assign({}, props), { input: schema })); | ||
}); | ||
var additionalItems = typeof props.input.additionalItems === "object" && | ||
props.input.additionalItems !== null | ||
? escape(__assign(__assign({}, props), { input: props.input.additionalItems })) | ||
: props.input.additionalItems; | ||
if (prefixItems.some(function (v) { return v === null; })) | ||
return null; | ||
else if (additionalItems === null) | ||
return null; | ||
return __assign(__assign({}, props.input), { prefixItems: prefixItems, additionalItems: additionalItems }); | ||
} | ||
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isArray(props.input)) { | ||
// ARRAY | ||
var items = escape(__assign(__assign({}, props), { input: props.input.items })); | ||
if (items === null) | ||
return null; | ||
return __assign(__assign({}, props.input), { items: items }); | ||
} | ||
return props.input; | ||
}; | ||
var flat = function (elements) { | ||
return elements | ||
.map(function (elem) { return (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(elem) ? flat(elem.oneOf) : elem); }) | ||
.flat(); | ||
}; |
@@ -74,2 +74,3 @@ import { OpenApi } from "./OpenApi"; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}) => ILlmSchema | null; | ||
@@ -76,0 +77,0 @@ /** |
@@ -61,3 +61,3 @@ "use strict"; | ||
HttpLlm.application = function (document, options) { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
// MIGRATE | ||
@@ -69,2 +69,3 @@ if (document["x-samchon-emended"] === true) | ||
separate: (_b = options === null || options === void 0 ? void 0 : options.separate) !== null && _b !== void 0 ? _b : null, | ||
recursive: (_c = options === null || options === void 0 ? void 0 : options.recursive) !== null && _c !== void 0 ? _c : 3, | ||
}); | ||
@@ -71,0 +72,0 @@ }; |
@@ -165,2 +165,10 @@ import { OpenApi } from "../OpenApi"; | ||
/** | ||
* Whether to allow recursive types or not. | ||
* | ||
* If allow, then how many times to repeat the recursive types. | ||
* | ||
* @default 3 | ||
*/ | ||
recursive: false | number; | ||
/** | ||
* Separator function for the parameters. | ||
@@ -167,0 +175,0 @@ * |
@@ -51,2 +51,10 @@ import { ILlmFunction } from "./ILlmFunction"; | ||
/** | ||
* Whether to allow recursive types or not. | ||
* | ||
* If allow, then how many times to repeat the recursive types. | ||
* | ||
* @default 3 | ||
*/ | ||
recursive: false | number; | ||
/** | ||
* Separator function for the parameters. | ||
@@ -53,0 +61,0 @@ * |
@@ -15,2 +15,11 @@ import { OpenApi } from "../OpenApi"; | ||
const isOneOf: (schema: OpenApi.IJsonSchema) => schema is OpenApi.IJsonSchema.IOneOf; | ||
const isRecursiveReference: (props: { | ||
components: OpenApi.IComponents; | ||
schema: OpenApi.IJsonSchema; | ||
}) => boolean; | ||
const escape: (props: { | ||
components: OpenApi.IComponents; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}) => OpenApi.IJsonSchema | null; | ||
const visit: (props: { | ||
@@ -17,0 +26,0 @@ closure: (schema: OpenApi.IJsonSchema) => void; |
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __values = (this && this.__values) || function(o) { | ||
@@ -29,2 +40,11 @@ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -79,5 +99,30 @@ exports.OpenApiTypeChecker = void 0; | ||
}; | ||
OpenApiTypeChecker.isRecursiveReference = function (props) { | ||
if (OpenApiTypeChecker.isReference(props.schema) === false) | ||
return false; | ||
var counter = new Map(); | ||
OpenApiTypeChecker.visit({ | ||
components: props.components, | ||
schema: props.schema, | ||
closure: function (schema) { | ||
var _a; | ||
if (OpenApiTypeChecker.isReference(schema)) { | ||
var key = schema.$ref.split("#/components/schemas/")[1]; | ||
counter.set(key, ((_a = counter.get(key)) !== null && _a !== void 0 ? _a : 0) + 1); | ||
} | ||
}, | ||
}); | ||
return Array.from(counter.values()).some(function (v) { return v > 1; }); | ||
}; | ||
/* ----------------------------------------------------------- | ||
OPERATORS | ||
----------------------------------------------------------- */ | ||
OpenApiTypeChecker.escape = function (props) { | ||
return escapeSchema({ | ||
components: props.components, | ||
schema: props.schema, | ||
recursive: props.recursive, | ||
visited: new Map(), | ||
}) || null; | ||
}; | ||
OpenApiTypeChecker.visit = function (props) { | ||
@@ -137,2 +182,139 @@ var already = new Set(); | ||
}; | ||
var escapeSchema = function (props) { | ||
var _a, _b, _c; | ||
if (OpenApiTypeChecker.isReference(props.schema)) { | ||
// REFERENCE | ||
var name_1 = props.schema.$ref.split("#/components/schemas/")[1]; | ||
var target = (_a = props.components.schemas) === null || _a === void 0 ? void 0 : _a[name_1]; | ||
if (target === undefined) | ||
return null; | ||
else if (props.visited.has(name_1) === true) { | ||
if (props.recursive === false) | ||
return null; | ||
var depth = props.visited.get(name_1); | ||
if (depth > props.recursive) | ||
return undefined; | ||
props.visited.set(name_1, depth + 1); | ||
return escapeSchema({ | ||
components: props.components, | ||
schema: target, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}); | ||
} | ||
return escapeSchema({ | ||
components: props.components, | ||
schema: target, | ||
recursive: props.recursive, | ||
visited: new Map(__spreadArray(__spreadArray([], __read(props.visited), false), [[name_1, 1]], false)), | ||
}); | ||
} | ||
else if (OpenApiTypeChecker.isOneOf(props.schema)) { | ||
// UNION | ||
var elements = props.schema.oneOf.map(function (schema) { | ||
return escapeSchema({ | ||
components: props.components, | ||
schema: schema, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}); | ||
}); | ||
if (elements.some(function (v) { return v === null; })) | ||
return null; | ||
var filtered = elements.filter(function (v) { return v !== undefined; }); | ||
if (filtered.length === 0) | ||
return undefined; | ||
return __assign(__assign({}, props), { oneOf: filtered.map(function (v) { return flat(props.components, v); }).flat() }); | ||
} | ||
else if (OpenApiTypeChecker.isObject(props.schema)) { | ||
// OBJECT | ||
var object_1 = props.schema; | ||
var properties_1 = Object.entries((_b = object_1.properties) !== null && _b !== void 0 ? _b : {}).map(function (_a) { | ||
var _b = __read(_a, 2), key = _b[0], value = _b[1]; | ||
return [ | ||
key, | ||
escapeSchema({ | ||
components: props.components, | ||
schema: value, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}), | ||
]; | ||
}); | ||
var additionalProperties = object_1.additionalProperties | ||
? typeof object_1.additionalProperties === "object" && | ||
object_1.additionalProperties !== null | ||
? escapeSchema({ | ||
components: props.components, | ||
schema: object_1.additionalProperties, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}) | ||
: object_1.additionalProperties | ||
: false; | ||
if (properties_1.some(function (_a) { | ||
var _b = __read(_a, 2), _k = _b[0], v = _b[1]; | ||
return v === null; | ||
}) || | ||
additionalProperties === null) | ||
return null; | ||
else if (properties_1.some(function (_a) { | ||
var _b; | ||
var _c = __read(_a, 2), k = _c[0], v = _c[1]; | ||
return v === undefined && ((_b = object_1.required) === null || _b === void 0 ? void 0 : _b.includes(k)) === true; | ||
}) === true) | ||
return undefined; | ||
return __assign(__assign({}, object_1), { properties: Object.fromEntries(properties_1.filter(function (_a) { | ||
var _b = __read(_a, 2), _k = _b[0], v = _b[1]; | ||
return v !== undefined; | ||
})), additionalProperties: additionalProperties !== null && additionalProperties !== void 0 ? additionalProperties : false, required: (_c = object_1.required) === null || _c === void 0 ? void 0 : _c.filter(function (k) { | ||
return properties_1.some(function (_a) { | ||
var _b = __read(_a, 2), key = _b[0], value = _b[1]; | ||
return key === k && value !== undefined; | ||
}); | ||
}) }); | ||
} | ||
else if (OpenApiTypeChecker.isTuple(props.schema)) { | ||
// TUPLE | ||
var elements = props.schema.prefixItems.map(function (schema) { | ||
return escapeSchema({ | ||
components: props.components, | ||
schema: schema, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}); | ||
}); | ||
var additionalItems = props.schema.additionalItems | ||
? typeof props.schema.additionalItems === "object" && | ||
props.schema.additionalItems !== null | ||
? escapeSchema({ | ||
components: props.components, | ||
schema: props.schema.additionalItems, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}) | ||
: props.schema.additionalItems | ||
: false; | ||
if (elements.some(function (v) { return v === null; }) || additionalItems === null) | ||
return null; | ||
else if (elements.some(function (v) { return v === undefined; })) | ||
return undefined; | ||
return __assign(__assign({}, props.schema), { prefixItems: elements, additionalItems: additionalItems !== null && additionalItems !== void 0 ? additionalItems : false }); | ||
} | ||
else if (OpenApiTypeChecker.isArray(props.schema)) { | ||
// ARRAY | ||
var items = escapeSchema({ | ||
components: props.components, | ||
schema: props.schema.items, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}); | ||
if (items === null) | ||
return null; | ||
else if (items === undefined) | ||
return __assign(__assign({}, props.schema), { minItems: undefined, maxItems: 0, items: {} }); | ||
return __assign(__assign({}, props.schema), { items: items }); | ||
} | ||
return props.schema; | ||
}; | ||
var coverStation = function (p) { | ||
@@ -158,4 +340,4 @@ var _a; | ||
// COMPARE WITH FLATTENING | ||
var alpha = flatSchema(p.components, p.x); | ||
var beta = flatSchema(p.components, p.y); | ||
var alpha = flat(p.components, p.x); | ||
var beta = flat(p.components, p.y); | ||
if (alpha.some(function (x) { return OpenApiTypeChecker.isUnknown(x); })) | ||
@@ -351,13 +533,18 @@ return true; | ||
}; | ||
var flatSchema = function (components, schema) { | ||
schema = escapeReference(components, schema); | ||
if (OpenApiTypeChecker.isOneOf(schema)) | ||
return schema.oneOf.map(function (v) { return flatSchema(components, v); }).flat(); | ||
return [schema]; | ||
}; | ||
var escapeReference = function (components, schema) { | ||
return OpenApiTypeChecker.isReference(schema) | ||
? escapeReference(components, components.schemas[schema.$ref.replace("#/components/schemas/", "")]) | ||
: schema; | ||
}; | ||
})(OpenApiTypeChecker || (exports.OpenApiTypeChecker = OpenApiTypeChecker = {})); | ||
var flat = function (components, schema) { | ||
schema = escapeReference(components, schema); | ||
if (OpenApiTypeChecker.isOneOf(schema)) | ||
return schema.oneOf.map(function (v) { return flat(components, v); }).flat(); | ||
return [schema]; | ||
}; | ||
var escapeReference = function (components, schema) { | ||
var _a, _b; | ||
if (OpenApiTypeChecker.isReference(schema) === false) | ||
return schema; | ||
var key = schema.$ref.replace("#/components/schemas/", ""); | ||
var found = escapeReference(components, (_b = (_a = components.schemas) === null || _a === void 0 ? void 0 : _a[key]) !== null && _b !== void 0 ? _b : {}); | ||
if (found === undefined) | ||
throw new Error("Reference not found: ".concat(JSON.stringify(schema.$ref))); | ||
return escapeReference(components, found); | ||
}; |
{ | ||
"name": "@samchon/openapi", | ||
"version": "2.0.0-dev.20241107", | ||
"version": "2.0.0-dev.20241108", | ||
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
@@ -11,2 +11,3 @@ import { OpenApi } from "../OpenApi"; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}): IGeminiSchema | null => { | ||
@@ -13,0 +14,0 @@ const schema: ILlmSchema | null = HttpLlmConverter.schema(props); |
@@ -53,7 +53,8 @@ import { OpenApi } from "../OpenApi"; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}): ILlmSchema | null => { | ||
const resolved: OpenApi.IJsonSchema | null = escape({ | ||
const resolved: OpenApi.IJsonSchema | null = OpenApiTypeChecker.escape({ | ||
components: props.components, | ||
visited: new Set(), | ||
input: props.schema, | ||
schema: props.schema, | ||
recursive: props.recursive, | ||
}); | ||
@@ -85,2 +86,3 @@ if (resolved === null) return null; | ||
schema: s, | ||
recursive: options.recursive, | ||
}); | ||
@@ -178,117 +180,1 @@ const output: ILlmSchema | null | undefined = | ||
}; | ||
const escape = (props: { | ||
components: OpenApi.IComponents; | ||
visited: Set<string>; | ||
input: OpenApi.IJsonSchema; | ||
}): OpenApi.IJsonSchema | null => { | ||
if (OpenApiTypeChecker.isReference(props.input)) { | ||
// REFERENCE | ||
const name: string = props.input.$ref.split("#/components/schemas/")[1]; | ||
const target: OpenApi.IJsonSchema | undefined = | ||
props.components.schemas?.[name]; | ||
if (!target) return null; | ||
else if (props.visited.has(name)) return null; | ||
return escape({ | ||
components: props.components, | ||
visited: new Set([...props.visited, name]), | ||
input: target, | ||
}); | ||
} else if (OpenApiTypeChecker.isOneOf(props.input)) { | ||
// ONE-OF | ||
const oneOf: Array<OpenApi.IJsonSchema | null> = props.input.oneOf.map( | ||
(schema) => | ||
escape({ | ||
...props, | ||
input: schema, | ||
})!, | ||
); | ||
if (oneOf.some((v) => v === null)) return null; | ||
return { | ||
...props.input, | ||
oneOf: flat(oneOf as OpenApi.IJsonSchema[]), | ||
}; | ||
} else if (OpenApiTypeChecker.isObject(props.input)) { | ||
// OBJECT | ||
const properties: Array<[string, OpenApi.IJsonSchema | null]> | undefined = | ||
props.input.properties | ||
? Object.entries(props.input.properties).map( | ||
([key, value]) => | ||
[ | ||
key, | ||
escape({ | ||
...props, | ||
input: value, | ||
}), | ||
] as const, | ||
) | ||
: undefined; | ||
const additionalProperties: | ||
| OpenApi.IJsonSchema | ||
| null | ||
| boolean | ||
| undefined = props.input.additionalProperties | ||
? typeof props.input.additionalProperties === "object" && | ||
props.input.additionalProperties !== null | ||
? escape({ | ||
...props, | ||
input: props.input.additionalProperties, | ||
}) | ||
: props.input.additionalProperties | ||
: undefined; | ||
if (properties && properties.some(([_k, v]) => v === null)) return null; | ||
else if (additionalProperties === null) return null; | ||
return { | ||
...props.input, | ||
properties: properties | ||
? Object.fromEntries( | ||
properties.filter(([_k, v]) => !!v) as Array< | ||
[string, OpenApi.IJsonSchema] | ||
>, | ||
) | ||
: undefined, | ||
additionalProperties, | ||
}; | ||
} else if (OpenApiTypeChecker.isTuple(props.input)) { | ||
// TUPLE | ||
const prefixItems: Array<OpenApi.IJsonSchema | null> = | ||
props.input.prefixItems.map((schema) => | ||
escape({ | ||
...props, | ||
input: schema, | ||
}), | ||
); | ||
const additionalItems: OpenApi.IJsonSchema | null | boolean | undefined = | ||
typeof props.input.additionalItems === "object" && | ||
props.input.additionalItems !== null | ||
? escape({ | ||
...props, | ||
input: props.input.additionalItems, | ||
}) | ||
: props.input.additionalItems; | ||
if (prefixItems.some((v) => v === null)) return null; | ||
else if (additionalItems === null) return null; | ||
return { | ||
...props.input, | ||
prefixItems: prefixItems as OpenApi.IJsonSchema[], | ||
additionalItems, | ||
}; | ||
} else if (OpenApiTypeChecker.isArray(props.input)) { | ||
// ARRAY | ||
const items: OpenApi.IJsonSchema | null = escape({ | ||
...props, | ||
input: props.input.items, | ||
}); | ||
if (items === null) return null; | ||
return { | ||
...props.input, | ||
items, | ||
}; | ||
} | ||
return props.input; | ||
}; | ||
const flat = (elements: OpenApi.IJsonSchema[]): OpenApi.IJsonSchema[] => | ||
elements | ||
.map((elem) => (OpenApiTypeChecker.isOneOf(elem) ? flat(elem.oneOf) : elem)) | ||
.flat(); |
@@ -84,2 +84,3 @@ import { HttpMigration } from "./HttpMigration"; | ||
separate: options?.separate ?? null, | ||
recursive: options?.recursive ?? 3, | ||
}, | ||
@@ -105,2 +106,3 @@ ); | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}): ILlmSchema | null => HttpLlmConverter.schema(props); | ||
@@ -107,0 +109,0 @@ |
@@ -182,2 +182,11 @@ import { OpenApi } from "../OpenApi"; | ||
/** | ||
* Whether to allow recursive types or not. | ||
* | ||
* If allow, then how many times to repeat the recursive types. | ||
* | ||
* @default 3 | ||
*/ | ||
recursive: false | number; | ||
/** | ||
* Separator function for the parameters. | ||
@@ -184,0 +193,0 @@ * |
@@ -53,2 +53,11 @@ import { ILlmFunction } from "./ILlmFunction"; | ||
/** | ||
* Whether to allow recursive types or not. | ||
* | ||
* If allow, then how many times to repeat the recursive types. | ||
* | ||
* @default 3 | ||
*/ | ||
recursive: false | number; | ||
/** | ||
* Separator function for the parameters. | ||
@@ -55,0 +64,0 @@ * |
@@ -12,2 +12,3 @@ import { OpenApi } from "../OpenApi"; | ||
(schema as OpenApi.IJsonSchema.INull).type === "null"; | ||
export const isUnknown = ( | ||
@@ -25,2 +26,3 @@ schema: OpenApi.IJsonSchema, | ||
(schema as OpenApi.IJsonSchema.IConstant).const !== undefined; | ||
export const isBoolean = ( | ||
@@ -30,2 +32,3 @@ schema: OpenApi.IJsonSchema, | ||
(schema as OpenApi.IJsonSchema.IBoolean).type === "boolean"; | ||
export const isInteger = ( | ||
@@ -35,2 +38,3 @@ schema: OpenApi.IJsonSchema, | ||
(schema as OpenApi.IJsonSchema.IInteger).type === "integer"; | ||
export const isNumber = ( | ||
@@ -40,2 +44,3 @@ schema: OpenApi.IJsonSchema, | ||
(schema as OpenApi.IJsonSchema.INumber).type === "number"; | ||
export const isString = ( | ||
@@ -51,2 +56,3 @@ schema: OpenApi.IJsonSchema, | ||
(schema as OpenApi.IJsonSchema.IArray).items !== undefined; | ||
export const isTuple = ( | ||
@@ -57,2 +63,3 @@ schema: OpenApi.IJsonSchema, | ||
(schema as OpenApi.IJsonSchema.ITuple).prefixItems !== undefined; | ||
export const isObject = ( | ||
@@ -62,2 +69,3 @@ schema: OpenApi.IJsonSchema, | ||
(schema as OpenApi.IJsonSchema.IObject).type === "object"; | ||
export const isReference = ( | ||
@@ -67,2 +75,3 @@ schema: OpenApi.IJsonSchema, | ||
(schema as any).$ref !== undefined; | ||
export const isOneOf = ( | ||
@@ -73,5 +82,36 @@ schema: OpenApi.IJsonSchema, | ||
export const isRecursiveReference = (props: { | ||
components: OpenApi.IComponents; | ||
schema: OpenApi.IJsonSchema; | ||
}): boolean => { | ||
if (isReference(props.schema) === false) return false; | ||
const counter: Map<string, number> = new Map(); | ||
visit({ | ||
components: props.components, | ||
schema: props.schema, | ||
closure: (schema) => { | ||
if (OpenApiTypeChecker.isReference(schema)) { | ||
const key: string = schema.$ref.split("#/components/schemas/")[1]; | ||
counter.set(key, (counter.get(key) ?? 0) + 1); | ||
} | ||
}, | ||
}); | ||
return Array.from(counter.values()).some((v) => v > 1); | ||
}; | ||
/* ----------------------------------------------------------- | ||
OPERATORS | ||
----------------------------------------------------------- */ | ||
export const escape = (props: { | ||
components: OpenApi.IComponents; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
}): OpenApi.IJsonSchema | null => | ||
escapeSchema({ | ||
components: props.components, | ||
schema: props.schema, | ||
recursive: props.recursive, | ||
visited: new Map(), | ||
}) || null; | ||
export const visit = (props: { | ||
@@ -125,2 +165,159 @@ closure: (schema: OpenApi.IJsonSchema) => void; | ||
const escapeSchema = (props: { | ||
components: OpenApi.IComponents; | ||
schema: OpenApi.IJsonSchema; | ||
recursive: false | number; | ||
visited: Map<string, number>; | ||
}): OpenApi.IJsonSchema | null | undefined => { | ||
if (isReference(props.schema)) { | ||
// REFERENCE | ||
const name: string = props.schema.$ref.split("#/components/schemas/")[1]; | ||
const target: OpenApi.IJsonSchema | undefined = | ||
props.components.schemas?.[name]; | ||
if (target === undefined) return null; | ||
else if (props.visited.has(name) === true) { | ||
if (props.recursive === false) return null; | ||
const depth: number = props.visited.get(name)!; | ||
if (depth > props.recursive) return undefined; | ||
props.visited.set(name, depth + 1); | ||
return escapeSchema({ | ||
components: props.components, | ||
schema: target, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}); | ||
} | ||
return escapeSchema({ | ||
components: props.components, | ||
schema: target, | ||
recursive: props.recursive, | ||
visited: new Map([...props.visited, [name, 1]]), | ||
}); | ||
} else if (isOneOf(props.schema)) { | ||
// UNION | ||
const elements: Array<OpenApi.IJsonSchema | null | undefined> = | ||
props.schema.oneOf.map((schema) => | ||
escapeSchema({ | ||
components: props.components, | ||
schema: schema, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}), | ||
); | ||
if (elements.some((v) => v === null)) return null; | ||
const filtered: OpenApi.IJsonSchema[] = elements.filter( | ||
(v) => v !== undefined, | ||
) as OpenApi.IJsonSchema[]; | ||
if (filtered.length === 0) return undefined; | ||
return { | ||
...props, | ||
oneOf: filtered.map((v) => flat(props.components, v)).flat(), | ||
}; | ||
} else if (isObject(props.schema)) { | ||
// OBJECT | ||
const object: OpenApi.IJsonSchema.IObject = props.schema; | ||
const properties: Array< | ||
[string, OpenApi.IJsonSchema | null | undefined] | ||
> = Object.entries(object.properties ?? {}).map(([key, value]) => [ | ||
key, | ||
escapeSchema({ | ||
components: props.components, | ||
schema: value, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}), | ||
]); | ||
const additionalProperties: | ||
| OpenApi.IJsonSchema | ||
| null | ||
| boolean | ||
| undefined = object.additionalProperties | ||
? typeof object.additionalProperties === "object" && | ||
object.additionalProperties !== null | ||
? escapeSchema({ | ||
components: props.components, | ||
schema: object.additionalProperties, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}) | ||
: object.additionalProperties | ||
: false; | ||
if ( | ||
properties.some(([_k, v]) => v === null) || | ||
additionalProperties === null | ||
) | ||
return null; | ||
else if ( | ||
properties.some( | ||
([k, v]) => v === undefined && object.required?.includes(k) === true, | ||
) === true | ||
) | ||
return undefined; | ||
return { | ||
...object, | ||
properties: Object.fromEntries( | ||
properties.filter(([_k, v]) => v !== undefined) as Array< | ||
[string, OpenApi.IJsonSchema] | ||
>, | ||
), | ||
additionalProperties: additionalProperties ?? false, | ||
required: object.required?.filter((k) => | ||
properties.some(([key, value]) => key === k && value !== undefined), | ||
), | ||
}; | ||
} else if (isTuple(props.schema)) { | ||
// TUPLE | ||
const elements: Array<OpenApi.IJsonSchema | null | undefined> = | ||
props.schema.prefixItems.map((schema) => | ||
escapeSchema({ | ||
components: props.components, | ||
schema: schema, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}), | ||
); | ||
const additionalItems: OpenApi.IJsonSchema | null | boolean | undefined = | ||
props.schema.additionalItems | ||
? typeof props.schema.additionalItems === "object" && | ||
props.schema.additionalItems !== null | ||
? escapeSchema({ | ||
components: props.components, | ||
schema: props.schema.additionalItems, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}) | ||
: props.schema.additionalItems | ||
: false; | ||
if (elements.some((v) => v === null) || additionalItems === null) | ||
return null; | ||
else if (elements.some((v) => v === undefined)) return undefined; | ||
return { | ||
...props.schema, | ||
prefixItems: elements as OpenApi.IJsonSchema[], | ||
additionalItems: additionalItems ?? false, | ||
}; | ||
} else if (isArray(props.schema)) { | ||
// ARRAY | ||
const items: OpenApi.IJsonSchema | null | undefined = escapeSchema({ | ||
components: props.components, | ||
schema: props.schema.items, | ||
recursive: props.recursive, | ||
visited: props.visited, | ||
}); | ||
if (items === null) return null; | ||
else if (items === undefined) | ||
return { | ||
...props.schema, | ||
minItems: undefined, | ||
maxItems: 0, | ||
items: {}, | ||
}; | ||
return { | ||
...props.schema, | ||
items: items, | ||
}; | ||
} | ||
return props.schema; | ||
}; | ||
const coverStation = (p: { | ||
@@ -159,4 +356,4 @@ components: OpenApi.IComponents; | ||
// COMPARE WITH FLATTENING | ||
const alpha: OpenApi.IJsonSchema[] = flatSchema(p.components, p.x); | ||
const beta: OpenApi.IJsonSchema[] = flatSchema(p.components, p.y); | ||
const alpha: OpenApi.IJsonSchema[] = flat(p.components, p.x); | ||
const beta: OpenApi.IJsonSchema[] = flat(p.components, p.y); | ||
if (alpha.some((x) => isUnknown(x))) return true; | ||
@@ -395,23 +592,27 @@ else if (beta.some((x) => isUnknown(x))) return false; | ||
(x === "iri-reference" && y === "uri-reference"); | ||
} | ||
const flatSchema = ( | ||
components: OpenApi.IComponents, | ||
schema: OpenApi.IJsonSchema, | ||
): OpenApi.IJsonSchema[] => { | ||
schema = escapeReference(components, schema); | ||
if (isOneOf(schema)) | ||
return schema.oneOf.map((v) => flatSchema(components, v)).flat(); | ||
return [schema]; | ||
}; | ||
const flat = ( | ||
components: OpenApi.IComponents, | ||
schema: OpenApi.IJsonSchema, | ||
): OpenApi.IJsonSchema[] => { | ||
schema = escapeReference(components, schema); | ||
if (OpenApiTypeChecker.isOneOf(schema)) | ||
return schema.oneOf.map((v) => flat(components, v)).flat(); | ||
return [schema]; | ||
}; | ||
const escapeReference = ( | ||
components: OpenApi.IComponents, | ||
schema: OpenApi.IJsonSchema, | ||
): Exclude<OpenApi.IJsonSchema, OpenApi.IJsonSchema.IReference> => | ||
isReference(schema) | ||
? escapeReference( | ||
components, | ||
components.schemas![schema.$ref.replace("#/components/schemas/", "")], | ||
) | ||
: schema; | ||
} | ||
const escapeReference = ( | ||
components: OpenApi.IComponents, | ||
schema: OpenApi.IJsonSchema, | ||
): Exclude<OpenApi.IJsonSchema, OpenApi.IJsonSchema.IReference> => { | ||
if (OpenApiTypeChecker.isReference(schema) === false) return schema; | ||
const key = schema.$ref.replace("#/components/schemas/", ""); | ||
const found: OpenApi.IJsonSchema | undefined = escapeReference( | ||
components, | ||
components.schemas?.[key] ?? {}, | ||
); | ||
if (found === undefined) | ||
throw new Error(`Reference not found: ${JSON.stringify(schema.$ref)}`); | ||
return escapeReference(components, found); | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
1359484
23687