Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add JsonSerializable(createJsonMeta) #1164

Merged
merged 16 commits into from Jun 28, 2022
9 changes: 9 additions & 0 deletions json_annotation/lib/src/json_serializable.dart
Expand Up @@ -6,6 +6,7 @@ import 'package:meta/meta_meta.dart';

import 'allowed_keys_helpers.dart';
import 'checked_helpers.dart';
import 'enum_helpers.dart';
import 'json_converter.dart';
import 'json_key.dart';

Expand Down Expand Up @@ -64,6 +65,13 @@ class JsonSerializable {
/// This setting has no effect if [createFactory] is `false`.
final String? constructor;

/// If `true` (defaults to false), a private, static `_$ExampleJsonMeta`
/// constant is created in the generated part file.
///
/// This constant can be used by other code-generators to support features
/// such as [fieldRename].
final bool? createJsonMeta;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"meta" is pretty vague here. Maybe createFieldMap? Let's talk before you start rewriting everything...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xFieldMap sounds good to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


/// If `true` (the default), a private, static `_$ExampleFromJson` method
/// is created in the generated part file.
///
Expand Down Expand Up @@ -231,6 +239,7 @@ class JsonSerializable {
this.anyMap,
this.checked,
this.constructor,
this.createJsonMeta,
this.createFactory,
this.createToJson,
this.disallowUnrecognizedKeys,
Expand Down
46 changes: 8 additions & 38 deletions json_annotation/lib/src/json_serializable.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions json_serializable/lib/src/encoder_helper.dart
Expand Up @@ -16,6 +16,26 @@ import 'unsupported_type_error.dart';
abstract class EncodeHelper implements HelperCore {
String _fieldAccess(FieldElement field) => '$_toJsonParamName.${field.name}';

/// Generates an object containing metadatas related to the encoding,
/// destined to be used by other code-generators.
String createJsonMeta(Set<FieldElement> accessibleFieldSet) {
assert(config.createJsonMeta);

final buffer =
StringBuffer('const _\$${element.name}JsonMeta = <String, String> {');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Careful using element.name – if it's already private you'll end up with double _ which makes analyzer sad.

I have a helper around here somewhere for this"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I haven't seen another util for this


for (final field in accessibleFieldSet) {
buffer.writeln(
'${escapeDartString(field.name)}: '
'${escapeDartString(nameAccess(field))},',
);
}

buffer.write('};');

return buffer.toString();
}

Iterable<String> createToJson(Set<FieldElement> accessibleFields) sync* {
assert(config.createToJson);

Expand Down
4 changes: 4 additions & 0 deletions json_serializable/lib/src/generator_helper.dart
Expand Up @@ -108,6 +108,10 @@ class GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper {
},
);

if (config.createJsonMeta) {
yield createJsonMeta(accessibleFieldSet);
}

if (config.createToJson) {
yield* createToJson(accessibleFieldSet);
}
Expand Down
6 changes: 6 additions & 0 deletions json_serializable/lib/src/type_helpers/config_types.dart
Expand Up @@ -45,6 +45,7 @@ class ClassConfig {
final String constructor;
final bool createFactory;
final bool createToJson;
final bool createJsonMeta;
final bool disallowUnrecognizedKeys;
final bool explicitToJson;
final FieldRename fieldRename;
Expand All @@ -60,6 +61,7 @@ class ClassConfig {
required this.constructor,
required this.createFactory,
required this.createToJson,
required this.createJsonMeta,
required this.disallowUnrecognizedKeys,
required this.explicitToJson,
required this.fieldRename,
Expand All @@ -76,6 +78,8 @@ class ClassConfig {
checked: config.checked ?? ClassConfig.defaults.checked,
anyMap: config.anyMap ?? ClassConfig.defaults.anyMap,
constructor: config.constructor ?? ClassConfig.defaults.constructor,
createJsonMeta:
config.createJsonMeta ?? ClassConfig.defaults.createJsonMeta,
createFactory:
config.createFactory ?? ClassConfig.defaults.createFactory,
createToJson: config.createToJson ?? ClassConfig.defaults.createToJson,
Expand All @@ -101,6 +105,7 @@ class ClassConfig {
constructor: '',
createFactory: true,
createToJson: true,
createJsonMeta: false,
disallowUnrecognizedKeys: false,
explicitToJson: false,
fieldRename: FieldRename.none,
Expand All @@ -115,6 +120,7 @@ class ClassConfig {
constructor: constructor,
createFactory: createFactory,
createToJson: createToJson,
createJsonMeta: createJsonMeta,
ignoreUnannotated: ignoreUnannotated,
explicitToJson: explicitToJson,
includeIfNull: includeIfNull,
Expand Down
2 changes: 2 additions & 0 deletions json_serializable/lib/src/utils.dart
Expand Up @@ -56,6 +56,7 @@ JsonSerializable _valueForAnnotation(ConstantReader reader) => JsonSerializable(
constructor: reader.read('constructor').literalValue as String?,
createFactory: reader.read('createFactory').literalValue as bool?,
createToJson: reader.read('createToJson').literalValue as bool?,
createJsonMeta: reader.read('createJsonMeta').literalValue as bool?,
disallowUnrecognizedKeys:
reader.read('disallowUnrecognizedKeys').literalValue as bool?,
explicitToJson: reader.read('explicitToJson').literalValue as bool?,
Expand Down Expand Up @@ -101,6 +102,7 @@ ClassConfig mergeConfig(
constructor: constructor,
createFactory: annotation.createFactory ?? config.createFactory,
createToJson: annotation.createToJson ?? config.createToJson,
createJsonMeta: annotation.createJsonMeta ?? config.createJsonMeta,
disallowUnrecognizedKeys:
annotation.disallowUnrecognizedKeys ?? config.disallowUnrecognizedKeys,
explicitToJson: annotation.explicitToJson ?? config.explicitToJson,
Expand Down
5 changes: 5 additions & 0 deletions json_serializable/test/config_test.dart
Expand Up @@ -126,6 +126,10 @@ void main() {
lastLine = "type 'int' is not a subtype of type 'String?' in type "
'cast';
break;
case 'create_to_json':
lastLine = "type 'int' is not a subtype of type 'bool?' in type "
'cast';
break;
default:
lastLine =
"type 'int' is not a subtype of type 'bool?' in type cast";
Expand All @@ -152,6 +156,7 @@ const _invalidConfig = {
'checked': 42,
'constructor': 42,
'create_factory': 42,
'create_json_meta': 42,
'create_to_json': 42,
'disallow_unrecognized_keys': 42,
'explicit_to_json': 42,
Expand Down
11 changes: 11 additions & 0 deletions json_serializable/test/integration/integration_test.dart
Expand Up @@ -7,6 +7,7 @@ import 'package:test/test.dart';

import '../test_utils.dart';
import 'json_enum_example.dart';
import 'json_meta_example.dart';
import 'json_test_common.dart' show Category, Platform, StatusCode;
import 'json_test_example.dart';

Expand Down Expand Up @@ -322,4 +323,14 @@ void main() {
isNull,
);
});

test(r'_$ModelJsonMeta', () {
expect(
modelMeta,
{
'firstName': 'first-name',
'lastName': 'LAST_NAME',
},
);
});
}
28 changes: 28 additions & 0 deletions json_serializable/test/integration/json_meta_example.dart
@@ -0,0 +1,28 @@
import 'package:json_annotation/json_annotation.dart';

part 'json_meta_example.g.dart';

@JsonSerializable(createJsonMeta: true, fieldRename: FieldRename.kebab)
class Model {
Model({
required this.firstName,
required this.lastName,
this.ignoredName,
});

factory Model.fromJson(Map<String, Object?> json) => _$ModelFromJson(json);

final String firstName;

@JsonKey(name: 'LAST_NAME')
final String lastName;

@JsonKey(ignore: true)
final String? ignoredName;

String get fullName => '$firstName $lastName';

Map<String, Object?> toJson() => _$ModelToJson(this);
}

const modelMeta = _$ModelJsonMeta;
24 changes: 24 additions & 0 deletions json_serializable/test/integration/json_meta_example.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions json_serializable/test/shared_config.dart
Expand Up @@ -19,6 +19,7 @@ final generatorConfigNonDefaultJson =
constructor: 'something',
createFactory: false,
createToJson: false,
createJsonMeta: true,
disallowUnrecognizedKeys: true,
explicitToJson: true,
fieldRename: FieldRename.kebab,
Expand Down
1 change: 1 addition & 0 deletions json_serializable/test/test_sources/test_sources.dart
Expand Up @@ -15,6 +15,7 @@ class ConfigurationImplicitDefaults {
constructor: '',
createFactory: true,
createToJson: true,
createJsonMeta: false,
disallowUnrecognizedKeys: false,
explicitToJson: false,
fieldRename: FieldRename.none,
Expand Down