(ast: AST)
| 2582 | |
| 2583 | /** @internal */ |
| 2584 | export function collectSentinels(ast: AST): ReadonlyArray<Sentinel> { |
| 2585 | switch (ast._tag) { |
| 2586 | default: |
| 2587 | return [] |
| 2588 | case "Declaration": { |
| 2589 | const s = ast.annotations?.[InternalAnnotations.SENTINELS_ANNOTATION_KEY] |
| 2590 | return Array.isArray(s) ? s : [] |
| 2591 | } |
| 2592 | case "Objects": |
| 2593 | return ast.propertySignatures.flatMap((ps): Array<Sentinel> => { |
| 2594 | const type = ps.type |
| 2595 | if (!isOptional(type)) { |
| 2596 | if (isLiteral(type)) { |
| 2597 | return [{ key: ps.name, literal: type.literal }] |
| 2598 | } |
| 2599 | if (isUniqueSymbol(type)) { |
| 2600 | return [{ key: ps.name, literal: type.symbol }] |
| 2601 | } |
| 2602 | } |
| 2603 | return [] |
| 2604 | }) |
| 2605 | case "Arrays": |
| 2606 | return ast.elements.flatMap((e, i): Array<Sentinel> => { |
| 2607 | if (!isOptional(e)) { |
| 2608 | if (isLiteral(e)) { |
| 2609 | return [{ key: i, literal: e.literal }] |
| 2610 | } |
| 2611 | if (isUniqueSymbol(e)) { |
| 2612 | return [{ key: i, literal: e.symbol }] |
| 2613 | } |
| 2614 | } |
| 2615 | return [] |
| 2616 | }) |
| 2617 | case "Union": { |
| 2618 | if (ast.types.length === 0) return [] |
| 2619 | const members = ast.types.map((type) => collectSentinels(toCandidate(type))) |
| 2620 | return members[0].filter((s) => |
| 2621 | members.every((sentinels) => sentinels.some((o) => o.key === s.key && o.literal === s.literal)) |
| 2622 | ) |
| 2623 | } |
| 2624 | case "Suspend": |
| 2625 | return collectSentinels(ast.thunk()) |
| 2626 | } |
| 2627 | } |
| 2628 | |
| 2629 | type CandidateIndex = (input: any, isConstructor: boolean) => ReadonlyArray<AST> |
| 2630 | type SentinelEntry = readonly [ |
no test coverage detected