Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/dart_mappable/lib/src/annotations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class MappableClass extends MappableInterface {
const MappableClass({
super.caseStyle,
super.ignoreNull,
super.ignore,
super.uniqueId,
this.discriminatorKey,
this.discriminatorValue,
Expand Down Expand Up @@ -145,6 +146,7 @@ class MappableRecord extends MappableInterface {
const MappableRecord({
super.caseStyle,
super.ignoreNull,
super.ignore,
super.uniqueId,
super.hook,
super.includeCustomMappers,
Expand All @@ -158,6 +160,7 @@ abstract class MappableInterface {
const MappableInterface._({
this.caseStyle,
this.ignoreNull,
this.ignore,
this.uniqueId,
this.hook,
this.generateMethods,
Expand All @@ -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<String>? ignore;

/// A unique id representing this class.
///
/// This only needs to be set when you have two classes with the same name
Expand Down Expand Up @@ -205,6 +211,7 @@ class MappableLib {
this.caseStyle,
this.enumCaseStyle,
this.ignoreNull,
this.ignore,
this.discriminatorKey,
this.generateMethods,
this.generateInitializerForScope,
Expand All @@ -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<String>? ignore;

/// Property key used for type discriminators.
final String? discriminatorKey;

Expand Down
9 changes: 7 additions & 2 deletions packages/dart_mappable/lib/src/mappers/class_mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,13 @@ abstract class ClassMapperBase<T extends Object>

@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};
}
Expand Down
23 changes: 20 additions & 3 deletions packages/dart_mappable/lib/src/mappers/interface_mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ abstract class InterfaceMapperBase<T extends Object> extends MapperBase<T> {
/// 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<String> get ignore => [];

/// The optional mapping hook defined for this interface.
MappingHook? get hook => null;

Expand Down Expand Up @@ -185,21 +188,35 @@ abstract class InterfaceMapperBase<T extends Object> extends MapperBase<T> {
T value,
Iterable<Field<T, dynamic>> fields,
bool ignoreNull,
Iterable<String> ignore,
EncodingContext context) {
bool shallow = context.options?.shallow ?? false;

// Helper to determine if a field should be ignored
bool shouldIncludeField(Field<T, dynamic> 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<V>(Map<String, dynamic> map) => decodeValue<V>(map);
Expand Down
9 changes: 7 additions & 2 deletions packages/dart_mappable/lib/src/mappers/record_mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ abstract class RecordMapperBase<T extends Record> extends InterfaceMapperBase<T>

@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
Expand Down
5 changes: 5 additions & 0 deletions packages/dart_mappable_builder/lib/src/builder_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class MappableOptions {
final CaseStyle? caseStyle;
final CaseStyle? enumCaseStyle;
final bool? ignoreNull;
final Iterable<String>? ignore;
final String? discriminatorKey;
final int? generateMethods;
final InitializerScope? initializerScope;
Expand All @@ -23,6 +24,7 @@ class MappableOptions {
this.caseStyle,
this.enumCaseStyle,
this.ignoreNull,
this.ignore,
this.discriminatorKey,
this.generateMethods,
this.initializerScope,
Expand All @@ -36,6 +38,7 @@ class MappableOptions {
enumCaseStyle =
CaseStyle.fromString(options['enumCaseStyle'] as String?),
ignoreNull = options['ignoreNull'] as bool?,
ignore = options['ignore'] as Iterable<String>?,
discriminatorKey = options['discriminatorKey'] as String?,
generateMethods =
parseGenerateMethods(toList(options['generateMethods'])),
Expand All @@ -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,
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ abstract class ClassMapperElement extends InterfaceMapperElement<ClassElement>
superElement?.ignoreNull ??
false;

late final Iterable<String> ignore =
annotation.value?.read('ignore')?.toStringList() ?? [];

late final int generateMethods =
annotation.value?.read('generateMethods')?.toIntValue() ??
options.generateMethods ??
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class ClassMapperGenerator extends MapperGenerator<TargetClassMapperElement>
output.write(' @override\n final bool ignoreNull = true;\n');
}

if (element.ignore.isNotEmpty) {
output.write(
' @override\n final Iterable<String> ignore = const [${element.ignore.map((e) => "'$e'").join(', ')}];\n');
}

if (element.isDiscriminatingSubclass) {
await generateDiscriminatorFields(output);
generateInheritOverride(output);
Expand Down
3 changes: 3 additions & 0 deletions packages/dart_mappable_builder/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ extension NullableType on DartType {
extension TypeList on DartObject {
List<DartType>? toTypeList() =>
toListValue()?.map((o) => o.toTypeValue()).whereType<DartType>().toList();

List<String>? toStringList() =>
toListValue()?.map((o) => o.toStringValue()).whereType<String>().toList();
}

extension ObjectReader on DartObject {
Expand Down