| 178 | const MAX_SHAPE_JSON_CHARS = 16_000; |
| 179 | |
| 180 | const shrink = (shape: InferredShape, depth: number): InferredShape => { |
| 181 | if (depth <= 0) return UNKNOWN; |
| 182 | if (shape.anyOf) return { anyOf: shape.anyOf.map((branch) => shrink(branch, depth - 1)) }; |
| 183 | if (shape.type === "array" && shape.items) { |
| 184 | return { type: "array", items: shrink(shape.items, depth - 1) }; |
| 185 | } |
| 186 | if (shape.type === "object" && shape.additionalProperties) { |
| 187 | return { type: "object", additionalProperties: shrink(shape.additionalProperties, depth - 1) }; |
| 188 | } |
| 189 | if (shape.type === "object" && shape.properties) { |
| 190 | const properties: Record<string, InferredShape> = {}; |
| 191 | for (const [key, child] of Object.entries(shape.properties)) { |
| 192 | properties[key] = shrink(child, depth - 1); |
| 193 | } |
| 194 | return { ...shape, properties }; |
| 195 | } |
| 196 | return shape; |
| 197 | }; |
| 198 | |
| 199 | /** Fold a new observation into an existing record, keeping the result bounded. */ |
| 200 | export const observeShape = ( |