@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
288 lines (287 loc) • 11.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatGptTypeChecker = void 0;
const MapUtil_1 = require("./MapUtil");
var ChatGptTypeChecker;
(function (ChatGptTypeChecker) {
/* -----------------------------------------------------------
TYPE CHECKERS
----------------------------------------------------------- */
/**
* Test whether the schema is a nul type.
*
* @param schema Target schema
* @returns Whether null type or not
*/
ChatGptTypeChecker.isNull = (schema) => schema.type === "null";
/**
* Test whether the schema is an unknown type.
*
* @param schema Target schema
* @returns Whether unknown type or not
*/
ChatGptTypeChecker.isUnknown = (schema) => schema.type === undefined &&
!ChatGptTypeChecker.isAnyOf(schema) &&
!ChatGptTypeChecker.isReference(schema);
/**
* Test whether the schema is a boolean type.
*
* @param schema Target schema
* @returns Whether boolean type or not
*/
ChatGptTypeChecker.isBoolean = (schema) => schema.type === "boolean";
/**
* Test whether the schema is an integer type.
*
* @param schema Target schema
* @returns Whether integer type or not
*/
ChatGptTypeChecker.isInteger = (schema) => schema.type === "integer";
/**
* Test whether the schema is a number type.
*
* @param schema Target schema
* @returns Whether number type or not
*/
ChatGptTypeChecker.isNumber = (schema) => schema.type === "number";
/**
* Test whether the schema is a string type.
*
* @param schema Target schema
* @returns Whether string type or not
*/
ChatGptTypeChecker.isString = (schema) => schema.type === "string";
/**
* Test whether the schema is an array type.
*
* @param schema Target schema
* @returns Whether array type or not
*/
ChatGptTypeChecker.isArray = (schema) => schema.type === "array" &&
schema.items !== undefined;
/**
* Test whether the schema is an object type.
*
* @param schema Target schema
* @returns Whether object type or not
*/
ChatGptTypeChecker.isObject = (schema) => schema.type === "object";
/**
* Test whether the schema is a reference type.
*
* @param schema Target schema
* @returns Whether reference type or not
*/
ChatGptTypeChecker.isReference = (schema) => schema.$ref !== undefined;
/**
* Test whether the schema is an union type.
*
* @param schema Target schema
* @returns Whether union type or not
*/
ChatGptTypeChecker.isAnyOf = (schema) => schema.anyOf !== undefined;
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
/**
* Visit every nested schemas.
*
* Visit every nested schemas of the target, and apply the `props.closure` function.
*
* Here is the list of occurring nested visitings:
*
* - {@link IChatGptSchema.IAnyOf.anyOf}
* - {@link IChatGptSchema.IReference}
* - {@link IChatGptSchema.IObject.properties}
* - {@link IChatGptSchema.IArray.items}
*
* @param props Properties for visiting
*/
ChatGptTypeChecker.visit = (props) => {
var _a, _b;
const already = new Set();
const refAccessor = (_a = props.refAccessor) !== null && _a !== void 0 ? _a : "$input.$defs";
const next = (schema, accessor) => {
var _a;
props.closure(schema, accessor);
if (ChatGptTypeChecker.isReference(schema)) {
const key = schema.$ref.split("#/$defs/").pop();
if (already.has(key) === true)
return;
already.add(key);
const found = (_a = props.$defs) === null || _a === void 0 ? void 0 : _a[key];
if (found !== undefined)
next(found, `${refAccessor}[${key}]`);
}
else if (ChatGptTypeChecker.isAnyOf(schema))
schema.anyOf.forEach((s, i) => next(s, `${accessor}.anyOf[${i}]`));
else if (ChatGptTypeChecker.isObject(schema)) {
for (const [key, value] of Object.entries(schema.properties))
next(value, `${accessor}.properties[${JSON.stringify(key)}]`);
if (typeof schema.additionalProperties === "object" &&
schema.additionalProperties !== null)
next(schema.additionalProperties, `${accessor}.additionalProperties`);
}
else if (ChatGptTypeChecker.isArray(schema))
next(schema.items, `${accessor}.items`);
};
next(props.schema, (_b = props.accessor) !== null && _b !== void 0 ? _b : "$input.schemas");
};
/**
* Test whether the `x` schema covers the `y` schema.
*
* @param props Properties for testing
* @returns Whether the `x` schema covers the `y` schema
*/
ChatGptTypeChecker.covers = (props) => coverStation({
$defs: props.$defs,
x: props.x,
y: props.y,
visited: new Map(),
});
const coverStation = (p) => {
var _a;
const cache = (_a = p.visited.get(p.x)) === null || _a === void 0 ? void 0 : _a.get(p.y);
if (cache !== undefined)
return cache;
// FOR RECURSIVE CASE
const nested = MapUtil_1.MapUtil.take(p.visited)(p.x)(() => new Map());
nested.set(p.y, true);
// COMPUTE IT
const result = coverSchema(p);
nested.set(p.y, result);
return result;
};
const coverSchema = (p) => {
// CHECK EQUALITY
if (p.x === p.y)
return true;
else if (ChatGptTypeChecker.isReference(p.x) && ChatGptTypeChecker.isReference(p.y) && p.x.$ref === p.y.$ref)
return true;
// COMPARE WITH FLATTENING
const alpha = flatSchema(p.$defs, p.x);
const beta = flatSchema(p.$defs, p.y);
if (alpha.some((x) => ChatGptTypeChecker.isUnknown(x)))
return true;
else if (beta.some((x) => ChatGptTypeChecker.isUnknown(x)))
return false;
return beta.every((b) => alpha.some((a) => coverEscapedSchema({
$defs: p.$defs,
visited: p.visited,
x: a,
y: b,
})));
};
const coverEscapedSchema = (p) => {
// CHECK EQUALITY
if (p.x === p.y)
return true;
else if (ChatGptTypeChecker.isUnknown(p.x))
return true;
else if (ChatGptTypeChecker.isUnknown(p.y))
return false;
else if (ChatGptTypeChecker.isNull(p.x))
return ChatGptTypeChecker.isNull(p.y);
// ATOMIC CASE
else if (ChatGptTypeChecker.isBoolean(p.x))
return ChatGptTypeChecker.isBoolean(p.y) && coverBoolean(p.x, p.y);
else if (ChatGptTypeChecker.isInteger(p.x))
return ChatGptTypeChecker.isInteger(p.y) && coverInteger(p.x, p.y);
else if (ChatGptTypeChecker.isNumber(p.x))
return ChatGptTypeChecker.isNumber(p.y) && coverNumber(p.x, p.y);
else if (ChatGptTypeChecker.isString(p.x))
return ChatGptTypeChecker.isString(p.y) && coverString(p.x, p.y);
// INSTANCE CASE
else if (ChatGptTypeChecker.isArray(p.x))
return (ChatGptTypeChecker.isArray(p.y) &&
coverArray({
$defs: p.$defs,
visited: p.visited,
x: p.x,
y: p.y,
}));
else if (ChatGptTypeChecker.isObject(p.x))
return (ChatGptTypeChecker.isObject(p.y) &&
coverObject({
$defs: p.$defs,
visited: p.visited,
x: p.x,
y: p.y,
}));
else if (ChatGptTypeChecker.isReference(p.x))
return ChatGptTypeChecker.isReference(p.y) && p.x.$ref === p.y.$ref;
return false;
};
const coverArray = (p) => coverStation({
$defs: p.$defs,
visited: p.visited,
x: p.x.items,
y: p.y.items,
});
const coverObject = (p) => {
var _a;
if (!p.x.additionalProperties && !!p.y.additionalProperties)
return false;
else if (!!p.x.additionalProperties &&
!!p.y.additionalProperties &&
((typeof p.x.additionalProperties === "object" &&
p.y.additionalProperties === true) ||
(typeof p.x.additionalProperties === "object" &&
typeof p.y.additionalProperties === "object" &&
!coverStation({
$defs: p.$defs,
visited: p.visited,
x: p.x.additionalProperties,
y: p.y.additionalProperties,
}))))
return false;
return Object.entries((_a = p.y.properties) !== null && _a !== void 0 ? _a : {}).every(([key, b]) => {
var _a, _b, _c, _d, _e;
const a = (_a = p.x.properties) === null || _a === void 0 ? void 0 : _a[key];
if (a === undefined)
return false;
else if (((_c = (_b = p.x.required) === null || _b === void 0 ? void 0 : _b.includes(key)) !== null && _c !== void 0 ? _c : false) === true &&
((_e = (_d = p.y.required) === null || _d === void 0 ? void 0 : _d.includes(key)) !== null && _e !== void 0 ? _e : false) === false)
return false;
return coverStation({
$defs: p.$defs,
visited: p.visited,
x: a,
y: b,
});
});
};
const coverBoolean = (x, y) => {
var _a, _b;
if (!!((_a = x.enum) === null || _a === void 0 ? void 0 : _a.length))
return !!((_b = y.enum) === null || _b === void 0 ? void 0 : _b.length) && y.enum.every((v) => x.enum.includes(v));
return true;
};
const coverInteger = (x, y) => {
var _a, _b;
if (!!((_a = x.enum) === null || _a === void 0 ? void 0 : _a.length))
return !!((_b = y.enum) === null || _b === void 0 ? void 0 : _b.length) && y.enum.every((v) => x.enum.includes(v));
return x.type === y.type;
};
const coverNumber = (x, y) => {
var _a, _b;
if (!!((_a = x.enum) === null || _a === void 0 ? void 0 : _a.length))
return !!((_b = y.enum) === null || _b === void 0 ? void 0 : _b.length) && y.enum.every((v) => x.enum.includes(v));
return x.type === y.type || (x.type === "number" && y.type === "integer");
};
const coverString = (x, y) => {
var _a, _b;
if (!!((_a = x.enum) === null || _a === void 0 ? void 0 : _a.length))
return !!((_b = y.enum) === null || _b === void 0 ? void 0 : _b.length) && y.enum.every((v) => x.enum.includes(v));
return x.type === y.type;
};
const flatSchema = ($defs, schema) => {
schema = escapeReference($defs, schema);
if (ChatGptTypeChecker.isAnyOf(schema))
return schema.anyOf.map((v) => flatSchema($defs, v)).flat();
return [schema];
};
const escapeReference = ($defs, schema) => ChatGptTypeChecker.isReference(schema)
? escapeReference($defs, $defs[schema.$ref.replace("#/$defs/", "")])
: schema;
})(ChatGptTypeChecker || (exports.ChatGptTypeChecker = ChatGptTypeChecker = {}));
;