@@ -300,28 +300,33 @@ class SchemaAnalyzer {
300300 bool required , {
301301 bool allowEnum = true ,
302302 }) {
303- final type = schemas.type;
303+ final (type, typeIsNullable) = schemas.typeAndNullable;
304+ final isNullable = typeIsNullable || ! required ;
305+
304306 final DartType dartType;
305307 switch (type) {
306308 case null :
307- dartType = ObjectDartType (isNullable: ! required );
309+ dartType = ObjectDartType (isNullable: isNullable );
308310 case SchemaType .boolean:
309- dartType = BoolDartType (isNullable: ! required );
311+ dartType = BoolDartType (isNullable: isNullable );
310312 case SchemaType .integer:
311- dartType = IntDartType (isNullable: ! required );
313+ dartType = IntDartType (isNullable: isNullable );
312314 case SchemaType .string:
313315 if (schemas.generateUri) {
314- dartType = UriDartType (isNullable: ! required );
316+ dartType = UriDartType (isNullable: isNullable );
315317 } else if (schemas.generateEnum && allowEnum) {
316318 _analyzeEnumClass (schemas);
317319 final classInfo = _classes[schemas.className]! ;
318- dartType = ClassDartType (classInfo: classInfo, isNullable: ! required );
320+ dartType = ClassDartType (
321+ classInfo: classInfo,
322+ isNullable: isNullable,
323+ );
319324 } else {
320325 if (schemas.patterns.length > 1 ) {
321326 throw UnsupportedError ('Only one pattern is supported.' );
322327 }
323328 final pattern = schemas.patterns.firstOrNull;
324- dartType = StringDartType (isNullable: ! required , pattern: pattern);
329+ dartType = StringDartType (isNullable: isNullable , pattern: pattern);
325330 }
326331 case SchemaType .object:
327332 final additionalPropertiesSchema =
@@ -352,7 +357,7 @@ class SchemaAnalyzer {
352357 ),
353358 isNullable: false ,
354359 ),
355- isNullable: ! required ,
360+ isNullable: isNullable ,
356361 );
357362 default :
358363 throw UnimplementedError (itemType.toString ());
@@ -366,7 +371,7 @@ class SchemaAnalyzer {
366371 dartType = MapDartType (
367372 keyType: keyDartType,
368373 valueType: ClassDartType (classInfo: clazz, isNullable: false ),
369- isNullable: ! required ,
374+ isNullable: isNullable ,
370375 );
371376 } else {
372377 dartType = MapDartType (
@@ -375,17 +380,21 @@ class SchemaAnalyzer {
375380 valueType: ObjectDartType (isNullable: true ),
376381 isNullable: false ,
377382 ),
378- isNullable: ! required ,
383+ isNullable: isNullable ,
379384 );
380385 }
381386 case null :
382387 if (schemas.additionalPropertiesBool == true ) {
383388 dartType = ClassDartType (
384389 classInfo: jsonObjectClassInfo,
385- isNullable: ! required ,
390+ isNullable: isNullable ,
386391 );
387392 } else {
388393 final oneOfs = additionalPropertiesSchema.oneOfs;
394+ if (oneOfs.isEmpty) {
395+ // No type information.
396+ return const ObjectDartType (isNullable: true );
397+ }
389398 if (oneOfs.length != 1 ) {
390399 throw UnimplementedError ();
391400 }
@@ -413,7 +422,7 @@ class SchemaAnalyzer {
413422 isNullable: true ,
414423 pattern: stringPattern,
415424 ),
416- isNullable: ! required ,
425+ isNullable: isNullable ,
417426 );
418427 } else {
419428 throw UnimplementedError ();
@@ -423,7 +432,13 @@ class SchemaAnalyzer {
423432 dartType = MapDartType (
424433 keyType: keyDartType,
425434 valueType: const StringDartType (isNullable: false ),
426- isNullable: ! required ,
435+ isNullable: isNullable,
436+ );
437+ case SchemaType .integer:
438+ dartType = MapDartType (
439+ keyType: keyDartType,
440+ valueType: const IntDartType (isNullable: false ),
441+ isNullable: isNullable,
427442 );
428443 default :
429444 throw UnimplementedError (additionalPropertiesType.toString ());
@@ -433,31 +448,60 @@ class SchemaAnalyzer {
433448 typeName ?? = _ucFirst (_snakeToCamelCase (propertyKey));
434449 _analyzeClass (schemas, name: typeName);
435450 final classInfo = _classes[typeName]! ;
436- dartType = ClassDartType (classInfo: classInfo, isNullable: ! required );
451+ dartType = ClassDartType (
452+ classInfo: classInfo,
453+ isNullable: isNullable,
454+ );
437455 }
438456 case SchemaType .array:
439457 final items = schemas.items;
440- final itemType = items.type ;
458+ final ( itemType, itemNullable) = items.typeAndNullable ;
441459 switch (itemType) {
442460 case SchemaType .string:
443461 if (items.generateUri) {
444462 dartType = ListDartType (
445- itemType: const UriDartType (isNullable: false ),
446- isNullable: ! required ,
463+ itemType: UriDartType (isNullable: itemNullable ),
464+ isNullable: isNullable ,
447465 );
448466 } else {
449467 dartType = ListDartType (
450- itemType: const StringDartType (isNullable: false ),
451- isNullable: ! required ,
468+ itemType: StringDartType (isNullable: itemNullable ),
469+ isNullable: isNullable ,
452470 );
453471 }
454- case SchemaType .object:
455- final typeName = items.className! ;
456- _analyzeClass (items);
457- final classInfo = _classes[typeName]! ;
472+ case SchemaType .integer:
458473 dartType = ListDartType (
459- itemType: ClassDartType (classInfo: classInfo, isNullable: false ),
460- isNullable: ! required ,
474+ itemType: IntDartType (isNullable: itemNullable),
475+ isNullable: isNullable,
476+ );
477+ case SchemaType .object:
478+ final typeName = items.className;
479+ if (typeName != null ) {
480+ _analyzeClass (items);
481+ final classInfo = _classes[typeName]! ;
482+ dartType = ListDartType (
483+ itemType: ClassDartType (
484+ classInfo: classInfo,
485+ isNullable: itemNullable,
486+ ),
487+ isNullable: isNullable,
488+ );
489+ } else if (items.generateMapOf) {
490+ dartType = const ListDartType (
491+ itemType: MapDartType (
492+ valueType: ObjectDartType (isNullable: true ),
493+ isNullable: true ,
494+ ),
495+ isNullable: true ,
496+ );
497+ } else {
498+ throw UnimplementedError (itemType.toString ());
499+ }
500+ case null :
501+ // No type information.
502+ dartType = const ListDartType (
503+ itemType: ObjectDartType (isNullable: true ),
504+ isNullable: true ,
461505 );
462506 default :
463507 throw UnimplementedError (itemType.toString ());
@@ -550,7 +594,7 @@ extension type JsonSchemas._(List<JsonSchema> _schemas) {
550594 for (final schema in _schemas) ...schema.requiredProperties ?? [],
551595 }.toList ()..sort ();
552596
553- SchemaType ? get type {
597+ Set < SchemaType > get types {
554598 final types = < SchemaType > {};
555599 for (final schema in _schemas) {
556600 final schemaTypes = schema.typeList;
@@ -560,12 +604,27 @@ extension type JsonSchemas._(List<JsonSchema> _schemas) {
560604 }
561605 }
562606 }
607+ return types;
608+ }
609+
610+ SchemaType ? get type {
563611 if (types.length > 1 ) {
564612 throw StateError ('Multiple types found' );
565613 }
566614 return types.singleOrNull;
567615 }
568616
617+ (SchemaType ? , bool ) get typeAndNullable {
618+ if (types.length <= 1 ) {
619+ return (types.singleOrNull, false );
620+ } else if (types.length == 2 && types.contains (SchemaType .nullValue)) {
621+ final type = types.firstWhere ((t) => t != SchemaType .nullValue);
622+ return (type, true );
623+ } else {
624+ throw UnsupportedError ('Multiple types: $types .' );
625+ }
626+ }
627+
569628 List <RegExp > get patterns {
570629 final patterns = < RegExp > {};
571630 for (final schema in _schemas) {
@@ -745,10 +804,6 @@ extension on JsonSchemas {
745804
746805 String ? get generateSubClassesKey {
747806 if (type != SchemaType .object) return null ;
748- // A tagged union either has only a key, or a key and an encoding.
749- // Classes with more than 2 properties have their a property that has
750- // predefined values generated as an enum class.
751- if (propertyKeys.length > 2 ) return null ;
752807 for (final p in propertyKeys) {
753808 final propertySchemas = property (p);
754809 if (propertySchemas.anyOfs.isNotEmpty) {
@@ -785,7 +840,10 @@ extension on JsonSchemas {
785840 if (path.contains ('#/definitions/' )) {
786841 final splits = path.split ('/' );
787842 final indexOf = splits.indexOf ('definitions' );
788- final nameParts = splits.skip (indexOf + 1 ).where ((e) => e.isNotEmpty);
843+ final nameParts = splits
844+ .skip (indexOf + 1 )
845+ .where ((e) => e.isNotEmpty)
846+ .toList ();
789847 if (nameParts.length == 1 && nameParts.single.startsWithUpperCase ()) {
790848 return nameParts.single;
791849 }
0 commit comments