1414
1515from __future__ import annotations
1616
17- from typing import Any
17+ from typing import Any , TypeAlias , cast
1818
19+ JSONPrimitive : TypeAlias = None | str | int | float | bool
20+ JSONValue : TypeAlias = JSONPrimitive | list ["JSONValue" ] | dict [str , "JSONValue" ]
21+ JSONObject : TypeAlias = dict [str , JSONValue ]
1922
20- def dereference_local_refs (schema : dict [ str , Any ] ) -> dict [ str , Any ] :
23+ def dereference_local_refs (schema : JSONObject ) -> JSONObject :
2124 """Inline local ``$ref`` pointers in a JSON Schema.
2225
2326 Behavior mirrors ``dereferenceLocalRefs`` in the TypeScript SDK:
@@ -51,18 +54,24 @@ def dereference_local_refs(schema: dict[str, Any]) -> dict[str, Any]:
5154 else :
5255 return schema
5356
54- defs : dict [str , Any ] = schema [defs_key ] or {}
57+ raw_defs = schema [defs_key ]
58+ if raw_defs is None :
59+ return schema
60+ if not isinstance (raw_defs , dict ):
61+ return schema
62+
63+ defs : JSONObject = raw_defs
5564 if not defs :
5665 return schema
5766
5867 # Cache resolved defs to avoid redundant traversal on diamond references.
59- resolved_defs : dict [str , Any ] = {}
68+ resolved_defs : dict [str , JSONValue ] = {}
6069 # Def names where a cycle was detected — their $ref is left in place and
6170 # their $defs entries must be preserved in the output.
6271 cyclic_defs : set [str ] = set ()
6372 prefix = f"#/{ defs_key } /"
6473
65- def inline (node : Any , stack : set [str ]) -> Any :
74+ def inline (node : JSONValue , stack : set [str ]) -> JSONValue :
6675 if node is None or isinstance (node , str | int | float | bool ):
6776 return node
6877 if isinstance (node , list ):
@@ -95,14 +104,17 @@ def inline(node: Any, stack: set[str]) -> Any:
95104 resolved_defs [def_name ] = resolved
96105
97106 # Siblings of $ref (JSON Schema 2020-12).
98- siblings = {k : v for k , v in node .items () if k != "$ref" }
107+ siblings : JSONObject = {k : v for k , v in node .items () if k != "$ref" }
99108 if siblings and isinstance (resolved , dict ):
100- resolved_siblings = {k : inline (v , stack ) for k , v in siblings .items ()}
101- return {** resolved , ** resolved_siblings }
109+ resolved_schema = cast (JSONObject , resolved )
110+ resolved_siblings : JSONObject = {
111+ key : inline (value , stack ) for key , value in siblings .items ()
112+ }
113+ return {** resolved_schema , ** resolved_siblings }
102114 return resolved
103115
104116 # Regular object — recurse into values, but skip the top-level $defs container.
105- result : dict [ str , Any ] = {}
117+ result : JSONObject = {}
106118 for key , value in node .items ():
107119 if node is schema and key in ("$defs" , "definitions" ):
108120 continue
@@ -116,7 +128,7 @@ def inline(node: Any, stack: set[str]) -> Any:
116128
117129 # Preserve only cyclic defs in the output.
118130 if cyclic_defs :
119- preserved = {name : defs [name ] for name in cyclic_defs if name in defs }
131+ preserved : JSONObject = {name : defs [name ] for name in cyclic_defs if name in defs }
120132 inlined [defs_key ] = preserved
121133
122134 return inlined
0 commit comments