@@ -255,50 +255,6 @@ pub(crate) fn schema_extensions(
255255 }
256256}
257257
258- /// Used to visit all schemas and collect all dependencies.
259- pub ( crate ) struct ReferenceVisitor < ' a > {
260- generator : & ' a schemars:: gen:: SchemaGenerator ,
261- dependencies : indexmap:: IndexMap < String , schemars:: schema:: Schema > ,
262- }
263-
264- impl < ' a > ReferenceVisitor < ' a > {
265- pub fn new ( generator : & ' a schemars:: gen:: SchemaGenerator ) -> Self {
266- Self { generator, dependencies : indexmap:: IndexMap :: new ( ) }
267- }
268-
269- pub fn dependencies (
270- self ,
271- ) -> indexmap:: IndexMap < String , schemars:: schema:: Schema > {
272- self . dependencies
273- }
274- }
275-
276- impl schemars:: visit:: Visitor for ReferenceVisitor < ' _ > {
277- fn visit_schema_object ( & mut self , schema : & mut SchemaObject ) {
278- if let Some ( refstr) = & schema. reference {
279- let definitions_path = & self . generator . settings ( ) . definitions_path ;
280- let name = & refstr[ definitions_path. len ( ) ..] ;
281-
282- if !self . dependencies . contains_key ( name) {
283- let mut refschema = self
284- . generator
285- . definitions ( )
286- . get ( name)
287- . expect ( "invalid reference" )
288- . clone ( ) ;
289- self . dependencies . insert (
290- name. to_string ( ) ,
291- schemars:: schema:: Schema :: Bool ( false ) ,
292- ) ;
293- schemars:: visit:: visit_schema ( self , & mut refschema) ;
294- self . dependencies . insert ( name. to_string ( ) , refschema) ;
295- }
296- }
297-
298- schemars:: visit:: visit_schema_object ( self , schema) ;
299- }
300- }
301-
302258pub ( crate ) fn schema_extract_description (
303259 schema : & schemars:: schema:: Schema ,
304260) -> ( Option < String > , schemars:: schema:: Schema ) {
@@ -379,14 +335,26 @@ pub(crate) fn j2oas_schema(
379335 // when consumers use a type such as serde_json::Value.
380336 schemars:: schema:: Schema :: Bool ( true ) => {
381337 openapiv3:: ReferenceOr :: Item ( openapiv3:: Schema {
382- schema_data : openapiv3:: SchemaData :: default ( ) ,
383- schema_kind : openapiv3:: SchemaKind :: Any (
384- openapiv3:: AnySchema :: default ( ) ,
385- ) ,
338+ schema_data : Default :: default ( ) ,
339+ schema_kind : openapiv3:: SchemaKind :: Any ( Default :: default ( ) ) ,
386340 } )
387341 }
342+ // The unsatisfiable, "match nothing" schema. We represent this as
343+ // the `not` of the permissive schema.
388344 schemars:: schema:: Schema :: Bool ( false ) => {
389- panic ! ( "We don't expect to see a schema that matches the null set" )
345+ openapiv3:: ReferenceOr :: Item ( openapiv3:: Schema {
346+ schema_data : Default :: default ( ) ,
347+ schema_kind : openapiv3:: SchemaKind :: Not {
348+ not : Box :: new ( openapiv3:: ReferenceOr :: Item (
349+ openapiv3:: Schema {
350+ schema_data : Default :: default ( ) ,
351+ schema_kind : openapiv3:: SchemaKind :: Any (
352+ Default :: default ( ) ,
353+ ) ,
354+ } ,
355+ ) ) ,
356+ } ,
357+ } )
390358 }
391359 schemars:: schema:: Schema :: Object ( obj) => j2oas_schema_object ( name, obj) ,
392360 }
@@ -411,6 +379,73 @@ fn j2oas_schema_object(
411379 } ;
412380 }
413381
382+ let kind = j2oas_schema_object_kind ( obj) ;
383+
384+ let mut data = openapiv3:: SchemaData :: default ( ) ;
385+
386+ if matches ! (
387+ & obj. extensions. get( "nullable" ) ,
388+ Some ( serde_json:: Value :: Bool ( true ) )
389+ ) {
390+ data. nullable = true ;
391+ }
392+
393+ if let Some ( metadata) = & obj. metadata {
394+ data. title . clone_from ( & metadata. title ) ;
395+ data. description . clone_from ( & metadata. description ) ;
396+ data. default . clone_from ( & metadata. default ) ;
397+ data. deprecated = metadata. deprecated ;
398+ data. read_only = metadata. read_only ;
399+ data. write_only = metadata. write_only ;
400+ }
401+
402+ // Preserve extensions
403+ data. extensions = obj
404+ . extensions
405+ . iter ( )
406+ . filter ( |( key, _) | key. starts_with ( "x-" ) )
407+ . map ( |( key, value) | ( key. clone ( ) , value. clone ( ) ) )
408+ . collect ( ) ;
409+
410+ if let Some ( name) = name {
411+ data. title = Some ( name. clone ( ) ) ;
412+ }
413+ if let Some ( example) = obj. extensions . get ( "example" ) {
414+ data. example = Some ( example. clone ( ) ) ;
415+ }
416+
417+ openapiv3:: ReferenceOr :: Item ( openapiv3:: Schema {
418+ schema_data : data,
419+ schema_kind : kind,
420+ } )
421+ }
422+
423+ fn j2oas_schema_object_kind (
424+ obj : & schemars:: schema:: SchemaObject ,
425+ ) -> openapiv3:: SchemaKind {
426+ // If the JSON schema is attempting to express an unsatisfiable schema
427+ // using an empty enumerated values array, that presents a problem
428+ // translating to the openapiv3 crate's representation. While we might
429+ // like to simply use the schema `false` that is *also* challenging to
430+ // represent via the openapiv3 crate *and* it precludes us from preserving
431+ // extensions, if they happen to be present. Instead we'll represent this
432+ // construction using `{ not: {} }` i.e. the opposite of the permissive
433+ // schema.
434+ if let Some ( enum_values) = & obj. enum_values {
435+ if enum_values. is_empty ( ) {
436+ return openapiv3:: SchemaKind :: Not {
437+ not : Box :: new ( openapiv3:: ReferenceOr :: Item (
438+ openapiv3:: Schema {
439+ schema_data : Default :: default ( ) ,
440+ schema_kind : openapiv3:: SchemaKind :: Any (
441+ Default :: default ( ) ,
442+ ) ,
443+ } ,
444+ ) ) ,
445+ } ;
446+ }
447+ }
448+
414449 let ty = match & obj. instance_type {
415450 Some ( schemars:: schema:: SingleOrVec :: Single ( ty) ) => Some ( ty. as_ref ( ) ) ,
416451 Some ( schemars:: schema:: SingleOrVec :: Vec ( _) ) => {
@@ -423,7 +458,7 @@ fn j2oas_schema_object(
423458 None => None ,
424459 } ;
425460
426- let kind = match ( ty, & obj. subschemas ) {
461+ match ( ty, & obj. subschemas ) {
427462 ( Some ( schemars:: schema:: InstanceType :: Null ) , None ) => {
428463 openapiv3:: SchemaKind :: Type ( openapiv3:: Type :: String (
429464 openapiv3:: StringType {
@@ -485,45 +520,7 @@ fn j2oas_schema_object(
485520 openapiv3:: SchemaKind :: Any ( openapiv3:: AnySchema :: default ( ) )
486521 }
487522 ( Some ( _) , Some ( _) ) => j2oas_any ( ty, obj) ,
488- } ;
489-
490- let mut data = openapiv3:: SchemaData :: default ( ) ;
491-
492- if matches ! (
493- & obj. extensions. get( "nullable" ) ,
494- Some ( serde_json:: Value :: Bool ( true ) )
495- ) {
496- data. nullable = true ;
497- }
498-
499- if let Some ( metadata) = & obj. metadata {
500- data. title . clone_from ( & metadata. title ) ;
501- data. description . clone_from ( & metadata. description ) ;
502- data. default . clone_from ( & metadata. default ) ;
503- data. deprecated = metadata. deprecated ;
504- data. read_only = metadata. read_only ;
505- data. write_only = metadata. write_only ;
506523 }
507-
508- // Preserve extensions
509- data. extensions = obj
510- . extensions
511- . iter ( )
512- . filter ( |( key, _) | key. starts_with ( "x-" ) )
513- . map ( |( key, value) | ( key. clone ( ) , value. clone ( ) ) )
514- . collect ( ) ;
515-
516- if let Some ( name) = name {
517- data. title = Some ( name. clone ( ) ) ;
518- }
519- if let Some ( example) = obj. extensions . get ( "example" ) {
520- data. example = Some ( example. clone ( ) ) ;
521- }
522-
523- openapiv3:: ReferenceOr :: Item ( openapiv3:: Schema {
524- schema_data : data,
525- schema_kind : kind,
526- } )
527524}
528525
529526fn j2oas_any (
@@ -842,6 +839,7 @@ fn j2oas_string(
842839 let enumeration = enum_values
843840 . iter ( )
844841 . flat_map ( |v| {
842+ assert ! ( !v. is_empty( ) ) ;
845843 v. iter ( ) . map ( |vv| match vv {
846844 serde_json:: Value :: Null => None ,
847845 serde_json:: Value :: String ( s) => Some ( s. clone ( ) ) ,
0 commit comments