(value: unknown, visited: Set<unknown> = new Set())
| 438 | } |
| 439 | |
| 440 | function isJsonValue(value: unknown, visited: Set<unknown> = new Set()): value is JsonValue { |
| 441 | if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") { |
| 442 | return true |
| 443 | } |
| 444 | if (Array.isArray(value) || typeof value === "object") { |
| 445 | // Check for cyclic references |
| 446 | if (visited.has(value)) { |
| 447 | return false |
| 448 | } |
| 449 | visited.add(value) |
| 450 | try { |
| 451 | if (Array.isArray(value)) { |
| 452 | return value.every((item) => isJsonValue(item, visited)) |
| 453 | } |
| 454 | // Exclude non-plain objects (Date, RegExp, etc.) by checking constructor |
| 455 | const proto = Object.getPrototypeOf(value) |
| 456 | if (proto !== null && proto !== Object.prototype) { |
| 457 | return false |
| 458 | } |
| 459 | // JSON only allows string keys, so exclude objects with Symbol keys |
| 460 | if (Object.getOwnPropertySymbols(value).length > 0) { |
| 461 | return false |
| 462 | } |
| 463 | // Check all values are JSON values |
| 464 | return Object.values(value).every((v) => isJsonValue(v, visited)) |
| 465 | } finally { |
| 466 | visited.delete(value) |
| 467 | } |
| 468 | } |
| 469 | return false |
| 470 | } |
| 471 | |
| 472 | function pruneJsonSchemaAnnotations( |
| 473 | ast: AST.AST, |
no test coverage detected