UNPKG

@mintlify/validation

Version:

Validates mint.json files

195 lines (194 loc) 7.29 kB
import hash from 'object-hash'; import { v4 as uuidv4 } from 'uuid'; export const replaceSchemaRefs = ({ schema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap = new WeakMap(), }) => { if ('$ref' in schema) { const refId = schema.$ref; const uuid = refUuidMap[refId] || uuidv4(); schema.$ref = uuid; return; } if (schemaToUuidMap.has(schema)) { const value = schemaToUuidMap.get(schema); if (value === '') { // circular reference found at the top level without processing children return; } else { return; } } schemaToUuidMap.set(schema, ''); if ('properties' in schema && schema.properties && typeof schema.properties === 'object') { Object.entries(schema.properties).forEach(([propName, subschema]) => { var _a; if (typeof subschema !== 'object' || subschema === null) { return; } const childUuid = processChildSchema({ childSchema: subschema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }); if (childUuid && ((_a = schema.properties) === null || _a === void 0 ? void 0 : _a[propName])) { // eslint-disable-next-line @typescript-eslint/no-explicit-any schema.properties[propName] = childUuid; } }); } if ('items' in schema && schema.items && typeof schema.items === 'object') { const childUuid = processChildSchema({ childSchema: schema.items, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }); if (childUuid) { // eslint-disable-next-line @typescript-eslint/no-explicit-any schema.items = childUuid; } } if ('additionalProperties' in schema && typeof schema.additionalProperties === 'object') { const childUuid = processChildSchema({ childSchema: schema.additionalProperties, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }); if (childUuid) { // eslint-disable-next-line @typescript-eslint/no-explicit-any schema.additionalProperties = childUuid; } } if ('oneOf' in schema && schema.oneOf && Array.isArray(schema.oneOf)) { schema.oneOf.forEach((subschema, index) => { var _a; if (typeof subschema !== 'object') { return; } const childUuid = processChildSchema({ childSchema: subschema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }); if (childUuid && ((_a = schema.oneOf) === null || _a === void 0 ? void 0 : _a[index])) { // eslint-disable-next-line @typescript-eslint/no-explicit-any schema.oneOf[index] = childUuid; } }); } if ('anyOf' in schema && schema.anyOf && Array.isArray(schema.anyOf)) { schema.anyOf.forEach((subschema, index) => { var _a; if (typeof subschema !== 'object') { return; } const childUuid = processChildSchema({ childSchema: subschema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }); if (childUuid && ((_a = schema.anyOf) === null || _a === void 0 ? void 0 : _a[index])) { // eslint-disable-next-line @typescript-eslint/no-explicit-any schema.anyOf[index] = childUuid; } }); } if ('allOf' in schema && schema.allOf && Array.isArray(schema.allOf)) { schema.allOf.forEach((subschema, index) => { var _a; if (typeof subschema !== 'object') { return; } const childUuid = processChildSchema({ childSchema: subschema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }); if (childUuid && ((_a = schema.allOf) === null || _a === void 0 ? void 0 : _a[index])) { // eslint-disable-next-line @typescript-eslint/no-explicit-any schema.allOf[index] = childUuid; } }); } if ('not' in schema && schema.not && typeof schema.not === 'object') { const childUuid = processChildSchema({ childSchema: schema.not, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }); if (childUuid) { // eslint-disable-next-line @typescript-eslint/no-explicit-any schema.not = childUuid; } } }; const processChildSchema = ({ childSchema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }) => { if (typeof childSchema !== 'object') { return; } // preserve sibling properties when resolving $ref if ('$ref' in childSchema) { const refId = childSchema.$ref; const refUuid = refUuidMap[refId] || uuidv4(); // if no siblings, safe to return ref uuid directly const siblingKeys = Object.keys(childSchema).filter((key) => key !== '$ref'); if (siblingKeys.length === 0) { return refUuid; } // otherwise make new schema node with $ref and adjacent properties const childUuid = uuidv4(); childSchema.$ref = refUuid; const objectHash = hash(childSchema); if (objectHash in hashedNodeMap) { uuidObjectHashMap[childUuid] = objectHash; schemaToUuidMap.set(childSchema, childUuid); return childUuid; } uuidObjectHashMap[childUuid] = objectHash; hashedNodeMap[objectHash] = childSchema; schemaToUuidMap.set(childSchema, childUuid); return childUuid; } if (schemaToUuidMap.has(childSchema)) { // circular reference!! return existing uuid const existingUuid = schemaToUuidMap.get(childSchema); if (existingUuid) { return existingUuid; } } // assign new uuid for child const childUuid = uuidv4(); const objectHash = hash(childSchema); // check if this exact schema already exists in the graph if (objectHash in hashedNodeMap) { // schema already exists, just map the uuid to it uuidObjectHashMap[childUuid] = objectHash; schemaToUuidMap.set(childSchema, childUuid); return childUuid; } // add to the graph maps uuidObjectHashMap[childUuid] = objectHash; // recursively process the child schema before adding it to the graph replaceSchemaRefs({ schema: childSchema, refUuidMap, uuidObjectHashMap, hashedNodeMap, schemaToUuidMap, }); schemaToUuidMap.set(childSchema, childUuid); hashedNodeMap[objectHash] = childSchema; return childUuid; };