@@ -103,127 +103,71 @@ impl ParseDocument<'_> for crate::SchemaRef {
103103// ============================================================================
104104
105105/// Parsed integer schema - syntactic representation with range as string.
106- #[ derive( Debug , Clone ) ]
106+ #[ derive( Debug , Clone , eure_macros:: ParseDocument ) ]
107+ #[ eure( crate = eure_document, rename_all = "kebab-case" ) ]
107108pub struct ParsedIntegerSchema {
108109 /// Range constraint as string (e.g., "[0, 100)", "(-∞, 0]")
110+ #[ eure( default ) ]
109111 pub range : Option < String > ,
110112 /// Multiple-of constraint
113+ #[ eure( default ) ]
111114 pub multiple_of : Option < BigInt > ,
112115}
113116
114- impl ParseDocument < ' _ > for ParsedIntegerSchema {
115- type Error = ParseError ;
116- fn parse ( ctx : & ParseContext < ' _ > ) -> Result < Self , Self :: Error > {
117- let rec = ctx. parse_record ( ) ?;
118- let range = rec. field_optional ( "range" ) ;
119- let multiple_of = rec. field_optional ( "multiple-of" ) ;
120- rec. allow_unknown_fields ( ) ?;
121- Ok ( ParsedIntegerSchema {
122- range : range. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
123- multiple_of : multiple_of. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
124- } )
125- }
126- }
127-
128117/// Parsed float schema - syntactic representation with range as string.
129- #[ derive( Debug , Clone ) ]
118+ #[ derive( Debug , Clone , eure_macros:: ParseDocument ) ]
119+ #[ eure( crate = eure_document, rename_all = "kebab-case" ) ]
130120pub struct ParsedFloatSchema {
131121 /// Range constraint as string
122+ #[ eure( default ) ]
132123 pub range : Option < String > ,
133124 /// Multiple-of constraint
125+ #[ eure( default ) ]
134126 pub multiple_of : Option < f64 > ,
135127 /// Precision constraint ("f32" or "f64")
128+ #[ eure( default ) ]
136129 pub precision : Option < String > ,
137130}
138131
139- impl ParseDocument < ' _ > for ParsedFloatSchema {
140- type Error = ParseError ;
141- fn parse ( ctx : & ParseContext < ' _ > ) -> Result < Self , Self :: Error > {
142- let rec = ctx. parse_record ( ) ?;
143- let range = rec. field_optional ( "range" ) ;
144- let multiple_of = rec. field_optional ( "multiple-of" ) ;
145- let precision = rec. field_optional ( "precision" ) ;
146- rec. allow_unknown_fields ( ) ?;
147- Ok ( ParsedFloatSchema {
148- range : range. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
149- multiple_of : multiple_of. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
150- precision : precision. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
151- } )
152- }
153- }
154-
155132/// Parsed array schema with NodeId references.
156- #[ derive( Debug , Clone ) ]
133+ #[ derive( Debug , Clone , eure_macros:: ParseDocument ) ]
134+ #[ eure( crate = eure_document, rename_all = "kebab-case" ) ]
157135pub struct ParsedArraySchema {
158136 /// Schema for array elements
159137 pub item : NodeId ,
160138 /// Minimum number of elements
139+ #[ eure( default ) ]
161140 pub min_length : Option < u32 > ,
162141 /// Maximum number of elements
142+ #[ eure( default ) ]
163143 pub max_length : Option < u32 > ,
164144 /// All elements must be unique
145+ #[ eure( default ) ]
165146 pub unique : bool ,
166147 /// Array must contain at least one element matching this schema
148+ #[ eure( default ) ]
167149 pub contains : Option < NodeId > ,
168150 /// Binding style for formatting
151+ #[ eure( ext, default ) ]
169152 pub binding_style : Option < BindingStyle > ,
170153}
171154
172- impl ParseDocument < ' _ > for ParsedArraySchema {
173- type Error = ParseError ;
174- fn parse ( ctx : & ParseContext < ' _ > ) -> Result < Self , Self :: Error > {
175- let rec = ctx. parse_record ( ) ?;
176- let item = rec. field ( "item" ) ?;
177- let min_length = rec. field_optional ( "min-length" ) ;
178- let max_length = rec. field_optional ( "max-length" ) ;
179- let unique = rec. field_optional ( "unique" ) ;
180- let contains = rec. field_optional ( "contains" ) ;
181- rec. allow_unknown_fields ( ) ?;
182-
183- let binding_style = ctx. parse_ext_optional ( "binding-style" ) ?;
184-
185- Ok ( ParsedArraySchema {
186- item : item. node_id ( ) ,
187- min_length : min_length. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
188- max_length : max_length. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
189- unique : unique. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?. unwrap_or ( false ) ,
190- contains : contains. map ( |ctx| Ok ( ctx. node_id ( ) ) ) . transpose ( ) ?,
191- binding_style,
192- } )
193- }
194- }
195-
196155/// Parsed map schema with NodeId references.
197- #[ derive( Debug , Clone ) ]
156+ #[ derive( Debug , Clone , eure_macros:: ParseDocument ) ]
157+ #[ eure( crate = eure_document, rename_all = "kebab-case" ) ]
198158pub struct ParsedMapSchema {
199159 /// Schema for keys
200160 pub key : NodeId ,
201161 /// Schema for values
202162 pub value : NodeId ,
203163 /// Minimum number of key-value pairs
164+ #[ eure( default ) ]
204165 pub min_size : Option < u32 > ,
205166 /// Maximum number of key-value pairs
167+ #[ eure( default ) ]
206168 pub max_size : Option < u32 > ,
207169}
208170
209- impl ParseDocument < ' _ > for ParsedMapSchema {
210- type Error = ParseError ;
211- fn parse ( ctx : & ParseContext < ' _ > ) -> Result < Self , Self :: Error > {
212- let rec = ctx. parse_record ( ) ?;
213- let key = rec. field ( "key" ) ?;
214- let value = rec. field ( "value" ) ?;
215- let min_size = rec. field_optional ( "min-size" ) ;
216- let max_size = rec. field_optional ( "max-size" ) ;
217- rec. allow_unknown_fields ( ) ?;
218- Ok ( ParsedMapSchema {
219- key : key. node_id ( ) ,
220- value : value. node_id ( ) ,
221- min_size : min_size. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
222- max_size : max_size. map ( |ctx| ctx. parse ( ) ) . transpose ( ) ?,
223- } )
224- }
225- }
226-
227171/// Parsed record field schema with NodeId reference.
228172#[ derive( Debug , Clone , eure_macros:: ParseDocument ) ]
229173#[ eure( crate = eure_document, parse_ext, rename_all = "kebab-case" ) ]
@@ -311,30 +255,16 @@ impl ParseDocument<'_> for ParsedRecordSchema {
311255}
312256
313257/// Parsed tuple schema with NodeId references.
314- #[ derive( Debug , Clone ) ]
258+ #[ derive( Debug , Clone , eure_macros:: ParseDocument ) ]
259+ #[ eure( crate = eure_document, rename_all = "kebab-case" ) ]
315260pub struct ParsedTupleSchema {
316261 /// Schema for each element by position (NodeId references)
317262 pub elements : Vec < NodeId > ,
318263 /// Binding style for formatting
264+ #[ eure( ext, default ) ]
319265 pub binding_style : Option < BindingStyle > ,
320266}
321267
322- impl ParseDocument < ' _ > for ParsedTupleSchema {
323- type Error = ParseError ;
324- fn parse ( ctx : & ParseContext < ' _ > ) -> Result < Self , Self :: Error > {
325- let rec = ctx. parse_record ( ) ?;
326- let elements = rec. field ( "elements" ) ?;
327- rec. allow_unknown_fields ( ) ?;
328-
329- let binding_style = ctx. parse_ext_optional ( "binding-style" ) ?;
330-
331- Ok ( ParsedTupleSchema {
332- elements : elements. parse ( ) ?,
333- binding_style,
334- } )
335- }
336- }
337-
338268/// Parsed union schema with NodeId references.
339269#[ derive( Debug , Clone ) ]
340270pub struct ParsedUnionSchema {
@@ -699,9 +629,21 @@ impl ParseDocument<'_> for ParsedSchemaNodeContent {
699629impl ParseDocument < ' _ > for ParsedSchemaNode {
700630 type Error = ParseError ;
701631 fn parse ( ctx : & ParseContext < ' _ > ) -> Result < Self , Self :: Error > {
702- let content = ctx. parse :: < ParsedSchemaNodeContent > ( ) ?;
703- let metadata = ParsedSchemaMetadata :: parse_from_extensions ( ctx) ?;
704- let ext_types = parse_ext_types ( ctx) ?;
632+ // Create a flattened context so child parsers' deny_unknown_* are no-ops.
633+ // All accesses are recorded in the shared accessed set (via Rc).
634+ let flatten_ctx = ctx. flatten ( ) ;
635+
636+ // Parse schema-level extensions - marks $ext-type, $description, etc. as accessed
637+ let ext_types = parse_ext_types ( & flatten_ctx) ?;
638+ let metadata = ParsedSchemaMetadata :: parse_from_extensions ( & flatten_ctx) ?;
639+
640+ // Content parsing uses the flattened context
641+ let content = flatten_ctx. parse :: < ParsedSchemaNodeContent > ( ) ?;
642+
643+ // Note: We do NOT validate unknown extensions here because:
644+ // 1. At the document root, $types extension is handled by the converter
645+ // 2. Content types use flatten context, so their deny is already no-op
646+ // The caller (e.g., Converter) should handle document-level validation if needed.
705647
706648 Ok ( ParsedSchemaNode {
707649 content,
0 commit comments