diff --git a/packages/dart_mappable/lib/src/annotations.dart b/packages/dart_mappable/lib/src/annotations.dart index 5289f9d5..436fe5bf 100644 --- a/packages/dart_mappable/lib/src/annotations.dart +++ b/packages/dart_mappable/lib/src/annotations.dart @@ -13,6 +13,7 @@ class MappableClass extends MappableInterface { const MappableClass({ super.caseStyle, super.ignoreNull, + super.ignore, super.uniqueId, this.discriminatorKey, this.discriminatorValue, @@ -145,6 +146,7 @@ class MappableRecord extends MappableInterface { const MappableRecord({ super.caseStyle, super.ignoreNull, + super.ignore, super.uniqueId, super.hook, super.includeCustomMappers, @@ -158,6 +160,7 @@ abstract class MappableInterface { const MappableInterface._({ this.caseStyle, this.ignoreNull, + this.ignore, this.uniqueId, this.hook, this.generateMethods, @@ -170,6 +173,9 @@ abstract class MappableInterface { /// If true removes all map keys with null values. final bool? ignoreNull; + /// Property keys to exclude from `toMap` and `toJson`. + final Iterable? ignore; + /// A unique id representing this class. /// /// This only needs to be set when you have two classes with the same name @@ -205,6 +211,7 @@ class MappableLib { this.caseStyle, this.enumCaseStyle, this.ignoreNull, + this.ignore, this.discriminatorKey, this.generateMethods, this.generateInitializerForScope, @@ -219,6 +226,9 @@ class MappableLib { /// If true removes all map keys with null values. final bool? ignoreNull; + /// Property keys to exclude from `toMap` and `toJson`. + final Iterable? ignore; + /// Property key used for type discriminators. final String? discriminatorKey; diff --git a/packages/dart_mappable/lib/src/mappers/class_mapper.dart b/packages/dart_mappable/lib/src/mappers/class_mapper.dart index bfaadd91..df008819 100644 --- a/packages/dart_mappable/lib/src/mappers/class_mapper.dart +++ b/packages/dart_mappable/lib/src/mappers/class_mapper.dart @@ -200,8 +200,13 @@ abstract class ClassMapperBase @override Object? encode(T value, EncodingContext context) { - var result = - InterfaceMapperBase.encodeFields(value, _params, ignoreNull, context); + var result = InterfaceMapperBase.encodeFields( + value, + _params, + ignoreNull, + ignore, + context, + ); if (_encodedStaticParams != null) { return {...result, ...?_encodedStaticParams}; } diff --git a/packages/dart_mappable/lib/src/mappers/interface_mapper.dart b/packages/dart_mappable/lib/src/mappers/interface_mapper.dart index 69b94535..1e401879 100644 --- a/packages/dart_mappable/lib/src/mappers/interface_mapper.dart +++ b/packages/dart_mappable/lib/src/mappers/interface_mapper.dart @@ -114,6 +114,9 @@ abstract class InterfaceMapperBase extends MapperBase { /// Whether to ignore null values when encoding the fields of this interface. bool get ignoreNull => false; + /// Whether to ignore values when encoding the fields of this interface. + Iterable get ignore => []; + /// The optional mapping hook defined for this interface. MappingHook? get hook => null; @@ -185,21 +188,35 @@ abstract class InterfaceMapperBase extends MapperBase { T value, Iterable> fields, bool ignoreNull, + Iterable ignore, EncodingContext context) { bool shallow = context.options?.shallow ?? false; + + // Helper to determine if a field should be ignored + bool shouldIncludeField(Field f) { + return !ignore.contains(f.key); + } + if (shallow) { return { for (var f in fields) - if (!ignoreNull || f.get(value) != null) f.key: f.get(value), + if (shouldIncludeField(f) && (!ignoreNull || f.get(value) != null)) + f.key: f.get(value), }; } + if (ignoreNull) { return { for (var f in fields) - if (f.get(value) != null) f.key: f.encode(value, context), + if (shouldIncludeField(f) && f.get(value) != null) + f.key: f.encode(value, context), }; } - return {for (var f in fields) f.key: f.encode(value, context)}; + + return { + for (var f in fields) + if (shouldIncludeField(f)) f.key: f.encode(value, context), + }; } V decodeMap(Map map) => decodeValue(map); diff --git a/packages/dart_mappable/lib/src/mappers/record_mapper.dart b/packages/dart_mappable/lib/src/mappers/record_mapper.dart index 926772bc..facc7b91 100644 --- a/packages/dart_mappable/lib/src/mappers/record_mapper.dart +++ b/packages/dart_mappable/lib/src/mappers/record_mapper.dart @@ -26,8 +26,13 @@ abstract class RecordMapperBase extends InterfaceMapperBase @override Object? encode(T value, EncodingContext context) { - return InterfaceMapperBase.encodeFields(value, fields.values, ignoreNull, - context.change(args: () => apply(context))); + return InterfaceMapperBase.encodeFields( + value, + fields.values, + ignoreNull, + ignore, + context.change(args: () => apply(context)), + ); } @override diff --git a/packages/dart_mappable_builder/lib/src/builder_options.dart b/packages/dart_mappable_builder/lib/src/builder_options.dart index 4541a8da..d0d282a2 100644 --- a/packages/dart_mappable_builder/lib/src/builder_options.dart +++ b/packages/dart_mappable_builder/lib/src/builder_options.dart @@ -12,6 +12,7 @@ class MappableOptions { final CaseStyle? caseStyle; final CaseStyle? enumCaseStyle; final bool? ignoreNull; + final Iterable? ignore; final String? discriminatorKey; final int? generateMethods; final InitializerScope? initializerScope; @@ -23,6 +24,7 @@ class MappableOptions { this.caseStyle, this.enumCaseStyle, this.ignoreNull, + this.ignore, this.discriminatorKey, this.generateMethods, this.initializerScope, @@ -36,6 +38,7 @@ class MappableOptions { enumCaseStyle = CaseStyle.fromString(options['enumCaseStyle'] as String?), ignoreNull = options['ignoreNull'] as bool?, + ignore = options['ignore'] as Iterable?, discriminatorKey = options['discriminatorKey'] as String?, generateMethods = parseGenerateMethods(toList(options['generateMethods'])), @@ -53,6 +56,7 @@ class MappableOptions { caseStyle: options.caseStyle ?? caseStyle, enumCaseStyle: options.enumCaseStyle ?? enumCaseStyle, ignoreNull: options.ignoreNull ?? ignoreNull, + ignore: options.ignore ?? ignore, discriminatorKey: options.discriminatorKey ?? discriminatorKey, generateMethods: options.generateMethods ?? generateMethods, initializerScope: options.initializerScope ?? initializerScope, @@ -66,6 +70,7 @@ class MappableOptions { caseStyle: caseStyleFromAnnotation(object.read('caseStyle')), enumCaseStyle: caseStyleFromAnnotation(object.read('enumCaseStyle')), ignoreNull: object.read('ignoreNull')?.toBoolValue(), + ignore: object.read('ignore')?.toStringList(), discriminatorKey: object.read('discriminatorKey')?.toStringValue(), generateMethods: object.read('generateMethods')?.toIntValue(), initializerScope: initScope?.isNull ?? true diff --git a/packages/dart_mappable_builder/lib/src/elements/class/class_mapper_element.dart b/packages/dart_mappable_builder/lib/src/elements/class/class_mapper_element.dart index d9afeeca..44709ebb 100644 --- a/packages/dart_mappable_builder/lib/src/elements/class/class_mapper_element.dart +++ b/packages/dart_mappable_builder/lib/src/elements/class/class_mapper_element.dart @@ -64,6 +64,9 @@ abstract class ClassMapperElement extends InterfaceMapperElement superElement?.ignoreNull ?? false; + late final Iterable ignore = + annotation.value?.read('ignore')?.toStringList() ?? []; + late final int generateMethods = annotation.value?.read('generateMethods')?.toIntValue() ?? options.generateMethods ?? diff --git a/packages/dart_mappable_builder/lib/src/generators/class_mapper_generator.dart b/packages/dart_mappable_builder/lib/src/generators/class_mapper_generator.dart index 6b80332f..4f6fff81 100644 --- a/packages/dart_mappable_builder/lib/src/generators/class_mapper_generator.dart +++ b/packages/dart_mappable_builder/lib/src/generators/class_mapper_generator.dart @@ -50,6 +50,11 @@ class ClassMapperGenerator extends MapperGenerator output.write(' @override\n final bool ignoreNull = true;\n'); } + if (element.ignore.isNotEmpty) { + output.write( + ' @override\n final Iterable ignore = const [${element.ignore.map((e) => "'$e'").join(', ')}];\n'); + } + if (element.isDiscriminatingSubclass) { await generateDiscriminatorFields(output); generateInheritOverride(output); diff --git a/packages/dart_mappable_builder/lib/src/utils.dart b/packages/dart_mappable_builder/lib/src/utils.dart index 480c3aad..2902dcaf 100644 --- a/packages/dart_mappable_builder/lib/src/utils.dart +++ b/packages/dart_mappable_builder/lib/src/utils.dart @@ -167,6 +167,9 @@ extension NullableType on DartType { extension TypeList on DartObject { List? toTypeList() => toListValue()?.map((o) => o.toTypeValue()).whereType().toList(); + + List? toStringList() => + toListValue()?.map((o) => o.toStringValue()).whereType().toList(); } extension ObjectReader on DartObject {