type JsonObject = Record; type RefHintValue = string | JsonObject; type DiscoveryTypingLike = { inputSchema?: unknown; outputSchema?: unknown; }; const isJsonObject = (value: unknown): value is JsonObject => typeof value === "object" && value !== null && !Array.isArray(value); const parseJson = (value: string): unknown | null => { try { return JSON.parse(value) as unknown; } catch { return null; } }; const resolveSchemaNode = ( value: unknown, refHintTable: Readonly>, parsedHintCache: Map, activeRefs: ReadonlySet, ): unknown => { if (Array.isArray(value)) { return value.map((item) => resolveSchemaNode(item, refHintTable, parsedHintCache, activeRefs) ); } if (!isJsonObject(value)) { return value; } const ref = typeof value.$ref === "string" ? value.$ref : null; if (ref && ref.startsWith("#/") && !activeRefs.has(ref)) { let resolvedRefValue = parsedHintCache.get(ref); if (resolvedRefValue === undefined) { const rawHint = refHintTable[ref]; resolvedRefValue = typeof rawHint === "string" ? parseJson(rawHint) : isJsonObject(rawHint) ? rawHint : null; parsedHintCache.set(ref, resolvedRefValue); } if (resolvedRefValue !== null && resolvedRefValue !== undefined) { const nextActiveRefs = new Set(activeRefs); nextActiveRefs.add(ref); const { $ref: _ignoredRef, ...rest } = value; const resolvedTarget = resolveSchemaNode( resolvedRefValue, refHintTable, parsedHintCache, nextActiveRefs, ); if (Object.keys(rest).length === 0) { return resolvedTarget; } const resolvedRest = resolveSchemaNode( rest, refHintTable, parsedHintCache, activeRefs, ); if (isJsonObject(resolvedTarget) && isJsonObject(resolvedRest)) { return { ...resolvedTarget, ...resolvedRest }; } return resolvedTarget; } } const next: JsonObject = {}; for (const [key, nestedValue] of Object.entries(value)) { next[key] = resolveSchemaNode( nestedValue, refHintTable, parsedHintCache, activeRefs, ); } return next; }; export const resolveSchemaWithRefHints = ( schema: unknown, refHintTable: Readonly> | undefined, ): unknown | null => { if (schema === undefined || schema === null) { return null; } if (!refHintTable || Object.keys(refHintTable).length === 0) { return schema; } const resolved = resolveSchemaNode( schema, refHintTable, new Map(), new Set(), ); return resolved; }; export const resolveTypingSchemasWithRefHints = ( typing: DiscoveryTypingLike | undefined, refHintTable: Readonly> | undefined, ): { inputSchema: unknown | null; outputSchema: unknown | null; } => ({ inputSchema: resolveSchemaWithRefHints( typing?.inputSchema, refHintTable, ), outputSchema: resolveSchemaWithRefHints( typing?.outputSchema, refHintTable, ), });