(schema: JSONSchema7)
| 820 | * Mutates `schema` in place and returns it. Idempotent. |
| 821 | */ |
| 822 | export function propagateInternalVisibility(schema: JSONSchema7): JSONSchema7 { |
| 823 | if (typeof schema !== "object" || schema === null) return schema; |
| 824 | |
| 825 | const { definitions, $defs } = collectDefinitionCollections(schema as Record<string, unknown>); |
| 826 | const allDefs: Record<string, JSONSchema7Definition> = { ...definitions, ...$defs }; |
| 827 | const internalTypeNames = new Set<string>(); |
| 828 | for (const [name, def] of Object.entries(allDefs)) { |
| 829 | if (def && typeof def === "object" && isSchemaInternal(def as JSONSchema7)) { |
| 830 | internalTypeNames.add(name); |
| 831 | } |
| 832 | } |
| 833 | if (internalTypeNames.size === 0) return schema; |
| 834 | |
| 835 | const refToName = (ref: unknown): string | undefined => { |
| 836 | if (typeof ref !== "string") return undefined; |
| 837 | const m = ref.match(/^#\/(?:definitions|\$defs)\/([^/]+)$/); |
| 838 | return m ? m[1] : undefined; |
| 839 | }; |
| 840 | |
| 841 | /** Returns true when a property's *direct* type carrier is an internal definition. */ |
| 842 | const propertyReferencesInternal = (propSchema: JSONSchema7): boolean => { |
| 843 | const direct = refToName((propSchema as Record<string, unknown>).$ref); |
| 844 | if (direct && internalTypeNames.has(direct)) return true; |
| 845 | const items = (propSchema as Record<string, unknown>).items; |
| 846 | if (items && typeof items === "object" && !Array.isArray(items)) { |
| 847 | const itemsRef = refToName((items as Record<string, unknown>).$ref); |
| 848 | if (itemsRef && internalTypeNames.has(itemsRef)) return true; |
| 849 | } |
| 850 | const addl = (propSchema as Record<string, unknown>).additionalProperties; |
| 851 | if (addl && typeof addl === "object") { |
| 852 | const addlRef = refToName((addl as Record<string, unknown>).$ref); |
| 853 | if (addlRef && internalTypeNames.has(addlRef)) return true; |
| 854 | } |
| 855 | return false; |
| 856 | }; |
| 857 | |
| 858 | const visit = (node: unknown): void => { |
| 859 | if (!node || typeof node !== "object") return; |
| 860 | if (Array.isArray(node)) { |
| 861 | for (const item of node) visit(item); |
| 862 | return; |
| 863 | } |
| 864 | const record = node as Record<string, unknown>; |
| 865 | const props = record.properties; |
| 866 | if (props && typeof props === "object" && !Array.isArray(props)) { |
| 867 | for (const propSchema of Object.values(props as Record<string, unknown>)) { |
| 868 | if (!propSchema || typeof propSchema !== "object") continue; |
| 869 | if (!isSchemaInternal(propSchema as JSONSchema7) && propertyReferencesInternal(propSchema as JSONSchema7)) { |
| 870 | (propSchema as Record<string, unknown>).visibility = "internal"; |
| 871 | } |
| 872 | visit(propSchema); |
| 873 | } |
| 874 | } |
| 875 | for (const key of ["items", "additionalProperties", "anyOf", "allOf", "oneOf"]) { |
| 876 | if (record[key]) visit(record[key]); |
| 877 | } |
| 878 | for (const collectionKey of ["definitions", "$defs"]) { |
| 879 | const collection = record[collectionKey]; |
no test coverage detected
searching dependent graphs…