+12








fcd7c979df
Co-authored-by: Artur <145776561+arturict@users.noreply.github.com> Co-authored-by: arturict <arturict@users.noreply.github.com> Co-authored-by: Thomas <thomas@ajnart.fr> Co-authored-by: Afonso Jorge Ramos <afonsojorgeramos@gmail.com> Co-authored-by: Danura30082 <danura30082+github@gmail.com> Co-authored-by: Kushie <122986913+kushiemoon-dev@users.noreply.github.com> Co-authored-by: ajnart <thomas@ajnart.fr> Co-authored-by: ajnart <thomas@ajnart.dev> Co-authored-by: chenjun <chenjun@foxmail.com> Co-authored-by: Wikibear <wikibear@users.noreply.github.com> Co-authored-by: Bergasha <bergasha@gmail.com> Co-authored-by: leafyelin <43306196+leafyelin@users.noreply.github.com> Co-authored-by: Lucas Araujo <lucas.lra@gmail.com> Co-authored-by: GreenMonito <86085570+GreenMonito@users.noreply.github.com> Co-authored-by: Nerdy-Technician <roffo@nerdy-technician.social> Co-authored-by: Jun <34545896+jcstrong@users.noreply.github.com> Co-authored-by: Edmond Abraham <54119952+gitedmond@users.noreply.github.com> Co-authored-by: thrawnx <tight.bulb9384@fastmail.com> Co-authored-by: Chris <58918656+nordada@users.noreply.github.com> Co-authored-by: yi111 <153097222+Yi-111-a@users.noreply.github.com> Co-authored-by: Yanis <naamaneyanis@gmail.com> Co-authored-by: Wikibear <me@sej.de> Co-authored-by: alessiottavo <93441886+alessiottavo@users.noreply.github.com>
93 lines
3.1 KiB
TypeScript
93 lines
3.1 KiB
TypeScript
type RecordValue = Record<string, unknown>;
|
|
|
|
function asRecord(value: unknown): RecordValue | undefined {
|
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
|
|
return value as RecordValue;
|
|
}
|
|
|
|
function hasExactKeys(value: RecordValue, keys: string[]) {
|
|
const actual = Object.keys(value).toSorted();
|
|
const expected = keys.toSorted();
|
|
if (actual.length !== expected.length) return false;
|
|
return actual.every((key, index) => key === expected[index]);
|
|
}
|
|
|
|
function isUnconstrainedRecursiveJsonSchema(name: string, value: unknown) {
|
|
const root = asRecord(value);
|
|
if (!root || !hasExactKeys(root, ["anyOf"]) || !Array.isArray(root.anyOf)) return false;
|
|
if (root.anyOf.length !== 6) return false;
|
|
|
|
const simpleTypes = new Set<string>();
|
|
let hasArray = false;
|
|
let hasObject = false;
|
|
const self = `#/components/schemas/${name.replaceAll("~", "~0").replaceAll("/", "~1")}`;
|
|
|
|
for (const member of root.anyOf) {
|
|
const variant = asRecord(member);
|
|
if (!variant) return false;
|
|
if (typeof variant.type === "string" && hasExactKeys(variant, ["type"])) {
|
|
simpleTypes.add(variant.type);
|
|
continue;
|
|
}
|
|
if (variant.type === "array" && hasExactKeys(variant, ["type", "items"])) {
|
|
const items = asRecord(variant.items);
|
|
if (!items || !hasExactKeys(items, ["$ref"]) || items.$ref !== self) return false;
|
|
hasArray = true;
|
|
continue;
|
|
}
|
|
if (variant.type === "object" && hasExactKeys(variant, ["type", "propertyNames", "additionalProperties"])) {
|
|
const propertyNames = asRecord(variant.propertyNames);
|
|
const additionalProperties = asRecord(variant.additionalProperties);
|
|
if (!propertyNames || !hasExactKeys(propertyNames, ["type"]) || propertyNames.type !== "string") return false;
|
|
if (!additionalProperties || !hasExactKeys(additionalProperties, ["$ref"]) || additionalProperties.$ref !== self)
|
|
return false;
|
|
hasObject = true;
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return (
|
|
simpleTypes.size === 4 &&
|
|
simpleTypes.has("string") &&
|
|
simpleTypes.has("number") &&
|
|
simpleTypes.has("boolean") &&
|
|
simpleTypes.has("null") &&
|
|
hasArray &&
|
|
hasObject
|
|
);
|
|
}
|
|
|
|
/** Scalar cannot render the generator's unconstrained, self-recursive JSON union. */
|
|
export function normalizeRecursiveJsonSchemasForScalar<T extends object>(document: T): T {
|
|
const root = asRecord(document);
|
|
const components = asRecord(root?.components);
|
|
const schemas = asRecord(components?.schemas);
|
|
if (!components || !schemas) return document;
|
|
|
|
const normalizedSchemas = { ...schemas };
|
|
let changed = false;
|
|
for (const [name, value] of Object.entries(schemas)) {
|
|
if (!isUnconstrainedRecursiveJsonSchema(name, value)) continue;
|
|
normalizedSchemas[name] = {
|
|
anyOf: [
|
|
{ type: "string" },
|
|
{ type: "number" },
|
|
{ type: "boolean" },
|
|
{ type: "null" },
|
|
{ type: "array" },
|
|
{ type: "object" },
|
|
],
|
|
};
|
|
changed = true;
|
|
}
|
|
if (!changed) return document;
|
|
return {
|
|
...document,
|
|
components: {
|
|
...components,
|
|
schemas: normalizedSchemas,
|
|
},
|
|
} as T;
|
|
}
|