增加反复下载不下来的json_serializable-2.0.0
| New file |
| | |
| | | # Below is a list of people and organizations that have contributed |
| | | # to the project. Names should be added to the list like so: |
| | | # |
| | | # Name/Organization <email address> |
| | | |
| | | Google Inc. |
| New file |
| | |
| | | ## 2.0.0 |
| | | |
| | | * Support all `build.yaml` configuration options on classes by adding a number |
| | | of fields to `JsonSerializable`: `anyMap`, `checked`, `explicitToJson`, |
| | | `generateToJsonFunction`, and `useWrappers`. |
| | | |
| | | * Support decode/encode of `dart:core` `Duration` |
| | | |
| | | * Code generated for fields and classes annotated with `JsonConverter` instances |
| | | now properly handles nullable fields. |
| | | |
| | | * Build configuration |
| | | |
| | | * You can now configure all settings exposed by the `JsonSerializable` |
| | | annotation within `build.yaml`. |
| | | |
| | | * **BREAKING** Unsupported options defined in `build.yaml` will cause |
| | | exceptions instead of being logged and ignored. |
| | | |
| | | * `json_serializable.dart` |
| | | |
| | | * **BREAKING** `JsonSerializableGenerator` now exposes a `config` property |
| | | of type `JsonSerializable` instead of individual properties for `checked`, |
| | | `anyMay`, etc. This will affect anyone creating or using this class via |
| | | code. |
| | | |
| | | * `type_helper.dart` |
| | | |
| | | * **BREAKING** `SerializeContext` and `DeserializeContext` have been replaced |
| | | with new `TypeHelperContext` class. |
| | | |
| | | * `TypeHelper` now has a type argument allowing implementors to specify a |
| | | specific implementation of `TypeHelperContext` for calls to `serialize` and |
| | | `deserialize`. Many of the included `TypeHelper` implementations have been |
| | | updated to indicate they expect more information from the source generator. |
| | | |
| | | ## 1.5.1 |
| | | |
| | | * Support the latest `pkg:analyzer`. |
| | | |
| | | ## 1.5.0 |
| | | |
| | | * Added support for `JsonConvert` annotation on fields. |
| | | |
| | | ## 1.4.0 |
| | | |
| | | * `type_helper.dart` |
| | | |
| | | * `TypeHelper` `serialize` and `deserialize` have return type `Object` instead |
| | | of `String`. This allows coordination between instances to support more |
| | | advanced features – like using the new `LambdaResult` class to avoid |
| | | creating unnecessary lambdas. When creating `TypeHelper` implementations, |
| | | handle non-`String` results by calling `toString()` on unrecognized values. |
| | | |
| | | * Declare support for `package:build` version `1.x.x`. |
| | | |
| | | ## 1.3.0 |
| | | |
| | | * Add support for types annotated with classes that extend `JsonConverter` from |
| | | `package:json_annotation`. |
| | | |
| | | * Export the following `TypeHelper` implementations in |
| | | `package:json_serializable/type_helper.dart`: |
| | | `ConvertHelper`, `EnumHelper`, `IterableHelper`, `JsonConverterHelper`, |
| | | `MapHelper`, `ValueHelper` |
| | | |
| | | * Added support for `Set` type as a target. |
| | | |
| | | ## 1.2.1 |
| | | |
| | | * Added back `const` for maps generated with `checked: true` configuration. |
| | | |
| | | ## 1.2.0 |
| | | |
| | | * Now throws `InvalidGenerationSourceError` instead of `UnsupportedError` for |
| | | some classes of constructor errors. |
| | | |
| | | * Supports class-static functions for `toJson` and `fromJson` on `JsonKey`. |
| | | |
| | | * Provide a warning about ignored setter-only properties instead of crashing. |
| | | |
| | | * Added back `const` for lists generated with `disallowUnrecognizedKeys`, |
| | | `required`, and `disallowNullValue`. |
| | | |
| | | * Fixed a bug when `disallowUnrecognizedKeys` is enabled. |
| | | |
| | | * Fixed a number of issues when dealing with inherited properties. |
| | | |
| | | ## 1.1.0 |
| | | |
| | | * Added support for automatically converting field names to JSON map keys as |
| | | `kebab-case` or `snake_case` with a new option on the `JsonSerializable` |
| | | annotation. |
| | | |
| | | ## 1.0.1 |
| | | |
| | | * Explicit `new` and `const` are no longer generated. |
| | | |
| | | ## 1.0.0 |
| | | |
| | | * **BREAKING** By default, code generated to support `toJson` now creates |
| | | a top-level function instead of a mixin. The default for the |
| | | `generate_to_json_function` is now `true`. To opt-out of this change, |
| | | set `generate_to_json_function` to `false`. |
| | | |
| | | * Now supports changing the serialized values of enums using `JsonValue`. |
| | | |
| | | ```dart |
| | | enum AutoApply { |
| | | none, |
| | | dependents, |
| | | @JsonValue('all_packages') |
| | | allPackages, |
| | | @JsonValue('root_package') |
| | | rootPackage |
| | | } |
| | | ``` |
| | | |
| | | * `JsonSerializableGenerator.generateForAnnotatedElement` now returns |
| | | `Iterable<String>` instead of `String`. |
| | | |
| | | * `SerializeContext` and `DeserializeContext` now have an `addMember` function |
| | | which allows `TypeHelper` instances to add additional members when handling |
| | | a field. This is useful for generating shared helpers, for instance. |
| | | |
| | | * **BREAKING** The `header` option is no longer supported and must be removed |
| | | from `build.yaml`. |
| | | |
| | | * If a manual build script is used the `json_serializable` builder must be |
| | | switched to `hideOutput: true`, and the `combiningBuilder` from `source_gen` |
| | | must be included following this builder. When using a generated build script |
| | | with `pub run build_runner` or `webdev` this is handled automatically. |
| | | |
| | | ## 0.5.8+1 |
| | | |
| | | * Support the Dart 2.0 stable release. |
| | | |
| | | ## 0.5.8 |
| | | |
| | | * Small fixes to support Dart 2 runtime semantics. |
| | | |
| | | * Support serializing types provided by platform-specific libraries (such as |
| | | Flutter) if they use custom convert functions. |
| | | |
| | | ## 0.5.7 |
| | | |
| | | * Added support for `JsonKey.required`. |
| | | * When `true`, generated code throws a `MissingRequiredKeysException` if |
| | | the key does not exist in the JSON map used to populate the annotated field. |
| | | * Will be captured and wrapped in a `CheckedFromJsonException` if |
| | | `checked` is enabled in `json_serializable`. |
| | | |
| | | * Added `JsonKey.disallowNullValue`. |
| | | * When `true`, generated code throws a `DisallowedNullValueException` if |
| | | the corresponding keys exist in in the JSON map, but it's value is null. |
| | | * Will be captured and wrapped in a `CheckedFromJsonException` if |
| | | `checked` is enabled in `json_serializable`. |
| | | |
| | | * Added support for `Uri` conversion. |
| | | |
| | | * Added missing `checked` parameter to the |
| | | `JsonSerializableGenerator.withDefaultHelpers` constructor. |
| | | |
| | | * Added `explicit_to_json` configuration option. |
| | | * See `JsonSerializableGenerator.explicitToJson` for details. |
| | | |
| | | * Added `generate_to_json_function` configuration option. |
| | | * See `JsonSerializableGenerator.generateToJsonFunction` for details. |
| | | |
| | | ## 0.5.6 |
| | | |
| | | * Added support for `JsonSerializable.disallowUnrecognizedKeys`. |
| | | * Throws an `UnrecognizedKeysException` if it finds unrecognized keys in the |
| | | JSON map used to populate the annotated field. |
| | | * Will be captured and wrapped in a `CheckedFromJsonException` if |
| | | `checked` is enabled in `json_serializable`. |
| | | * All `fromJson` constructors now use block syntax instead of fat arrows. |
| | | |
| | | ## 0.5.5 |
| | | |
| | | * Added support for `JsonKey.defaultValue`. |
| | | |
| | | * `enum` deserialization now uses helpers provided by `json_annotation`. |
| | | |
| | | * Small change to how nullable `Map` values are deserialized. |
| | | |
| | | * Small whitespace changes to `JsonLiteral` generation to align with `dartfmt`. |
| | | |
| | | * Improve detection of `toJson` and `fromJson` in nested types. |
| | | |
| | | ## 0.5.4+1 |
| | | |
| | | * Fixed a bug introduced in `0.5.4` in some cases where enum values are nested |
| | | in collections. |
| | | |
| | | ## 0.5.4 |
| | | |
| | | * Add `checked` configuration option. If `true`, generated `fromJson` functions |
| | | include extra checks to validate proper deserialization of types. |
| | | |
| | | * Added `any_map` to configuration. Allows `fromJson` code to |
| | | support dynamic `Map` instances that are not explicitly |
| | | `Map<String, dynaimc>`. |
| | | |
| | | * Added support for classes with type arguments. |
| | | |
| | | * Use `Map.map` for more map conversions. Simplifies generated code and fixes |
| | | a subtle issue when the `Map` key type is `dynamic` or `Object`. |
| | | |
| | | ## 0.5.3 |
| | | |
| | | * Require the latest version of `package:analyzer` - `v0.32.0`. |
| | | |
| | | * If `JsonKey.fromJson` function parameter is `Iterable` or `Map` with type |
| | | arguments of `dynamic` or `Object`, omit the arguments when generating a |
| | | cast. |
| | | `_myHelper(json['key'] as Map)` instead of |
| | | `_myHelper(json['key'] as Map<dynamic, dynamic>)`. |
| | | |
| | | * `JsonKey.fromJson`/`.toJson` now support functions with optional arguments. |
| | | |
| | | ## 0.5.2 |
| | | |
| | | * If `JsonKey.fromJson`/`toJson` are set, apply them before any custom |
| | | or default `TypeHelper` instances. This allows custom `DateTime` parsing, |
| | | by preempting the existing `DateTime` `TypeHelper`. |
| | | |
| | | ## 0.5.1 |
| | | |
| | | * Support new `fromJson` and `toJson` fields on `JsonKey`. |
| | | |
| | | * Use `log` exposed by `package:build`. This requires end-users to have at least |
| | | `package:build_runner` `^0.8.2`. |
| | | |
| | | * Updated minimum `package:source_gen` dependency to `0.8.1` which includes |
| | | improved error messages. |
| | | |
| | | ## 0.5.0 |
| | | |
| | | * **BREAKING** Removed deprecated support for `require_library_directive` / |
| | | `requireLibraryDirective` in `build_runner` configuration. |
| | | |
| | | * **BREAKING** Removed the deprecated `generators.dart` library. |
| | | |
| | | * **BREAKING** Removed `jsonPartBuilder` function from public API. |
| | | |
| | | * Support the latest `package:source_gen`. |
| | | |
| | | * Private and ignored fields are now excluded when generating serialization and |
| | | deserialization code by using `@JsonKey(ignore: true)`. |
| | | |
| | | * Throw an exception if a private field or an ignored field is referenced by a |
| | | required constructor argument. |
| | | |
| | | * More comprehensive escaping of string literals. |
| | | |
| | | ### `package:json_serializable/type_helper.dart` |
| | | |
| | | * **Breaking** The `nullable` parameter on `TypeHelper.serialize` and |
| | | `.deserialize` has been removed. It is now exposed in `SerializeContext` and |
| | | `DeserializeContext` abstract classes as a read-only property. |
| | | |
| | | * **Potentially Breaking** The `metadata` property on `SerializeContext` and |
| | | `DeserializeContext` is now readonly. This would potentially break code that |
| | | extends these classes – which is not expected. |
| | | |
| | | ## 0.4.0 |
| | | |
| | | * **Potentially Breaking** Inherited fields are now processed and used |
| | | when generating serialization and deserialization code. There is a possibility |
| | | that the generated code may change in undesired ways for classes annotated for |
| | | `v0.3`. |
| | | |
| | | * Avoid unnecessary braces in string escapes. |
| | | |
| | | * Use single quotes when generating code. |
| | | |
| | | ## 0.3.2 |
| | | |
| | | * The `require_library_directive` option now defaults to `false`. |
| | | The option will be removed entirely in `0.4.0`. |
| | | |
| | | ## 0.3.1+2 |
| | | |
| | | * Support the latest version of the `analyzer` package. |
| | | |
| | | ## 0.3.1+1 |
| | | |
| | | * Expanded `package:build` support to allow version `0.12.0`. |
| | | |
| | | ## 0.3.1 |
| | | |
| | | * Add a `build.yaml` so the builder can be consumed by users of `build_runner` |
| | | version 0.7.0. |
| | | |
| | | * Now requires a Dart `2.0.0-dev` release. |
| | | |
| | | ## 0.3.0 |
| | | |
| | | * **NEW** top-level library `json_serializable.dart`. |
| | | |
| | | * Replaces now deprecated `generators.dart` to access |
| | | `JsonSerializableGenerator` and `JsonLiteralGenerator`. |
| | | |
| | | * Adds the `jsonPartBuilder` function to make it easy to create a |
| | | `PartBuilder`, without creating an explicit dependency on `source_gen`. |
| | | |
| | | * **BREAKING** `UnsupportedTypeError` added a new required constructor argument: |
| | | `reason`. |
| | | |
| | | * **BREAKING** The deprecated `annotations.dart` library has been removed. |
| | | Use `package:json_annotation` instead. |
| | | |
| | | * **BREAKING** The arguments to `TypeHelper` `serialize` and `deserialize` have |
| | | changed. |
| | | * `SerializeContext` and `DeserializeContext` (new classes) are now passed |
| | | instead of the `TypeHelperGenerator` typedef (which has been deleted). |
| | | |
| | | * `JsonSerializableGenerator` now supports an optional `useWrappers` argument |
| | | when generates and uses wrapper classes to (hopefully) improve the speed and |
| | | memory usage of serialization – at the cost of more code. |
| | | |
| | | **NOTE**: `useWrappers` is not guaranteed to improve the performance of |
| | | serialization. Benchmarking is recommended. |
| | | |
| | | * Make `null` field handling smarter. If a field is classified as not |
| | | `nullable`, then use this knowledge when generating serialization code – even |
| | | if `includeIfNull` is `false`. |
| | | |
| | | ## 0.2.5 |
| | | |
| | | * Throw an exception if a duplicate JSON key is detected. |
| | | |
| | | * Support the `nullable` field on the `JsonSerializable` class annotation. |
| | | |
| | | ## 0.2.4+1 |
| | | |
| | | * Throw a more helpful error when a constructor is missing. |
| | | |
| | | ## 0.2.4 |
| | | |
| | | * Moved the annotations in `annotations.dart` to `package:json_annotations`. |
| | | * Allows package authors to release code that has the corresponding |
| | | annotations without requiring package users to inherit all of the transitive |
| | | dependencies. |
| | | |
| | | * Deprecated `annotations.dart`. |
| | | |
| | | ## 0.2.3 |
| | | |
| | | * Write out `toJson` methods more efficiently when the first fields written are |
| | | not intercepted by the null-checking method. |
| | | |
| | | ## 0.2.2+1 |
| | | |
| | | * Simplify the serialization of `Map` instances when no conversion is required |
| | | for `values`. |
| | | |
| | | * Handle `int` literals in JSON being assigned to `double` fields. |
| | | |
| | | ## 0.2.2 |
| | | |
| | | * Enable support for `enum` values. |
| | | * Added `asConst` to `JsonLiteral`. |
| | | * Improved the handling of Dart-specific characters in JSON strings. |
| | | |
| | | ## 0.2.1 |
| | | |
| | | * Upgrade to `package:source_gen` v0.7.0 |
| | | |
| | | ## 0.2.0+1 |
| | | |
| | | * When serializing classes that implement their own `fromJson` constructor, |
| | | honor their constructor parameter type. |
| | | |
| | | ## 0.2.0 |
| | | |
| | | * **BREAKING** Types are now segmented into their own libraries. |
| | | |
| | | * `package:json_serializable/generators.dart` contains `Generator` |
| | | implementations. |
| | | |
| | | * `package:json_serializable/annotations.dart` contains annotations. |
| | | This library should be imported with your target classes. |
| | | |
| | | * `package:json_serializable/type_helpers.dart` contains `TypeHelper` classes |
| | | and related helpers which allow custom generation for specific types. |
| | | |
| | | * **BREAKING** Generation fails for types that are not a JSON primitive or that |
| | | do not explicitly supports JSON serialization. |
| | | |
| | | * **BREAKING** `TypeHelper`: |
| | | |
| | | * Removed `can` methods. Return `null` from `(de)serialize` if the provided |
| | | type is not supported. |
| | | |
| | | * Added `(de)serializeNested` arguments to `(de)serialize` methods allowing |
| | | generic types. This is how support for `Iterable`, `List`, and `Map` |
| | | is implemented. |
| | | |
| | | * **BREAKING** `JsonKey.jsonName` was renamed to `name` and is now a named |
| | | parameter. |
| | | |
| | | * Added support for optional, non-nullable fields. |
| | | |
| | | * Added support for excluding `null` values when generating JSON. |
| | | |
| | | * Eliminated all implicit casts in generated code. These would end up being |
| | | runtime checks in most cases. |
| | | |
| | | * Provide a helpful error when generation fails due to undefined types. |
| | | |
| | | ## 0.1.0+1 |
| | | |
| | | * Fix homepage in `pubspec.yaml`. |
| | | |
| | | ## 0.1.0 |
| | | |
| | | * Split off from [source_gen](https://pub.dartlang.org/packages/source_gen). |
| | | |
| | | * Add `/* unsafe */` comments to generated output likely to be unsafe. |
| | | |
| | | * Support (de)serializing values in `Map`. |
| | | |
| | | * Fix ordering of fields when they are initialized via constructor. |
| | | |
| | | * Don't use static members when calculating fields to (de)serialize. |
| New file |
| | |
| | | Want to contribute? Great! First, read this page (including the small print at |
| | | the end). |
| | | |
| | | ### Before you contribute |
| | | Before we can use your code, you must sign the |
| | | [Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) |
| | | (CLA), which you can do online. The CLA is necessary mainly because you own the |
| | | copyright to your changes, even after your contribution becomes part of our |
| | | codebase, so we need your permission to use and distribute your code. We also |
| | | need to be sure of various other things—for instance that you'll tell us if you |
| | | know that your code infringes on other people's patents. You don't have to sign |
| | | the CLA until after you've submitted your code for review and a member has |
| | | approved it, but you must do it before we can put your code into our codebase. |
| | | |
| | | Before you start working on a larger contribution, you should get in touch with |
| | | us first through the issue tracker with your idea so that we can help out and |
| | | possibly guide you. Coordinating up front makes it much easier to avoid |
| | | frustration later on. |
| | | |
| | | ### Code reviews |
| | | All submissions, including submissions by project members, require review. |
| | | |
| | | ### File headers |
| | | All files in the project must start with the following header. |
| | | |
| | | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | ### The small print |
| | | Contributions made by corporations are covered by a different agreement than the |
| | | one above, the |
| | | [Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate). |
| New file |
| | |
| | | Copyright 2017, the Dart project authors. All rights reserved. |
| | | Redistribution and use in source and binary forms, with or without |
| | | modification, are permitted provided that the following conditions are |
| | | met: |
| | | |
| | | * Redistributions of source code must retain the above copyright |
| | | notice, this list of conditions and the following disclaimer. |
| | | * Redistributions in binary form must reproduce the above |
| | | copyright notice, this list of conditions and the following |
| | | disclaimer in the documentation and/or other materials provided |
| | | with the distribution. |
| | | * Neither the name of Google Inc. nor the names of its |
| | | contributors may be used to endorse or promote products derived |
| | | from this software without specific prior written permission. |
| | | |
| | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| New file |
| | |
| | | [](https://travis-ci.org/dart-lang/json_serializable) |
| | | |
| | | Provides [Dart Build System] builders for handling JSON. |
| | | |
| | | The builders generate code when they find members annotated with classes defined |
| | | in [package:json_annotation]. |
| | | |
| | | - To generate to/from JSON code for a class, annotate it with |
| | | `JsonSerializable`. You can provide arguments to `JsonSerializable` to |
| | | configure the generated code. You can also customize individual fields |
| | | by annotating them with `JsonKey` and providing custom arguments. |
| | | |
| | | - To generate a Dart field with the contents of a file containting JSON, use the |
| | | `JsonLiteral` annotation. |
| | | |
| | | To configure your project for the latest released version of, |
| | | `json_serializable` see the [example]. |
| | | |
| | | ## Example |
| | | |
| | | Given a library `example.dart` with an `Person` class annotated with |
| | | `@JsonSerializable()`: |
| | | |
| | | ```dart |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | part 'example.g.dart'; |
| | | |
| | | @JsonSerializable(nullable: false) |
| | | class Person { |
| | | final String firstName; |
| | | final String lastName; |
| | | final DateTime dateOfBirth; |
| | | Person({this.firstName, this.lastName, this.dateOfBirth}); |
| | | factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json); |
| | | Map<String, dynamic> toJson() => _$PersonToJson(this); |
| | | } |
| | | ``` |
| | | |
| | | Building creates the corresponding part `example.g.dart`: |
| | | |
| | | ```dart |
| | | part of 'example.dart'; |
| | | |
| | | Person _$PersonFromJson(Map<String, dynamic> json) { |
| | | return Person( |
| | | firstName: json['firstName'] as String, |
| | | lastName: json['lastName'] as String, |
| | | dateOfBirth: DateTime.parse(json['dateOfBirth'] as String)); |
| | | } |
| | | |
| | | Map<String, dynamic> _$PersonToJson(Person instance) => <String, dynamic>{ |
| | | 'firstName': instance.firstName, |
| | | 'lastName': instance.lastName, |
| | | 'dateOfBirth': instance.dateOfBirth.toIso8601String() |
| | | }; |
| | | ``` |
| | | |
| | | # Build configuration |
| | | |
| | | Besides setting arguments on the associated annotation classes, you can also |
| | | configure code generation by setting values in `build.yaml`. |
| | | |
| | | ```yaml |
| | | targets: |
| | | $default: |
| | | builders: |
| | | json_serializable: |
| | | options: |
| | | # Options configure how source code is generated for every |
| | | # `@JsonSerializable`-annotated class in the package. |
| | | # |
| | | # The default value for each is listed. |
| | | # |
| | | # For usage information, reference the corresponding field in |
| | | # `JsonSerializableGenerator`. |
| | | any_map: false |
| | | checked: false |
| | | create_factory: true |
| | | create_to_json: true |
| | | disallow_unrecognized_keys: false |
| | | explicit_to_json: false |
| | | field_rename: none |
| | | generate_to_json_function: true |
| | | include_if_null: true |
| | | nullable: true |
| | | use_wrappers: false |
| | | ``` |
| | | |
| | | [example]: https://github.com/dart-lang/json_serializable/blob/master/example |
| | | [Dart Build System]: https://github.com/dart-lang/build |
| | | [package:json_annotation]: https://pub.dartlang.org/packages/json_annotation |
| New file |
| | |
| | | # Read about `build.yaml` at https://pub.dartlang.org/packages/build_config |
| | | targets: |
| | | $default: |
| | | builders: |
| | | json_serializable: |
| | | enabled: true |
| | | generate_for: |
| | | include: |
| | | - example/* |
| | | - test/default_value/* |
| | | - test/generic_files/* |
| | | - test/integration/* |
| | | - test/kitchen_sink/* |
| | | - test/literal/* |
| | | - test/yaml/* |
| | | build_web_compilers|entrypoint: |
| | | generate_for: |
| | | - test/default_value/** |
| | | - test/generic_files/*_test.dart |
| | | - test/integration/*_test.dart |
| | | - test/kitchen_sink/** |
| | | |
| | | builders: |
| | | checked: |
| | | import: 'tool/builder.dart' |
| | | builder_factories: ['checked'] |
| | | build_extensions: {".dart": [".checked.dart"]} |
| | | auto_apply: root_package |
| | | build_to: source |
| | | runs_before: ["json_serializable"] |
| | | defaults: |
| | | generate_for: |
| | | - test/default_value/default_value.dart |
| | | - test/kitchen_sink/kitchen_sink.non_nullable.dart |
| | | |
| | | non_null: |
| | | import: 'tool/builder.dart' |
| | | builder_factories: ['nonNull'] |
| | | build_extensions: {".dart": [".non_nullable.dart"]} |
| | | auto_apply: root_package |
| | | build_to: source |
| | | runs_before: ["json_serializable"] |
| | | defaults: |
| | | generate_for: |
| | | - test/kitchen_sink/kitchen_sink.dart |
| | | - test/integration/json_test_example.dart |
| | | |
| | | wrapped: |
| | | import: 'tool/builder.dart' |
| | | builder_factories: ['wrapped'] |
| | | build_extensions: {".dart": [".wrapped.dart"]} |
| | | auto_apply: root_package |
| | | build_to: source |
| | | runs_before: ["json_serializable"] |
| | | defaults: |
| | | generate_for: |
| | | - test/generic_files/generic_class.dart |
| | | - test/kitchen_sink/kitchen_sink.dart |
| | | - test/kitchen_sink/kitchen_sink.non_nullable.dart |
| | | - test/integration/json_test_example.dart |
| | | - test/integration/json_test_example.non_nullable.dart |
| | | |
| | | json_serializable: |
| | | import: "package:json_serializable/builder.dart" |
| | | builder_factories: ["jsonSerializable"] |
| | | build_extensions: {".dart": ["json_serializable.g.part"]} |
| | | auto_apply: dependents |
| | | build_to: cache |
| | | applies_builders: ["source_gen|combining_builder"] |
| New file |
| | |
| | | tags: |
| | | presubmit-only: |
| | | skip: "Should only be run during presubmit" |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | part 'example.g.dart'; |
| | | |
| | | @JsonSerializable(nullable: false) |
| | | class Person { |
| | | final String firstName; |
| | | final String lastName; |
| | | final DateTime dateOfBirth; |
| | | Person({this.firstName, this.lastName, this.dateOfBirth}); |
| | | factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json); |
| | | Map<String, dynamic> toJson() => _$PersonToJson(this); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'example.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | Person _$PersonFromJson(Map<String, dynamic> json) { |
| | | return Person( |
| | | firstName: json['firstName'] as String, |
| | | lastName: json['lastName'] as String, |
| | | dateOfBirth: DateTime.parse(json['dateOfBirth'] as String)); |
| | | } |
| | | |
| | | Map<String, dynamic> _$PersonToJson(Person instance) => <String, dynamic>{ |
| | | 'firstName': instance.firstName, |
| | | 'lastName': instance.lastName, |
| | | 'dateOfBirth': instance.dateOfBirth.toIso8601String() |
| | | }; |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | /// Configuration for using `package:build`-compatible build systems. |
| | | /// |
| | | /// See: |
| | | /// * [build_runner](https://pub.dartlang.org/packages/build_runner) |
| | | /// |
| | | /// This library is **not** intended to be imported by typical end-users unless |
| | | /// you are creating a custom compilation pipeline. See documentation for |
| | | /// details, and `build.yaml` for how these builders are configured by default. |
| | | library json_serializable.builder; |
| | | |
| | | import 'package:build/build.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'src/json_part_builder.dart'; |
| | | |
| | | /// Supports `package:build_runner` creation and configuration of |
| | | /// `json_serializable`. |
| | | /// |
| | | /// Not meant to be invoked by hand-authored code. |
| | | Builder jsonSerializable(BuilderOptions options) { |
| | | final config = JsonSerializable.fromJson(options.config); |
| | | return jsonPartBuilder(config: config); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | export 'src/json_literal_generator.dart' show JsonLiteralGenerator; |
| | | export 'src/json_serializable_generator.dart' show JsonSerializableGenerator; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | /// Name used for closure argument when generating calls to `map`. |
| | | final closureArg = 'e'; |
| | | |
| | | const generatedLocalVarName = 'val'; |
| | | const toJsonMapHelperName = 'writeNotNull'; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import 'helper_core.dart'; |
| | | import 'json_literal_generator.dart'; |
| | | import 'type_helper.dart'; |
| | | import 'utils.dart'; |
| | | |
| | | class CreateFactoryResult { |
| | | final String output; |
| | | final Set<String> usedFields; |
| | | |
| | | CreateFactoryResult(this.output, this.usedFields); |
| | | } |
| | | |
| | | abstract class DecodeHelper implements HelperCore { |
| | | final StringBuffer _buffer = StringBuffer(); |
| | | |
| | | CreateFactoryResult createFactory(Map<String, FieldElement> accessibleFields, |
| | | Map<String, String> unavailableReasons) { |
| | | assert(config.createFactory); |
| | | assert(_buffer.isEmpty); |
| | | |
| | | final mapType = config.anyMap ? 'Map' : 'Map<String, dynamic>'; |
| | | _buffer.write('$targetClassReference ' |
| | | '${prefix}FromJson${genericClassArgumentsImpl(true)}' |
| | | '($mapType json) {\n'); |
| | | |
| | | String deserializeFun(String paramOrFieldName, |
| | | {ParameterElement ctorParam}) => |
| | | _deserializeForField(accessibleFields[paramOrFieldName], |
| | | ctorParam: ctorParam); |
| | | |
| | | _ConstructorData data; |
| | | if (config.checked) { |
| | | final classLiteral = escapeDartString(element.name); |
| | | |
| | | _buffer.write(''' |
| | | return \$checkedNew( |
| | | $classLiteral, |
| | | json, |
| | | () {\n'''); |
| | | |
| | | data = _writeConstructorInvocation( |
| | | element, |
| | | accessibleFields.keys, |
| | | accessibleFields.values |
| | | .where((fe) => !fe.isFinal) |
| | | .map((fe) => fe.name) |
| | | .toList(), |
| | | unavailableReasons, |
| | | deserializeFun); |
| | | |
| | | _writeChecks( |
| | | 6, |
| | | config, |
| | | accessibleFields.values |
| | | .where((fe) => data.usedCtorParamsAndFields.contains(fe.name))); |
| | | _buffer.write(''' |
| | | final val = ${data.content};'''); |
| | | |
| | | for (final field in data.fieldsToSet) { |
| | | _buffer.writeln(); |
| | | final safeName = safeNameAccess(accessibleFields[field]); |
| | | _buffer.write(''' |
| | | \$checkedConvert(json, $safeName, (v) => '''); |
| | | _buffer.write('val.$field = '); |
| | | _buffer.write(_deserializeForField(accessibleFields[field], |
| | | checkedProperty: true)); |
| | | _buffer.write(');'); |
| | | } |
| | | |
| | | _buffer.write('''\n return val; |
| | | }'''); |
| | | |
| | | final fieldKeyMap = Map.fromEntries(data.usedCtorParamsAndFields |
| | | .map((k) => MapEntry(k, nameAccess(accessibleFields[k]))) |
| | | .where((me) => me.key != me.value)); |
| | | |
| | | String fieldKeyMapArg; |
| | | if (fieldKeyMap.isEmpty) { |
| | | fieldKeyMapArg = ''; |
| | | } else { |
| | | final mapLiteral = jsonMapAsDart(fieldKeyMap); |
| | | fieldKeyMapArg = ', fieldKeyMap: const $mapLiteral'; |
| | | } |
| | | |
| | | _buffer.write(fieldKeyMapArg); |
| | | |
| | | _buffer.write(')'); |
| | | } else { |
| | | data = _writeConstructorInvocation( |
| | | element, |
| | | accessibleFields.keys, |
| | | accessibleFields.values |
| | | .where((fe) => !fe.isFinal) |
| | | .map((fe) => fe.name) |
| | | .toList(), |
| | | unavailableReasons, |
| | | deserializeFun); |
| | | |
| | | _writeChecks( |
| | | 2, |
| | | config, |
| | | accessibleFields.values |
| | | .where((fe) => data.usedCtorParamsAndFields.contains(fe.name))); |
| | | |
| | | _buffer.write(''' |
| | | return ${data.content}'''); |
| | | for (final field in data.fieldsToSet) { |
| | | _buffer.writeln(); |
| | | _buffer.write(' ..$field = '); |
| | | _buffer.write(deserializeFun(field)); |
| | | } |
| | | } |
| | | _buffer.writeln(';\n}'); |
| | | _buffer.writeln(); |
| | | |
| | | return CreateFactoryResult( |
| | | _buffer.toString(), data.usedCtorParamsAndFields); |
| | | } |
| | | |
| | | void _writeChecks(int indent, JsonSerializable classAnnotation, |
| | | Iterable<FieldElement> accessibleFields) { |
| | | final args = <String>[]; |
| | | |
| | | String constantList(Iterable<FieldElement> things) => |
| | | 'const ${jsonLiteralAsDart(things.map(nameAccess).toList())}'; |
| | | |
| | | if (classAnnotation.disallowUnrecognizedKeys) { |
| | | final allowKeysLiteral = constantList(accessibleFields); |
| | | |
| | | args.add('allowedKeys: $allowKeysLiteral'); |
| | | } |
| | | |
| | | final requiredKeys = |
| | | accessibleFields.where((fe) => jsonKeyFor(fe).required).toList(); |
| | | if (requiredKeys.isNotEmpty) { |
| | | final requiredKeyLiteral = constantList(requiredKeys); |
| | | |
| | | args.add('requiredKeys: $requiredKeyLiteral'); |
| | | } |
| | | |
| | | final disallowNullKeys = accessibleFields |
| | | .where((fe) => jsonKeyFor(fe).disallowNullValue) |
| | | .toList(); |
| | | if (disallowNullKeys.isNotEmpty) { |
| | | final dissallowNullKeyLiteral = constantList(disallowNullKeys); |
| | | |
| | | args.add('disallowNullValues: $dissallowNullKeyLiteral'); |
| | | } |
| | | |
| | | if (args.isNotEmpty) { |
| | | _buffer.writeln('${' ' * indent}\$checkKeys(json, ${args.join(', ')});'); |
| | | } |
| | | } |
| | | |
| | | String _deserializeForField(FieldElement field, |
| | | {ParameterElement ctorParam, bool checkedProperty}) { |
| | | checkedProperty ??= false; |
| | | final jsonKeyName = safeNameAccess(field); |
| | | final targetType = ctorParam?.type ?? field.type; |
| | | final contextHelper = getHelperContext(field); |
| | | |
| | | String value; |
| | | try { |
| | | if (config.checked) { |
| | | value = contextHelper.deserialize(targetType, 'v').toString(); |
| | | if (!checkedProperty) { |
| | | value = '\$checkedConvert(json, $jsonKeyName, (v) => $value)'; |
| | | } |
| | | } else { |
| | | assert(!checkedProperty, |
| | | 'should only be true if `_generator.checked` is true.'); |
| | | |
| | | value = contextHelper |
| | | .deserialize(targetType, 'json[$jsonKeyName]') |
| | | .toString(); |
| | | } |
| | | } on UnsupportedTypeError catch (e) { |
| | | throw createInvalidGenerationError('fromJson', field, e); |
| | | } |
| | | |
| | | final defaultValue = jsonKeyFor(field).defaultValue; |
| | | if (defaultValue != null) { |
| | | if (!contextHelper.nullable) { |
| | | throwUnsupported(field, |
| | | 'Cannot use `defaultValue` on a field with `nullable` false.'); |
| | | } |
| | | |
| | | value = '$value ?? $defaultValue'; |
| | | } |
| | | return value; |
| | | } |
| | | } |
| | | |
| | | /// [availableConstructorParameters] is checked to see if it is available. If |
| | | /// [availableConstructorParameters] does not contain the parameter name, |
| | | /// an [UnsupportedError] is thrown. |
| | | /// |
| | | /// To improve the error details, [unavailableReasons] is checked for the |
| | | /// unavailable constructor parameter. If the value is not `null`, it is |
| | | /// included in the [UnsupportedError] message. |
| | | /// |
| | | /// [writeableFields] are also populated, but only if they have not already |
| | | /// been defined by a constructor parameter with the same name. |
| | | _ConstructorData _writeConstructorInvocation( |
| | | ClassElement classElement, |
| | | Iterable<String> availableConstructorParameters, |
| | | Iterable<String> writeableFields, |
| | | Map<String, String> unavailableReasons, |
| | | String deserializeForField(String paramOrFieldName, |
| | | {ParameterElement ctorParam})) { |
| | | final className = classElement.name; |
| | | |
| | | final ctor = classElement.unnamedConstructor; |
| | | if (ctor == null) { |
| | | // TODO(kevmoo): support using another ctor - dart-lang/json_serializable#50 |
| | | throw UnsupportedError( |
| | | 'The class `$className` has no default constructor.'); |
| | | } |
| | | |
| | | final usedCtorParamsAndFields = Set<String>(); |
| | | final constructorArguments = <ParameterElement>[]; |
| | | final namedConstructorArguments = <ParameterElement>[]; |
| | | |
| | | for (final arg in ctor.parameters) { |
| | | if (!availableConstructorParameters.contains(arg.name)) { |
| | | if (arg.isNotOptional) { |
| | | var msg = 'Cannot populate the required constructor ' |
| | | 'argument: ${arg.name}.'; |
| | | |
| | | final additionalInfo = unavailableReasons[arg.name]; |
| | | |
| | | if (additionalInfo != null) { |
| | | msg = '$msg $additionalInfo'; |
| | | } |
| | | |
| | | throw InvalidGenerationSourceError(msg, element: ctor); |
| | | } |
| | | |
| | | continue; |
| | | } |
| | | |
| | | // TODO: validate that the types match! |
| | | if (arg.isNamed) { |
| | | namedConstructorArguments.add(arg); |
| | | } else { |
| | | constructorArguments.add(arg); |
| | | } |
| | | usedCtorParamsAndFields.add(arg.name); |
| | | } |
| | | |
| | | warnUndefinedElements( |
| | | constructorArguments.followedBy(namedConstructorArguments)); |
| | | |
| | | // fields that aren't already set by the constructor and that aren't final |
| | | final remainingFieldsForInvocationBody = |
| | | writeableFields.toSet().difference(usedCtorParamsAndFields); |
| | | |
| | | final buffer = StringBuffer(); |
| | | buffer.write('$className${genericClassArguments(classElement, false)}('); |
| | | if (constructorArguments.isNotEmpty) { |
| | | buffer.writeln(); |
| | | buffer.writeAll(constructorArguments.map((paramElement) { |
| | | final content = |
| | | deserializeForField(paramElement.name, ctorParam: paramElement); |
| | | return ' $content'; |
| | | }), ',\n'); |
| | | if (namedConstructorArguments.isNotEmpty) { |
| | | buffer.write(','); |
| | | } |
| | | } |
| | | if (namedConstructorArguments.isNotEmpty) { |
| | | buffer.writeln(); |
| | | buffer.writeAll(namedConstructorArguments.map((paramElement) { |
| | | final value = |
| | | deserializeForField(paramElement.name, ctorParam: paramElement); |
| | | return ' ${paramElement.name}: $value'; |
| | | }), ',\n'); |
| | | } |
| | | |
| | | buffer.write(')'); |
| | | |
| | | usedCtorParamsAndFields.addAll(remainingFieldsForInvocationBody); |
| | | |
| | | return _ConstructorData(buffer.toString(), remainingFieldsForInvocationBody, |
| | | usedCtorParamsAndFields); |
| | | } |
| | | |
| | | class _ConstructorData { |
| | | final String content; |
| | | final Set<String> fieldsToSet; |
| | | final Set<String> usedCtorParamsAndFields; |
| | | _ConstructorData( |
| | | this.content, this.fieldsToSet, this.usedCtorParamsAndFields); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'constants.dart'; |
| | | import 'helper_core.dart'; |
| | | import 'type_helper.dart'; |
| | | |
| | | abstract class EncodeHelper implements HelperCore { |
| | | String _fieldAccess(FieldElement field) { |
| | | var fieldAccess = field.name; |
| | | if (config.generateToJsonFunction) { |
| | | fieldAccess = '$_toJsonParamName.$fieldAccess'; |
| | | } |
| | | return fieldAccess; |
| | | } |
| | | |
| | | String _mixinClassName(bool withConstraints) => |
| | | '${prefix}SerializerMixin${genericClassArgumentsImpl(withConstraints)}'; |
| | | |
| | | String _wrapperClassName([bool withConstraints]) => |
| | | '${prefix}JsonMapWrapper${genericClassArgumentsImpl(withConstraints)}'; |
| | | |
| | | Iterable<String> createToJson(Set<FieldElement> accessibleFields) sync* { |
| | | assert(config.createToJson); |
| | | |
| | | final buffer = StringBuffer(); |
| | | |
| | | if (config.generateToJsonFunction) { |
| | | final functionName = '${prefix}ToJson${genericClassArgumentsImpl(true)}'; |
| | | buffer.write('Map<String, dynamic> $functionName' |
| | | '($targetClassReference $_toJsonParamName) '); |
| | | } else { |
| | | // |
| | | // Generate the mixin class |
| | | // |
| | | buffer.writeln('abstract class ${_mixinClassName(true)} {'); |
| | | |
| | | // write copies of the fields - this allows the toJson method to access |
| | | // the fields of the target class |
| | | for (final field in accessibleFields) { |
| | | //TODO - handle aliased imports |
| | | buffer.writeln(' ${field.type} get ${field.name};'); |
| | | } |
| | | |
| | | buffer.write(' Map<String, dynamic> toJson() '); |
| | | } |
| | | |
| | | final writeNaive = accessibleFields.every(_writeJsonValueNaive); |
| | | |
| | | if (config.useWrappers) { |
| | | final param = config.generateToJsonFunction ? _toJsonParamName : 'this'; |
| | | buffer.writeln('=> ${_wrapperClassName(false)}($param);'); |
| | | } else { |
| | | if (writeNaive) { |
| | | // write simple `toJson` method that includes all keys... |
| | | _writeToJsonSimple(buffer, accessibleFields); |
| | | } else { |
| | | // At least one field should be excluded if null |
| | | _writeToJsonWithNullChecks(buffer, accessibleFields); |
| | | } |
| | | } |
| | | |
| | | if (!config.generateToJsonFunction) { |
| | | // end of the mixin class |
| | | buffer.writeln('}'); |
| | | } |
| | | |
| | | yield buffer.toString(); |
| | | |
| | | if (config.useWrappers) { |
| | | yield _createWrapperClass(accessibleFields); |
| | | } |
| | | } |
| | | |
| | | String _createWrapperClass(Iterable<FieldElement> fields) { |
| | | final buffer = StringBuffer(); |
| | | buffer.writeln(); |
| | | // TODO(kevmoo): write JsonMapWrapper if annotation lib is prefix-imported |
| | | |
| | | final fieldType = config.generateToJsonFunction |
| | | ? targetClassReference |
| | | : _mixinClassName(false); |
| | | |
| | | buffer.writeln(''' |
| | | class ${_wrapperClassName(true)} extends \$JsonMapWrapper { |
| | | final $fieldType _v; |
| | | ${_wrapperClassName()}(this._v); |
| | | '''); |
| | | |
| | | if (fields.every(_writeJsonValueNaive)) { |
| | | // TODO(kevmoo): consider just doing one code path – if it's fast |
| | | // enough |
| | | final jsonKeys = fields.map(safeNameAccess).join(', '); |
| | | |
| | | // TODO(kevmoo): maybe put this in a static field instead? |
| | | // const lists have unfortunate overhead |
| | | buffer.writeln(''' |
| | | @override |
| | | Iterable<String> get keys => const [$jsonKeys]; |
| | | '''); |
| | | } else { |
| | | // At least one field should be excluded if null |
| | | buffer.writeln(' @override\n Iterable<String> get keys sync* {'); |
| | | |
| | | for (final field in fields) { |
| | | final nullCheck = !_writeJsonValueNaive(field); |
| | | if (nullCheck) { |
| | | buffer.write(' if (_v.${field.name} != null) {\n '); |
| | | } |
| | | buffer.writeln(' yield ${safeNameAccess(field)};'); |
| | | if (nullCheck) { |
| | | buffer.writeln(' }'); |
| | | } |
| | | } |
| | | |
| | | buffer.writeln(' }\n'); |
| | | } |
| | | |
| | | buffer.writeln(''' |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) {'''); |
| | | |
| | | for (final field in fields) { |
| | | final valueAccess = '_v.${field.name}'; |
| | | buffer.writeln(''' |
| | | case ${safeNameAccess(field)}: |
| | | return ${_serializeField(field, valueAccess)};'''); |
| | | } |
| | | |
| | | buffer.writeln(''' |
| | | } |
| | | } |
| | | return null; |
| | | }'''); |
| | | |
| | | buffer.writeln('}'); |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | void _writeToJsonSimple(StringBuffer buffer, Iterable<FieldElement> fields) { |
| | | buffer.writeln('=> <String, dynamic>{'); |
| | | |
| | | buffer.writeAll(fields.map((field) { |
| | | final access = _fieldAccess(field); |
| | | final value = |
| | | '${safeNameAccess(field)}: ${_serializeField(field, access)}'; |
| | | return ' $value'; |
| | | }), ',\n'); |
| | | |
| | | if (fields.isNotEmpty) { |
| | | buffer.write('\n '); |
| | | } |
| | | |
| | | buffer.writeln('};'); |
| | | } |
| | | |
| | | /// Name of the parameter used when generating top-level `toJson` functions |
| | | /// if [JsonSerializable.generateToJsonFunction] is `true`. |
| | | static const _toJsonParamName = 'instance'; |
| | | |
| | | void _writeToJsonWithNullChecks( |
| | | StringBuffer buffer, Iterable<FieldElement> fields) { |
| | | buffer.writeln('{'); |
| | | |
| | | buffer.writeln(' final $generatedLocalVarName = <String, dynamic>{'); |
| | | |
| | | // Note that the map literal is left open above. As long as target fields |
| | | // don't need to be intercepted by the `only if null` logic, write them |
| | | // to the map literal directly. In theory, should allow more efficient |
| | | // serialization. |
| | | var directWrite = true; |
| | | |
| | | for (final field in fields) { |
| | | var safeFieldAccess = _fieldAccess(field); |
| | | final safeJsonKeyString = safeNameAccess(field); |
| | | |
| | | // If `fieldName` collides with one of the local helpers, prefix |
| | | // access with `this.`. |
| | | if (safeFieldAccess == generatedLocalVarName || |
| | | safeFieldAccess == toJsonMapHelperName) { |
| | | assert(!config.generateToJsonFunction, |
| | | 'This code path should only be hit during the mixin codepath.'); |
| | | safeFieldAccess = 'this.$safeFieldAccess'; |
| | | } |
| | | |
| | | final expression = _serializeField(field, safeFieldAccess); |
| | | if (_writeJsonValueNaive(field)) { |
| | | if (directWrite) { |
| | | buffer.writeln(' $safeJsonKeyString: $expression,'); |
| | | } else { |
| | | buffer.writeln( |
| | | ' $generatedLocalVarName[$safeJsonKeyString] = $expression;'); |
| | | } |
| | | } else { |
| | | if (directWrite) { |
| | | // close the still-open map literal |
| | | buffer.writeln(' };'); |
| | | buffer.writeln(); |
| | | |
| | | // write the helper to be used by all following null-excluding |
| | | // fields |
| | | buffer.writeln(''' |
| | | void $toJsonMapHelperName(String key, dynamic value) { |
| | | if (value != null) { |
| | | $generatedLocalVarName[key] = value; |
| | | } |
| | | } |
| | | '''); |
| | | directWrite = false; |
| | | } |
| | | buffer.writeln( |
| | | ' $toJsonMapHelperName($safeJsonKeyString, $expression);'); |
| | | } |
| | | } |
| | | |
| | | buffer.writeln(' return $generatedLocalVarName;'); |
| | | buffer.writeln(' }'); |
| | | } |
| | | |
| | | String _serializeField(FieldElement field, String accessExpression) { |
| | | try { |
| | | return getHelperContext(field) |
| | | .serialize(field.type, accessExpression) |
| | | .toString(); |
| | | } on UnsupportedTypeError catch (e) { |
| | | throw createInvalidGenerationError('toJson', field, e); |
| | | } |
| | | } |
| | | |
| | | /// Returns `true` if the field can be written to JSON 'naively' – meaning |
| | | /// we can avoid checking for `null`. |
| | | /// |
| | | /// `true` if either: |
| | | /// `includeIfNull` is `true` |
| | | /// or |
| | | /// `nullable` is `false`. |
| | | bool _writeJsonValueNaive(FieldElement field) => |
| | | jsonKeyFor(field).includeIfNull || !jsonKeyFor(field).nullable; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | // ignore: implementation_imports |
| | | import 'package:analyzer/src/dart/resolver/inheritance_manager.dart' |
| | | show InheritanceManager; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import 'helper_core.dart'; |
| | | import 'utils.dart'; |
| | | |
| | | class _FieldSet implements Comparable<_FieldSet> { |
| | | final FieldElement field; |
| | | final FieldElement sortField; |
| | | |
| | | _FieldSet._(this.field, this.sortField) |
| | | : assert(field.name == sortField.name); |
| | | |
| | | factory _FieldSet(FieldElement classField, FieldElement superField) { |
| | | // At least one of these will != null, perhaps both. |
| | | final fields = [classField, superField].where((fe) => fe != null).toList(); |
| | | |
| | | // Prefer the class field over the inherited field when sorting. |
| | | final sortField = fields.first; |
| | | |
| | | // Prefer the field that's annotated with `JsonKey`, if any. |
| | | // If not, use the class field. |
| | | final fieldHasJsonKey = |
| | | fields.firstWhere(hasJsonKeyAnnotation, orElse: () => fields.first); |
| | | |
| | | return _FieldSet._(fieldHasJsonKey, sortField); |
| | | } |
| | | |
| | | @override |
| | | int compareTo(_FieldSet other) => _sortByLocation(sortField, other.sortField); |
| | | |
| | | static int _sortByLocation(FieldElement a, FieldElement b) { |
| | | final checkerA = TypeChecker.fromStatic(a.enclosingElement.type); |
| | | |
| | | if (!checkerA.isExactly(b.enclosingElement)) { |
| | | // in this case, you want to prioritize the enclosingElement that is more |
| | | // "super". |
| | | |
| | | if (checkerA.isSuperOf(b.enclosingElement)) { |
| | | return -1; |
| | | } |
| | | |
| | | final checkerB = TypeChecker.fromStatic(b.enclosingElement.type); |
| | | |
| | | if (checkerB.isSuperOf(a.enclosingElement)) { |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | /// Returns the offset of given field/property in its source file – with a |
| | | /// preference for the getter if it's defined. |
| | | int _offsetFor(FieldElement e) { |
| | | if (e.getter != null && e.getter.nameOffset != e.nameOffset) { |
| | | assert(e.nameOffset == -1); |
| | | return e.getter.nameOffset; |
| | | } |
| | | return e.nameOffset; |
| | | } |
| | | |
| | | return _offsetFor(a).compareTo(_offsetFor(b)); |
| | | } |
| | | } |
| | | |
| | | /// Returns a [Set] of all instance [FieldElement] items for [element] and |
| | | /// super classes, sorted first by their location in the inheritance hierarchy |
| | | /// (super first) and then by their location in the source file. |
| | | Iterable<FieldElement> createSortedFieldSet(ClassElement element) { |
| | | // Get all of the fields that need to be assigned |
| | | // TODO: support overriding the field set with an annotation option |
| | | final elementInstanceFields = Map.fromEntries( |
| | | element.fields.where((e) => !e.isStatic).map((e) => MapEntry(e.name, e))); |
| | | |
| | | final inheritedFields = <String, FieldElement>{}; |
| | | final manager = InheritanceManager(element.library); |
| | | |
| | | // ignore: deprecated_member_use |
| | | for (final v in manager.getMembersInheritedFromClasses(element).values) { |
| | | assert(v is! FieldElement); |
| | | if (_dartCoreObjectChecker.isExactly(v.enclosingElement)) { |
| | | continue; |
| | | } |
| | | |
| | | if (v is PropertyAccessorElement && v.isGetter) { |
| | | assert(v.variable is FieldElement); |
| | | final variable = v.variable as FieldElement; |
| | | assert(!inheritedFields.containsKey(variable.name)); |
| | | inheritedFields[variable.name] = variable; |
| | | } |
| | | } |
| | | |
| | | // Get the list of all fields for `element` |
| | | final allFields = |
| | | elementInstanceFields.keys.toSet().union(inheritedFields.keys.toSet()); |
| | | |
| | | final fields = allFields |
| | | .map((e) => _FieldSet(elementInstanceFields[e], inheritedFields[e])) |
| | | .toList(); |
| | | |
| | | // Sort the fields using the `compare` implementation in _FieldSet |
| | | fields.sort(); |
| | | |
| | | final fieldList = fields.map((fs) => fs.field).toList(); |
| | | warnUndefinedElements(fieldList); |
| | | return fieldList; |
| | | } |
| | | |
| | | const _dartCoreObjectChecker = TypeChecker.fromRuntime(Object); |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:build/build.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:meta/meta.dart'; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import 'json_key_utils.dart'; |
| | | import 'type_helper.dart'; |
| | | import 'type_helper_ctx.dart'; |
| | | import 'utils.dart'; |
| | | |
| | | abstract class HelperCore { |
| | | final ClassElement element; |
| | | final JsonSerializable config; |
| | | |
| | | HelperCore(this.element, this.config); |
| | | |
| | | Iterable<TypeHelper> get allTypeHelpers; |
| | | |
| | | void addMember(String memberContent); |
| | | |
| | | @protected |
| | | String get targetClassReference => |
| | | '${element.name}${genericClassArgumentsImpl(false)}'; |
| | | |
| | | @protected |
| | | String nameAccess(FieldElement field) => jsonKeyFor(field).name; |
| | | |
| | | @protected |
| | | String safeNameAccess(FieldElement field) => |
| | | escapeDartString(nameAccess(field)); |
| | | |
| | | @protected |
| | | String get prefix => '_\$${element.name}'; |
| | | |
| | | /// Returns a [String] representing the type arguments that exist on |
| | | /// [element]. |
| | | /// |
| | | /// Returns the output of calling [genericClassArguments] with [element]. |
| | | @protected |
| | | String genericClassArgumentsImpl(bool withConstraints) => |
| | | genericClassArguments(element, withConstraints); |
| | | |
| | | @protected |
| | | JsonKey jsonKeyFor(FieldElement field) => jsonKeyForField(field, config); |
| | | |
| | | @protected |
| | | TypeHelperContext getHelperContext(FieldElement field) => |
| | | typeHelperContext(this, field, jsonKeyFor(field)); |
| | | } |
| | | |
| | | InvalidGenerationSourceError createInvalidGenerationError( |
| | | String targetMember, FieldElement field, UnsupportedTypeError e) { |
| | | var message = 'Could not generate `$targetMember` code for `${field.name}`'; |
| | | |
| | | var todo = 'Make sure all of the types are serializable.'; |
| | | |
| | | if (e.type.isUndefined) { |
| | | message = '$message because the type is undefined.'; |
| | | todo = "Check your imports. If you're trying to generate code for a " |
| | | 'Platform-provided type, you may have to specify a custom ' |
| | | '`$targetMember` in the associated `@JsonKey` annotation.'; |
| | | } else { |
| | | if (field.type != e.type) { |
| | | message = '$message because of type `${e.type}`'; |
| | | } |
| | | |
| | | message = '$message.\n${e.reason}'; |
| | | } |
| | | |
| | | return InvalidGenerationSourceError(message, todo: todo, element: field); |
| | | } |
| | | |
| | | /// Returns a [String] representing the type arguments that exist on |
| | | /// [element]. |
| | | /// |
| | | /// If [withConstraints] is `null` or if [element] has no type arguments, an |
| | | /// empty [String] is returned. |
| | | /// |
| | | /// If [withConstraints] is true, any type constraints that exist on [element] |
| | | /// are included. |
| | | /// |
| | | /// For example, for class `class Sample<T as num, S>{...}` |
| | | /// |
| | | /// For [withConstraints] = `false`: |
| | | /// |
| | | /// ``` |
| | | /// "<T, S>" |
| | | /// ``` |
| | | /// |
| | | /// For [withConstraints] = `true`: |
| | | /// |
| | | /// ``` |
| | | /// "<T as num, S>" |
| | | /// ``` |
| | | String genericClassArguments(ClassElement element, bool withConstraints) { |
| | | if (withConstraints == null || element.typeParameters.isEmpty) { |
| | | return ''; |
| | | } |
| | | final values = element.typeParameters |
| | | .map((t) => withConstraints ? t.toString() : t.name) |
| | | .join(', '); |
| | | return '<$values>'; |
| | | } |
| | | |
| | | void warnUndefinedElements(Iterable<VariableElement> elements) { |
| | | for (final element in elements.where((fe) => fe.type.isUndefined)) { |
| | | final span = spanForElement(element); |
| | | log.warning(''' |
| | | This element has an undefined type. It may causes issues when generated code. |
| | | ${span.start.toolString} |
| | | ${span.highlight()}'''); |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:analyzer/dart/constant/value.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import 'json_literal_generator.dart'; |
| | | import 'utils.dart'; |
| | | |
| | | final _jsonKeyExpando = Expando<JsonKey>(); |
| | | |
| | | JsonKey jsonKeyForField(FieldElement field, JsonSerializable classAnnotation) => |
| | | _jsonKeyExpando[field] ??= _from(field, classAnnotation); |
| | | |
| | | JsonKey _from(FieldElement element, JsonSerializable classAnnotation) { |
| | | // If an annotation exists on `element` the source is a 'real' field. |
| | | // If the result is `null`, check the getter – it is a property. |
| | | // TODO(kevmoo) setters: github.com/dart-lang/json_serializable/issues/24 |
| | | final obj = jsonKeyAnnotation(element); |
| | | |
| | | if (obj == null) { |
| | | return _populateJsonKey(classAnnotation, element); |
| | | } |
| | | |
| | | Object _getLiteral(DartObject dartObject, Iterable<String> things) { |
| | | if (dartObject.isNull) { |
| | | return null; |
| | | } |
| | | |
| | | final reader = ConstantReader(dartObject); |
| | | |
| | | String badType; |
| | | if (reader.isSymbol) { |
| | | badType = 'Symbol'; |
| | | } else if (reader.isType) { |
| | | badType = 'Type'; |
| | | } else if (dartObject.type is FunctionType) { |
| | | // TODO(kevmoo): Support calling function for the default value? |
| | | badType = 'Function'; |
| | | } else if (!reader.isLiteral) { |
| | | badType = dartObject.type.name; |
| | | } |
| | | |
| | | if (badType != null) { |
| | | badType = things.followedBy([badType]).join(' > '); |
| | | throwUnsupported( |
| | | element, '`defaultValue` is `$badType`, it must be a literal.'); |
| | | } |
| | | |
| | | final literal = reader.literalValue; |
| | | |
| | | if (literal is num || literal is String || literal is bool) { |
| | | return literal; |
| | | } else if (literal is List<DartObject>) { |
| | | return literal |
| | | .map((e) => _getLiteral(e, things.followedBy(['List']))) |
| | | .toList(); |
| | | } else if (literal is Map<DartObject, DartObject>) { |
| | | final mapThings = things.followedBy(['Map']); |
| | | return literal.map((k, v) => |
| | | MapEntry(_getLiteral(k, mapThings), _getLiteral(v, mapThings))); |
| | | } |
| | | |
| | | badType = things.followedBy(['$dartObject']).join(' > '); |
| | | |
| | | throwUnsupported( |
| | | element, |
| | | 'The provided value is not supported: $badType. ' |
| | | 'This may be an error in package:json_serializable. ' |
| | | 'Please rerun your build with `--verbose` and file an issue.'); |
| | | } |
| | | |
| | | final defaultValueObject = obj.getField('defaultValue'); |
| | | |
| | | Object defaultValueLiteral; |
| | | |
| | | final enumFields = iterateEnumFields(defaultValueObject.type); |
| | | if (enumFields != null) { |
| | | final allowedValues = enumFields.map((p) => p.name).toList(); |
| | | final enumValueIndex = defaultValueObject.getField('index').toIntValue(); |
| | | defaultValueLiteral = |
| | | '${defaultValueObject.type.name}.${allowedValues[enumValueIndex]}'; |
| | | } else { |
| | | defaultValueLiteral = _getLiteral(defaultValueObject, []); |
| | | if (defaultValueLiteral != null) { |
| | | defaultValueLiteral = jsonLiteralAsDart(defaultValueLiteral); |
| | | } |
| | | } |
| | | |
| | | final disallowNullValue = obj.getField('disallowNullValue').toBoolValue(); |
| | | final includeIfNull = obj.getField('includeIfNull').toBoolValue(); |
| | | |
| | | if (disallowNullValue == true) { |
| | | if (includeIfNull == true) { |
| | | throwUnsupported( |
| | | element, |
| | | 'Cannot set both `disallowNullvalue` and `includeIfNull` to `true`. ' |
| | | 'This leads to incompatible `toJson` and `fromJson` behavior.'); |
| | | } |
| | | } |
| | | |
| | | return _populateJsonKey( |
| | | classAnnotation, |
| | | element, |
| | | name: obj.getField('name').toStringValue(), |
| | | nullable: obj.getField('nullable').toBoolValue(), |
| | | includeIfNull: includeIfNull, |
| | | ignore: obj.getField('ignore').toBoolValue(), |
| | | defaultValue: defaultValueLiteral, |
| | | required: obj.getField('required').toBoolValue(), |
| | | disallowNullValue: disallowNullValue, |
| | | ); |
| | | } |
| | | |
| | | JsonKey _populateJsonKey( |
| | | JsonSerializable classAnnotation, |
| | | FieldElement fieldElement, { |
| | | String name, |
| | | bool nullable, |
| | | bool includeIfNull, |
| | | bool ignore, |
| | | Object defaultValue, |
| | | bool required, |
| | | bool disallowNullValue, |
| | | }) { |
| | | final jsonKey = JsonKey( |
| | | name: _encodedFieldName(classAnnotation, name, fieldElement), |
| | | nullable: nullable ?? classAnnotation.nullable, |
| | | includeIfNull: _includeIfNull( |
| | | includeIfNull, disallowNullValue, classAnnotation.includeIfNull), |
| | | ignore: ignore ?? false, |
| | | defaultValue: defaultValue, |
| | | required: required ?? false, |
| | | disallowNullValue: disallowNullValue ?? false); |
| | | |
| | | return jsonKey; |
| | | } |
| | | |
| | | String _encodedFieldName(JsonSerializable classAnnotation, |
| | | String jsonKeyNameValue, FieldElement fieldElement) { |
| | | if (jsonKeyNameValue != null) { |
| | | return jsonKeyNameValue; |
| | | } |
| | | |
| | | switch (classAnnotation.fieldRename) { |
| | | case FieldRename.none: |
| | | // noop |
| | | break; |
| | | case FieldRename.snake: |
| | | return snakeCase(fieldElement.name); |
| | | case FieldRename.kebab: |
| | | return kebabCase(fieldElement.name); |
| | | } |
| | | |
| | | return fieldElement.name; |
| | | } |
| | | |
| | | bool _includeIfNull( |
| | | bool keyIncludeIfNull, bool keyDisallowNullValue, bool classIncludeIfNull) { |
| | | if (keyDisallowNullValue == true) { |
| | | assert(keyIncludeIfNull != true); |
| | | return false; |
| | | } |
| | | return keyIncludeIfNull ?? classIncludeIfNull; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'dart:async'; |
| | | import 'dart:convert'; |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:build/build.dart'; |
| | | import 'package:path/path.dart' as p; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'utils.dart'; |
| | | |
| | | class JsonLiteralGenerator extends GeneratorForAnnotation<JsonLiteral> { |
| | | const JsonLiteralGenerator(); |
| | | |
| | | @override |
| | | Future<String> generateForAnnotatedElement( |
| | | Element element, ConstantReader annotation, BuildStep buildStep) async { |
| | | if (p.isAbsolute(annotation.read('path').stringValue)) { |
| | | throw ArgumentError( |
| | | '`annotation.path` must be relative path to the source file.'); |
| | | } |
| | | |
| | | final sourcePathDir = p.dirname(buildStep.inputId.path); |
| | | final fileId = AssetId(buildStep.inputId.package, |
| | | p.join(sourcePathDir, annotation.read('path').stringValue)); |
| | | final content = json.decode(await buildStep.readAsString(fileId)); |
| | | |
| | | final asConst = annotation.read('asConst').boolValue; |
| | | |
| | | final thing = jsonLiteralAsDart(content).toString(); |
| | | final marked = asConst ? 'const' : 'final'; |
| | | |
| | | return '$marked _\$${element.name}JsonLiteral = $thing;'; |
| | | } |
| | | } |
| | | |
| | | /// Returns a [String] representing a valid Dart literal for [value]. |
| | | String jsonLiteralAsDart(dynamic value) { |
| | | if (value == null) return 'null'; |
| | | |
| | | if (value is String) return escapeDartString(value); |
| | | |
| | | if (value is bool || value is num) return value.toString(); |
| | | |
| | | if (value is List) { |
| | | final listItems = value.map(jsonLiteralAsDart).join(', '); |
| | | return '[$listItems]'; |
| | | } |
| | | |
| | | if (value is Map) return jsonMapAsDart(value); |
| | | |
| | | throw StateError( |
| | | 'Should never get here – with ${value.runtimeType} - `$value`.'); |
| | | } |
| | | |
| | | String jsonMapAsDart(Map value) { |
| | | final buffer = StringBuffer(); |
| | | buffer.write('{'); |
| | | |
| | | var first = true; |
| | | value.forEach((k, v) { |
| | | if (first) { |
| | | first = false; |
| | | } else { |
| | | buffer.writeln(','); |
| | | } |
| | | buffer.write(escapeDartString(k as String)); |
| | | buffer.write(': '); |
| | | buffer.write(jsonLiteralAsDart(v)); |
| | | }); |
| | | |
| | | buffer.write('}'); |
| | | |
| | | return buffer.toString(); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:build/build.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import 'json_literal_generator.dart'; |
| | | import 'json_serializable_generator.dart'; |
| | | |
| | | /// Returns a [Builder] for use within a `package:build_runner` |
| | | /// `BuildAction`. |
| | | /// |
| | | /// [formatOutput] is called to format the generated code. If not provided, |
| | | /// the default Dart code formatter is used. |
| | | Builder jsonPartBuilder( |
| | | {String formatOutput(String code), JsonSerializable config}) => |
| | | SharedPartBuilder([ |
| | | JsonSerializableGenerator(config: config), |
| | | const JsonLiteralGenerator() |
| | | ], 'json_serializable', formatOutput: formatOutput); |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:build/build.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import 'decode_helper.dart'; |
| | | import 'encoder_helper.dart'; |
| | | import 'field_helpers.dart'; |
| | | import 'helper_core.dart'; |
| | | import 'type_helper.dart'; |
| | | import 'type_helpers/convert_helper.dart'; |
| | | import 'type_helpers/date_time_helper.dart'; |
| | | import 'type_helpers/duration_helper.dart'; |
| | | import 'type_helpers/enum_helper.dart'; |
| | | import 'type_helpers/iterable_helper.dart'; |
| | | import 'type_helpers/json_converter_helper.dart'; |
| | | import 'type_helpers/json_helper.dart'; |
| | | import 'type_helpers/map_helper.dart'; |
| | | import 'type_helpers/uri_helper.dart'; |
| | | import 'type_helpers/value_helper.dart'; |
| | | import 'utils.dart'; |
| | | |
| | | class JsonSerializableGenerator |
| | | extends GeneratorForAnnotation<JsonSerializable> { |
| | | static const _coreHelpers = <TypeHelper>[ |
| | | IterableHelper(), |
| | | MapHelper(), |
| | | EnumHelper(), |
| | | ValueHelper(), |
| | | ]; |
| | | |
| | | static const _defaultHelpers = <TypeHelper>[ |
| | | JsonHelper(), |
| | | DateTimeHelper(), |
| | | UriHelper(), |
| | | DurationHelper(), |
| | | ]; |
| | | |
| | | final List<TypeHelper> _typeHelpers; |
| | | |
| | | Iterable<TypeHelper> get _allHelpers => const <TypeHelper>[ |
| | | ConvertHelper(), |
| | | JsonConverterHelper() |
| | | ].followedBy(_typeHelpers).followedBy(_coreHelpers); |
| | | |
| | | final JsonSerializable _config; |
| | | |
| | | JsonSerializable get config => _config.withDefaults(); |
| | | |
| | | /// Creates an instance of [JsonSerializableGenerator]. |
| | | /// |
| | | /// If [typeHelpers] is not provided, three built-in helpers are used: |
| | | /// [JsonHelper], [DateTimeHelper], [DurationHelper] and [UriHelper]. |
| | | const JsonSerializableGenerator({ |
| | | JsonSerializable config, |
| | | List<TypeHelper> typeHelpers, |
| | | }) : _config = config ?? JsonSerializable.defaults, |
| | | _typeHelpers = typeHelpers ?? _defaultHelpers; |
| | | |
| | | /// Creates an instance of [JsonSerializableGenerator]. |
| | | /// |
| | | /// [typeHelpers] provides a set of [TypeHelper] that will be used along with |
| | | /// the built-in helpers: |
| | | /// [JsonHelper], [DateTimeHelper], [DurationHelper] and [UriHelper]. |
| | | factory JsonSerializableGenerator.withDefaultHelpers( |
| | | Iterable<TypeHelper> typeHelpers, |
| | | {JsonSerializable config}) => |
| | | JsonSerializableGenerator( |
| | | config: config, |
| | | typeHelpers: |
| | | List.unmodifiable(typeHelpers.followedBy(_defaultHelpers))); |
| | | |
| | | @override |
| | | Iterable<String> generateForAnnotatedElement( |
| | | Element element, ConstantReader annotation, BuildStep buildStep) { |
| | | if (element is! ClassElement) { |
| | | final name = element.name; |
| | | throw InvalidGenerationSourceError('Generator cannot target `$name`.', |
| | | todo: 'Remove the JsonSerializable annotation from `$name`.', |
| | | element: element); |
| | | } |
| | | |
| | | final classElement = element as ClassElement; |
| | | final helper = _GeneratorHelper(this, classElement, annotation); |
| | | return helper._generate(); |
| | | } |
| | | } |
| | | |
| | | class _GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper { |
| | | final JsonSerializableGenerator _generator; |
| | | final _addedMembers = Set<String>(); |
| | | |
| | | _GeneratorHelper( |
| | | this._generator, ClassElement element, ConstantReader annotation) |
| | | : super(element, mergeConfig(_generator.config, annotation)); |
| | | |
| | | @override |
| | | void addMember(String memberContent) { |
| | | _addedMembers.add(memberContent); |
| | | } |
| | | |
| | | @override |
| | | Iterable<TypeHelper> get allTypeHelpers => _generator._allHelpers; |
| | | |
| | | Iterable<String> _generate() sync* { |
| | | assert(_addedMembers.isEmpty); |
| | | final sortedFields = createSortedFieldSet(element); |
| | | |
| | | // Used to keep track of why a field is ignored. Useful for providing |
| | | // helpful errors when generating constructor calls that try to use one of |
| | | // these fields. |
| | | final unavailableReasons = <String, String>{}; |
| | | |
| | | final accessibleFields = sortedFields.fold<Map<String, FieldElement>>( |
| | | <String, FieldElement>{}, (map, field) { |
| | | if (!field.isPublic) { |
| | | unavailableReasons[field.name] = 'It is assigned to a private field.'; |
| | | } else if (field.getter == null) { |
| | | assert(field.setter != null); |
| | | unavailableReasons[field.name] = |
| | | 'Setter-only properties are not supported.'; |
| | | log.warning('Setters are ignored: ${element.name}.${field.name}'); |
| | | } else if (jsonKeyFor(field).ignore) { |
| | | unavailableReasons[field.name] = 'It is assigned to an ignored field.'; |
| | | } else { |
| | | assert(!map.containsKey(field.name)); |
| | | map[field.name] = field; |
| | | } |
| | | |
| | | return map; |
| | | }); |
| | | |
| | | var accessibleFieldSet = accessibleFields.values.toSet(); |
| | | if (config.createFactory) { |
| | | final createResult = createFactory(accessibleFields, unavailableReasons); |
| | | yield createResult.output; |
| | | |
| | | accessibleFieldSet = accessibleFields.entries |
| | | .where((e) => createResult.usedFields.contains(e.key)) |
| | | .map((e) => e.value) |
| | | .toSet(); |
| | | } |
| | | |
| | | // Check for duplicate JSON keys due to colliding annotations. |
| | | // We do this now, since we have a final field list after any pruning done |
| | | // by `_writeCtor`. |
| | | accessibleFieldSet.fold(Set<String>(), (Set<String> set, fe) { |
| | | final jsonKey = nameAccess(fe); |
| | | if (!set.add(jsonKey)) { |
| | | throw InvalidGenerationSourceError( |
| | | 'More than one field has the JSON key `$jsonKey`.', |
| | | todo: 'Check the `JsonKey` annotations on fields.', |
| | | element: fe); |
| | | } |
| | | return set; |
| | | }); |
| | | |
| | | if (config.createToJson) { |
| | | yield* createToJson(accessibleFieldSet); |
| | | } |
| | | |
| | | yield* _addedMembers; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:source_gen/source_gen.dart' show TypeChecker; |
| | | |
| | | /// A [TypeChecker] for [Iterable]. |
| | | const coreIterableTypeChecker = TypeChecker.fromUrl('dart:core#Iterable'); |
| | | |
| | | const coreStringTypeChecker = TypeChecker.fromRuntime(String); |
| | | |
| | | const coreMapTypeChecker = TypeChecker.fromUrl('dart:core#Map'); |
| | | |
| | | /// Returns the generic type of the [Iterable] represented by [type]. |
| | | /// |
| | | /// If [type] does not extend [Iterable], an error is thrown. |
| | | DartType coreIterableGenericType(DartType type) => |
| | | typeArgumentsOf(type, coreIterableTypeChecker).single; |
| | | |
| | | /// If [type] is the [Type] or implements the [Type] represented by [checker], |
| | | /// returns the generic arguments to the [checker] [Type] if there are any. |
| | | /// |
| | | /// If the [checker] [Type] doesn't have generic arguments, `null` is returned. |
| | | List<DartType> typeArgumentsOf(DartType type, TypeChecker checker) { |
| | | final implementation = _getImplementationType(type, checker) as InterfaceType; |
| | | |
| | | return implementation?.typeArguments; |
| | | } |
| | | |
| | | /// A [TypeChecker] for [String], [bool] and [num]. |
| | | const simpleJsonTypeChecker = TypeChecker.any([ |
| | | coreStringTypeChecker, |
| | | TypeChecker.fromRuntime(bool), |
| | | TypeChecker.fromRuntime(num) |
| | | ]); |
| | | |
| | | String asStatement(DartType type) { |
| | | if (type.isDynamic || type.isObject) { |
| | | return ''; |
| | | } |
| | | |
| | | if (coreIterableTypeChecker.isAssignableFromType(type)) { |
| | | final itemType = coreIterableGenericType(type); |
| | | if (itemType.isDynamic || itemType.isObject) { |
| | | return ' as List'; |
| | | } |
| | | } |
| | | |
| | | if (coreMapTypeChecker.isAssignableFromType(type)) { |
| | | final args = typeArgumentsOf(type, coreMapTypeChecker); |
| | | assert(args.length == 2); |
| | | |
| | | if (args.every((dt) => dt.isDynamic || dt.isObject)) { |
| | | return ' as Map'; |
| | | } |
| | | } |
| | | |
| | | return ' as $type'; |
| | | } |
| | | |
| | | /// Returns all of the [DartType] types that [type] implements, mixes-in, and |
| | | /// extends, starting with [type] itself. |
| | | Iterable<DartType> typeImplementations(DartType type) sync* { |
| | | yield type; |
| | | |
| | | if (type is InterfaceType) { |
| | | yield* type.interfaces.expand(typeImplementations); |
| | | yield* type.mixins.expand(typeImplementations); |
| | | |
| | | if (type.superclass != null) { |
| | | yield* typeImplementations(type.superclass); |
| | | } |
| | | } |
| | | } |
| | | |
| | | DartType _getImplementationType(DartType type, TypeChecker checker) => |
| | | typeImplementations(type) |
| | | .firstWhere(checker.isExactlyType, orElse: () => null); |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | /// Context information provided in calls to [TypeHelper.serialize] and |
| | | /// [TypeHelper.deserialize]. |
| | | abstract class TypeHelperContext { |
| | | /// The annotated class that code is being generated for. |
| | | ClassElement get classElement; |
| | | |
| | | /// The field that code is being generated for. |
| | | FieldElement get fieldElement; |
| | | |
| | | /// Returns `true` if [fieldElement] could potentially contain a `null` value. |
| | | bool get nullable; |
| | | |
| | | /// [expression] may be just the name of the field or it may an expression |
| | | /// representing the serialization of a value. |
| | | Object serialize(DartType fieldType, String expression); |
| | | |
| | | /// [expression] may be just the name of the field or it may an expression |
| | | /// representing the serialization of a value. |
| | | Object deserialize(DartType fieldType, String expression); |
| | | |
| | | /// Adds [memberContent] to the set of generated, top-level members. |
| | | void addMember(String memberContent); |
| | | } |
| | | |
| | | /// Extended context information with includes configuration values |
| | | /// corresponding to `JsonSerializableGenerator` settings. |
| | | abstract class TypeHelperContextWithConfig extends TypeHelperContext { |
| | | JsonSerializable get config; |
| | | } |
| | | |
| | | abstract class TypeHelper<T extends TypeHelperContext> { |
| | | const TypeHelper(); |
| | | |
| | | /// Returns Dart code that serializes an [expression] representing a Dart |
| | | /// object of type [targetType]. |
| | | /// |
| | | /// If [targetType] is not supported, returns `null`. |
| | | /// |
| | | /// Let's say you want to serialize a class `Foo` as just its `id` property |
| | | /// of type `int`. |
| | | /// |
| | | /// Treating [expression] as a opaque Dart expression, the [serialize] |
| | | /// implementation could be a simple as: |
| | | /// |
| | | /// ```dart |
| | | /// String serialize(DartType targetType, String expression) => |
| | | /// "$expression.id"; |
| | | /// ```. |
| | | Object serialize(DartType targetType, String expression, T context); |
| | | |
| | | /// Returns Dart code that deserializes an [expression] representing a JSON |
| | | /// literal to into [targetType]. |
| | | /// |
| | | /// If [targetType] is not supported, returns `null`. |
| | | /// |
| | | /// Let's say you want to deserialize a class `Foo` by taking an `int` stored |
| | | /// in a JSON literal and calling the `Foo.fromInt` constructor. |
| | | /// |
| | | /// Treating [expression] as a opaque Dart expression representing a JSON |
| | | /// literal, the [deserialize] implementation could be a simple as: |
| | | /// |
| | | /// ```dart |
| | | /// String deserialize(DartType targetType, String expression) => |
| | | /// "new Foo.fromInt($expression)"; |
| | | /// ```. |
| | | /// |
| | | /// Note that [targetType] is not used here. If you wanted to support many |
| | | /// types of [targetType] you could write: |
| | | /// |
| | | /// ```dart |
| | | /// String deserialize(DartType targetType, String expression) => |
| | | /// "new ${targetType.name}.fromInt($expression)"; |
| | | /// ```. |
| | | Object deserialize(DartType targetType, String expression, T context); |
| | | } |
| | | |
| | | class LambdaResult { |
| | | final String expression; |
| | | final String lambda; |
| | | |
| | | LambdaResult(this.expression, this.lambda); |
| | | |
| | | @override |
| | | String toString() => '$lambda($expression)'; |
| | | |
| | | static String process(Object subField, String closureArg) => |
| | | (subField is LambdaResult && closureArg == subField.expression) |
| | | ? subField.lambda |
| | | : '($closureArg) => $subField'; |
| | | } |
| | | |
| | | class UnsupportedTypeError extends Error { |
| | | final String expression; |
| | | final DartType type; |
| | | final String reason; |
| | | |
| | | UnsupportedTypeError(this.type, this.expression, this.reason); |
| | | } |
| | | |
| | | Object commonNullPrefix( |
| | | bool nullable, String expression, Object unsafeExpression) => |
| | | nullable |
| | | ? '$expression == null ? null : $unsafeExpression' |
| | | : unsafeExpression; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/constant/value.dart'; |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'helper_core.dart'; |
| | | import 'type_helper.dart'; |
| | | import 'type_helpers/convert_helper.dart'; |
| | | import 'utils.dart'; |
| | | |
| | | TypeHelperContext typeHelperContext( |
| | | HelperCore helperCore, FieldElement fieldElement, JsonKey key) => |
| | | _TypeHelperCtx(helperCore, fieldElement, key); |
| | | |
| | | class _TypeHelperCtx |
| | | implements TypeHelperContextWithConfig, TypeHelperContextWithConvert { |
| | | final HelperCore _helperCore; |
| | | final JsonKey _key; |
| | | |
| | | @override |
| | | final FieldElement fieldElement; |
| | | |
| | | @override |
| | | bool get nullable => _key.nullable; |
| | | |
| | | @override |
| | | ClassElement get classElement => _helperCore.element; |
| | | |
| | | @override |
| | | JsonSerializable get config => _helperCore.config; |
| | | |
| | | _TypeHelperCtx(this._helperCore, this.fieldElement, this._key); |
| | | |
| | | @override |
| | | ConvertData get serializeConvertData => _pairFromContext?.toJson; |
| | | |
| | | @override |
| | | ConvertData get deserializeConvertData => _pairFromContext?.fromJson; |
| | | |
| | | _ConvertPair get _pairFromContext => _ConvertPair(fieldElement); |
| | | |
| | | @override |
| | | void addMember(String memberContent) { |
| | | _helperCore.addMember(memberContent); |
| | | } |
| | | |
| | | @override |
| | | Object serialize(DartType targetType, String expression) => _run( |
| | | targetType, |
| | | expression, |
| | | (TypeHelper th) => th.serialize(targetType, expression, this)); |
| | | |
| | | @override |
| | | Object deserialize(DartType targetType, String expression) => _run( |
| | | targetType, |
| | | expression, |
| | | (TypeHelper th) => th.deserialize(targetType, expression, this)); |
| | | |
| | | Object _run(DartType targetType, String expression, |
| | | Object invoke(TypeHelper instance)) => |
| | | _helperCore.allTypeHelpers.map(invoke).firstWhere((r) => r != null, |
| | | orElse: () => throw UnsupportedTypeError( |
| | | targetType, expression, _notSupportedWithTypeHelpersMsg)); |
| | | } |
| | | |
| | | final _notSupportedWithTypeHelpersMsg = |
| | | 'None of the provided `TypeHelper` instances support the defined type.'; |
| | | |
| | | class _ConvertPair { |
| | | static final _expando = Expando<_ConvertPair>(); |
| | | static _ConvertPair fromJsonKey(JsonKey key) => _expando[key]; |
| | | |
| | | final ConvertData fromJson, toJson; |
| | | |
| | | _ConvertPair._(this.fromJson, this.toJson); |
| | | |
| | | factory _ConvertPair(FieldElement element) { |
| | | var pair = _expando[element]; |
| | | |
| | | if (pair == null) { |
| | | final obj = jsonKeyAnnotation(element); |
| | | if (obj == null) { |
| | | pair = _ConvertPair._(null, null); |
| | | } else { |
| | | final toJson = _convertData(obj, element, false); |
| | | final fromJson = _convertData(obj, element, true); |
| | | pair = _ConvertPair._(fromJson, toJson); |
| | | } |
| | | _expando[element] = pair; |
| | | } |
| | | return pair; |
| | | } |
| | | } |
| | | |
| | | ConvertData _convertData(DartObject obj, FieldElement element, bool isFrom) { |
| | | final paramName = isFrom ? 'fromJson' : 'toJson'; |
| | | final objectValue = obj.getField(paramName); |
| | | |
| | | if (objectValue.isNull) { |
| | | return null; |
| | | } |
| | | |
| | | final type = objectValue.type as FunctionType; |
| | | |
| | | final executableElement = type.element as ExecutableElement; |
| | | |
| | | if (executableElement.parameters.isEmpty || |
| | | executableElement.parameters.first.isNamed || |
| | | executableElement.parameters.where((pe) => !pe.isOptional).length > 1) { |
| | | throwUnsupported( |
| | | element, |
| | | 'The `$paramName` function `${executableElement.name}` must have one ' |
| | | 'positional paramater.'); |
| | | } |
| | | |
| | | final argType = executableElement.parameters.first.type; |
| | | if (isFrom) { |
| | | final returnType = executableElement.returnType; |
| | | |
| | | if (returnType is TypeParameterType) { |
| | | // We keep things simple in this case. We rely on inferred type arguments |
| | | // to the `fromJson` function. |
| | | // TODO: consider adding error checking here if there is confusion. |
| | | } else if (!returnType.isAssignableTo(element.type)) { |
| | | throwUnsupported( |
| | | element, |
| | | 'The `$paramName` function `${executableElement.name}` return type ' |
| | | '`$returnType` is not compatible with field type `${element.type}`.'); |
| | | } |
| | | } else { |
| | | if (argType is TypeParameterType) { |
| | | // We keep things simple in this case. We rely on inferred type arguments |
| | | // to the `fromJson` function. |
| | | // TODO: consider adding error checking here if there is confusion. |
| | | } else if (!element.type.isAssignableTo(argType)) { |
| | | throwUnsupported( |
| | | element, |
| | | 'The `$paramName` function `${executableElement.name}` argument type ' |
| | | '`$argType` is not compatible with field type' |
| | | ' `${element.type}`.'); |
| | | } |
| | | } |
| | | |
| | | var name = executableElement.name; |
| | | |
| | | if (executableElement is MethodElement) { |
| | | name = '${executableElement.enclosingElement.name}.$name'; |
| | | } |
| | | |
| | | return ConvertData(name, argType); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | |
| | | import '../shared_checkers.dart'; |
| | | import '../type_helper.dart'; |
| | | |
| | | /// Information used by [ConvertHelper] when handling `JsonKey`-annotated |
| | | /// fields with `toJson` or `fromJson` values set. |
| | | class ConvertData { |
| | | final String name; |
| | | final DartType paramType; |
| | | |
| | | ConvertData(this.name, this.paramType); |
| | | } |
| | | |
| | | abstract class TypeHelperContextWithConvert extends TypeHelperContext { |
| | | ConvertData get serializeConvertData; |
| | | ConvertData get deserializeConvertData; |
| | | } |
| | | |
| | | class ConvertHelper extends TypeHelper<TypeHelperContextWithConvert> { |
| | | const ConvertHelper(); |
| | | |
| | | @override |
| | | String serialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConvert context) { |
| | | final toJsonData = context.serializeConvertData; |
| | | if (toJsonData != null) { |
| | | assert(toJsonData.paramType is TypeParameterType || |
| | | targetType.isAssignableTo(toJsonData.paramType)); |
| | | final result = '${toJsonData.name}($expression)'; |
| | | return commonNullPrefix(context.nullable, expression, result).toString(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @override |
| | | String deserialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConvert context) { |
| | | final fromJsonData = context.deserializeConvertData; |
| | | if (fromJsonData != null) { |
| | | final asContent = asStatement(fromJsonData.paramType); |
| | | final result = '${fromJsonData.name}($expression$asContent)'; |
| | | return commonNullPrefix(context.nullable, expression, result).toString(); |
| | | } |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:source_gen/source_gen.dart' show TypeChecker; |
| | | |
| | | import '../type_helper.dart'; |
| | | |
| | | class DateTimeHelper extends TypeHelper { |
| | | const DateTimeHelper(); |
| | | |
| | | @override |
| | | String serialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (!_matchesType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | final buffer = StringBuffer(expression); |
| | | |
| | | if (context.nullable) { |
| | | buffer.write('?'); |
| | | } |
| | | |
| | | buffer.write('.toIso8601String()'); |
| | | |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | @override |
| | | String deserialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (!_matchesType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | return commonNullPrefix(context.nullable, expression, |
| | | 'DateTime.parse($expression as String)') |
| | | .toString(); |
| | | } |
| | | } |
| | | |
| | | bool _matchesType(DartType type) => |
| | | const TypeChecker.fromUrl('dart:core#DateTime').isExactlyType(type); |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:source_gen/source_gen.dart' show TypeChecker; |
| | | import '../type_helper.dart'; |
| | | |
| | | class DurationHelper extends TypeHelper { |
| | | const DurationHelper(); |
| | | |
| | | @override |
| | | String serialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (!_matchesType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | final buffer = StringBuffer(expression); |
| | | |
| | | if (context.nullable) { |
| | | buffer.write('?'); |
| | | } |
| | | |
| | | buffer.write('.inMicroseconds'); |
| | | |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | @override |
| | | String deserialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (!_matchesType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | return commonNullPrefix( |
| | | context.nullable, |
| | | expression, |
| | | 'Duration(microseconds: $expression as int)', |
| | | ).toString(); |
| | | } |
| | | } |
| | | |
| | | bool _matchesType(DartType type) => |
| | | const TypeChecker.fromUrl('dart:core#Duration').isExactlyType(type); |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | |
| | | import '../json_literal_generator.dart'; |
| | | import '../type_helper.dart'; |
| | | import '../utils.dart'; |
| | | |
| | | final simpleExpression = RegExp('^[a-zA-Z_]+\$'); |
| | | |
| | | class EnumHelper extends TypeHelper { |
| | | const EnumHelper(); |
| | | |
| | | @override |
| | | String serialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | final memberContent = _enumValueMapFromType(targetType); |
| | | |
| | | if (memberContent == null) { |
| | | return null; |
| | | } |
| | | |
| | | context.addMember(memberContent); |
| | | |
| | | return '${_constMapName(targetType)}[$expression]'; |
| | | } |
| | | |
| | | @override |
| | | String deserialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | final memberContent = _enumValueMapFromType(targetType); |
| | | |
| | | if (memberContent == null) { |
| | | return null; |
| | | } |
| | | |
| | | context.addMember(_enumDecodeHelper); |
| | | |
| | | if (context.nullable) { |
| | | context.addMember(_enumDecodeHelperNullable); |
| | | } |
| | | |
| | | context.addMember(memberContent); |
| | | |
| | | final functionName = |
| | | context.nullable ? r'_$enumDecodeNullable' : r'_$enumDecode'; |
| | | return '$functionName(${_constMapName(targetType)}, ' |
| | | '$expression)'; |
| | | } |
| | | } |
| | | |
| | | String _constMapName(DartType targetType) => '_\$${targetType.name}EnumMap'; |
| | | |
| | | String _enumValueMapFromType(DartType targetType) { |
| | | final enumMap = enumFieldsMap(targetType); |
| | | |
| | | if (enumMap == null) { |
| | | return null; |
| | | } |
| | | |
| | | final items = |
| | | enumMap.entries.map((e) => ' ${targetType.name}.${e.key.name}: ' |
| | | '${jsonLiteralAsDart(e.value)}'); |
| | | |
| | | return 'const ${_constMapName(targetType)} = ' |
| | | '<${targetType.name}, dynamic>{\n${items.join(',\n')}\n};'; |
| | | } |
| | | |
| | | const _enumDecodeHelper = r''' |
| | | T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | throw ArgumentError('A value must be provided. Supported values: ' |
| | | '${enumValues.values.join(', ')}'); |
| | | } |
| | | return enumValues.entries |
| | | .singleWhere((e) => e.value == source, |
| | | orElse: () => throw ArgumentError( |
| | | '`$source` is not one of the supported values: ' |
| | | '${enumValues.values.join(', ')}')) |
| | | .key; |
| | | }'''; |
| | | |
| | | const _enumDecodeHelperNullable = r''' |
| | | T _$enumDecodeNullable<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | return null; |
| | | } |
| | | return _$enumDecode<T>(enumValues, source); |
| | | }'''; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:source_gen/source_gen.dart' show TypeChecker; |
| | | |
| | | import '../constants.dart'; |
| | | import '../shared_checkers.dart'; |
| | | import '../type_helper.dart'; |
| | | |
| | | class IterableHelper extends TypeHelper<TypeHelperContextWithConfig> { |
| | | const IterableHelper(); |
| | | |
| | | @override |
| | | String serialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConfig context) { |
| | | if (!coreIterableTypeChecker.isAssignableFromType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | final itemType = coreIterableGenericType(targetType); |
| | | |
| | | // This block will yield a regular list, which works fine for JSON |
| | | // Although it's possible that child elements may be marked unsafe |
| | | |
| | | var isList = _coreListChecker.isAssignableFromType(targetType); |
| | | final subField = context.serialize(itemType, closureArg); |
| | | |
| | | final optionalQuestion = context.nullable ? '?' : ''; |
| | | |
| | | // In the case of trivial JSON types (int, String, etc), `subField` |
| | | // will be identical to `substitute` – so no explicit mapping is needed. |
| | | // If they are not equal, then we to write out the substitution. |
| | | if (subField != closureArg) { |
| | | final lambda = LambdaResult.process(subField, closureArg); |
| | | if (context.config.useWrappers && isList) { |
| | | var method = '\$wrapList'; |
| | | if (context.nullable) { |
| | | method = '${method}HandleNull'; |
| | | } |
| | | |
| | | return '$method<$itemType>($expression, $lambda)'; |
| | | } |
| | | |
| | | expression = '$expression$optionalQuestion.map($lambda)'; |
| | | |
| | | // expression now represents an Iterable (even if it started as a List |
| | | // ...resetting `isList` to `false`. |
| | | isList = false; |
| | | } |
| | | |
| | | if (!isList) { |
| | | // If the static type is not a List, generate one. |
| | | expression += '$optionalQuestion.toList()'; |
| | | } |
| | | |
| | | return expression; |
| | | } |
| | | |
| | | @override |
| | | String deserialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (!coreIterableTypeChecker.isAssignableFromType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | final iterableGenericType = coreIterableGenericType(targetType); |
| | | |
| | | final itemSubVal = context.deserialize(iterableGenericType, closureArg); |
| | | |
| | | // If `itemSubVal` is the same and it's not a Set, then we don't need to do |
| | | // anything fancy |
| | | if (closureArg == itemSubVal && |
| | | !_coreSetChecker.isAssignableFromType(targetType)) { |
| | | return '$expression as List'; |
| | | } |
| | | |
| | | final optionalQuestion = context.nullable ? '?' : ''; |
| | | |
| | | final lambda = LambdaResult.process(itemSubVal, closureArg); |
| | | |
| | | var output = '($expression as List)$optionalQuestion.map($lambda)'; |
| | | |
| | | if (_coreListChecker.isAssignableFromType(targetType)) { |
| | | output += '$optionalQuestion.toList()'; |
| | | } else if (_coreSetChecker.isAssignableFromType(targetType)) { |
| | | output += '$optionalQuestion.toSet()'; |
| | | } |
| | | |
| | | return output; |
| | | } |
| | | } |
| | | |
| | | final _coreListChecker = const TypeChecker.fromUrl('dart:core#List'); |
| | | final _coreSetChecker = const TypeChecker.fromUrl('dart:core#Set'); |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/constant/value.dart'; |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import '../shared_checkers.dart'; |
| | | import '../type_helper.dart'; |
| | | |
| | | /// A [TypeHelper] that supports classes annotated with implementations of |
| | | /// [JsonConverter]. |
| | | class JsonConverterHelper extends TypeHelper { |
| | | const JsonConverterHelper(); |
| | | |
| | | @override |
| | | Object serialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | final converter = _typeConverter(targetType, context); |
| | | |
| | | if (converter == null) { |
| | | return null; |
| | | } |
| | | |
| | | return commonNullPrefix(context.nullable, expression, |
| | | LambdaResult(expression, '${converter.accessString}.toJson')); |
| | | } |
| | | |
| | | @override |
| | | Object deserialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | final converter = _typeConverter(targetType, context); |
| | | if (converter == null) { |
| | | return null; |
| | | } |
| | | |
| | | final asContent = asStatement(converter.jsonType); |
| | | |
| | | return commonNullPrefix( |
| | | context.nullable, |
| | | expression, |
| | | LambdaResult( |
| | | '$expression$asContent', '${converter.accessString}.fromJson')); |
| | | } |
| | | } |
| | | |
| | | class _JsonConvertData { |
| | | final String accessString; |
| | | final DartType jsonType; |
| | | |
| | | _JsonConvertData.className(String className, String accessor, this.jsonType) |
| | | : accessString = 'const $className${_withAccessor(accessor)}()'; |
| | | |
| | | _JsonConvertData.genericClass( |
| | | String className, String genericTypeArg, String accessor, this.jsonType) |
| | | : accessString = |
| | | '$className<$genericTypeArg>${_withAccessor(accessor)}()'; |
| | | |
| | | _JsonConvertData.propertyAccess(this.accessString, this.jsonType); |
| | | |
| | | static String _withAccessor(String accessor) => |
| | | accessor.isEmpty ? '' : '.$accessor'; |
| | | } |
| | | |
| | | _JsonConvertData _typeConverter(DartType targetType, TypeHelperContext ctx) { |
| | | List<_ConverterMatch> converterMatches(List<ElementAnnotation> items) => items |
| | | .map((annotation) => _compatibleMatch(targetType, annotation)) |
| | | .where((dt) => dt != null) |
| | | .toList(); |
| | | |
| | | var matchingAnnotations = converterMatches(ctx.fieldElement.metadata); |
| | | |
| | | if (matchingAnnotations.isEmpty) { |
| | | matchingAnnotations = converterMatches(ctx.classElement.metadata); |
| | | } |
| | | |
| | | return _typeConverterFrom(matchingAnnotations, targetType); |
| | | } |
| | | |
| | | _JsonConvertData _typeConverterFrom( |
| | | List<_ConverterMatch> matchingAnnotations, DartType targetType) { |
| | | if (matchingAnnotations.isEmpty) { |
| | | return null; |
| | | } |
| | | |
| | | if (matchingAnnotations.length > 1) { |
| | | throw InvalidGenerationSourceError( |
| | | 'Found more than one matching converter for `$targetType`.', |
| | | element: matchingAnnotations[1].elementAnnotation.element); |
| | | } |
| | | |
| | | final match = matchingAnnotations.single; |
| | | |
| | | final annotationElement = match.elementAnnotation.element; |
| | | if (annotationElement is PropertyAccessorElement) { |
| | | final enclosing = annotationElement.enclosingElement; |
| | | |
| | | var accessString = annotationElement.name; |
| | | |
| | | if (enclosing is ClassElement) { |
| | | accessString = '${enclosing.name}.$accessString'; |
| | | } |
| | | |
| | | return _JsonConvertData.propertyAccess(accessString, match.jsonType); |
| | | } |
| | | |
| | | final reviver = ConstantReader(match.annotation).revive(); |
| | | |
| | | if (reviver.namedArguments.isNotEmpty || |
| | | reviver.positionalArguments.isNotEmpty) { |
| | | throw InvalidGenerationSourceError( |
| | | 'Generators with constructor arguments are not supported.', |
| | | element: match.elementAnnotation.element); |
| | | } |
| | | |
| | | if (match.genericTypeArg != null) { |
| | | return _JsonConvertData.genericClass(match.annotation.type.name, |
| | | match.genericTypeArg, reviver.accessor, match.jsonType); |
| | | } |
| | | |
| | | return _JsonConvertData.className( |
| | | match.annotation.type.name, reviver.accessor, match.jsonType); |
| | | } |
| | | |
| | | class _ConverterMatch { |
| | | final DartObject annotation; |
| | | final DartType jsonType; |
| | | final ElementAnnotation elementAnnotation; |
| | | final String genericTypeArg; |
| | | |
| | | _ConverterMatch(this.elementAnnotation, this.annotation, this.jsonType, |
| | | this.genericTypeArg); |
| | | } |
| | | |
| | | _ConverterMatch _compatibleMatch( |
| | | DartType targetType, ElementAnnotation annotation) { |
| | | final constantValue = annotation.computeConstantValue(); |
| | | |
| | | final converterClassElement = constantValue.type.element as ClassElement; |
| | | |
| | | final jsonConverterSuper = converterClassElement.allSupertypes.singleWhere( |
| | | (e) => e is InterfaceType && _jsonConverterChecker.isExactly(e.element), |
| | | orElse: () => null); |
| | | |
| | | if (jsonConverterSuper == null) { |
| | | return null; |
| | | } |
| | | |
| | | assert(jsonConverterSuper.typeParameters.length == 2); |
| | | assert(jsonConverterSuper.typeArguments.length == 2); |
| | | |
| | | final fieldType = jsonConverterSuper.typeArguments[0]; |
| | | |
| | | if (fieldType.isEquivalentTo(targetType)) { |
| | | return _ConverterMatch( |
| | | annotation, constantValue, jsonConverterSuper.typeArguments[1], null); |
| | | } |
| | | |
| | | if (fieldType is TypeParameterType && targetType is TypeParameterType) { |
| | | assert(annotation.element is! PropertyAccessorElement); |
| | | assert(converterClassElement.typeParameters.isNotEmpty); |
| | | if (converterClassElement.typeParameters.length > 1) { |
| | | throw InvalidGenerationSourceError( |
| | | '`JsonConverter` implementations can have no more than one type ' |
| | | 'argument. `${converterClassElement.name}` has ' |
| | | '${converterClassElement.typeParameters.length}.', |
| | | element: converterClassElement); |
| | | } |
| | | |
| | | return _ConverterMatch(annotation, constantValue, |
| | | jsonConverterSuper.typeArguments[1], targetType.name); |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | const _jsonConverterChecker = TypeChecker.fromRuntime(JsonConverter); |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | import '../shared_checkers.dart'; |
| | | import '../type_helper.dart'; |
| | | import '../utils.dart'; |
| | | |
| | | class JsonHelper extends TypeHelper<TypeHelperContextWithConfig> { |
| | | const JsonHelper(); |
| | | |
| | | /// Simply returns the [expression] provided. |
| | | /// |
| | | /// By default, JSON encoding in from `dart:convert` calls `toJson()` on |
| | | /// provided objects. |
| | | @override |
| | | String serialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConfig context) { |
| | | if (!_canSerialize(context.config, targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | if (context.config.explicitToJson) { |
| | | return '$expression${context.nullable ? '?' : ''}.toJson()'; |
| | | } |
| | | return expression; |
| | | } |
| | | |
| | | @override |
| | | String deserialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConfig context) { |
| | | if (targetType is! InterfaceType) { |
| | | return null; |
| | | } |
| | | |
| | | final type = targetType as InterfaceType; |
| | | final classElement = type.element; |
| | | |
| | | final fromJsonCtor = classElement.constructors |
| | | .singleWhere((ce) => ce.name == 'fromJson', orElse: () => null); |
| | | |
| | | String asCast; |
| | | if (fromJsonCtor != null) { |
| | | // TODO: should verify that this type is a valid JSON type |
| | | final asCastType = fromJsonCtor.parameters.first.type; |
| | | asCast = asStatement(asCastType); |
| | | } else if (_annotation(context.config, type)?.createFactory == true) { |
| | | if (context.config.anyMap) { |
| | | asCast = ' as Map'; |
| | | } else { |
| | | asCast = ' as Map<String, dynamic>'; |
| | | } |
| | | } else { |
| | | return null; |
| | | } |
| | | |
| | | // TODO: the type could be imported from a library with a prefix! |
| | | // github.com/dart-lang/json_serializable/issues/19 |
| | | final result = '${targetType.name}.fromJson($expression$asCast)'; |
| | | |
| | | return commonNullPrefix(context.nullable, expression, result).toString(); |
| | | } |
| | | } |
| | | |
| | | bool _canSerialize(JsonSerializable config, DartType type) { |
| | | if (type is InterfaceType) { |
| | | final toJsonMethod = _toJsonMethod(type); |
| | | |
| | | if (toJsonMethod != null) { |
| | | // TODO: validate there are no required parameters |
| | | return true; |
| | | } |
| | | |
| | | if (_annotation(config, type)?.createToJson == true) { |
| | | // TODO: consider logging that we're assuming a user will wire up the |
| | | // generated mixin at some point... |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | JsonSerializable _annotation(JsonSerializable config, InterfaceType source) { |
| | | final annotations = const TypeChecker.fromRuntime(JsonSerializable) |
| | | .annotationsOfExact(source.element, throwOnUnresolved: false) |
| | | .toList(); |
| | | |
| | | if (annotations.isEmpty) { |
| | | return null; |
| | | } |
| | | |
| | | return mergeConfig(config, ConstantReader(annotations.single)); |
| | | } |
| | | |
| | | MethodElement _toJsonMethod(DartType type) => typeImplementations(type) |
| | | .map((dt) => dt is InterfaceType ? dt.getMethod('toJson') : null) |
| | | .firstWhere((me) => me != null, orElse: () => null); |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | |
| | | import '../constants.dart'; |
| | | import '../shared_checkers.dart'; |
| | | import '../type_helper.dart'; |
| | | import '../utils.dart'; |
| | | |
| | | const _keyParam = 'k'; |
| | | |
| | | class MapHelper extends TypeHelper<TypeHelperContextWithConfig> { |
| | | const MapHelper(); |
| | | |
| | | @override |
| | | String serialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConfig context) { |
| | | if (!coreMapTypeChecker.isAssignableFromType(targetType)) { |
| | | return null; |
| | | } |
| | | final args = typeArgumentsOf(targetType, coreMapTypeChecker); |
| | | assert(args.length == 2); |
| | | |
| | | final keyType = args[0]; |
| | | final valueType = args[1]; |
| | | |
| | | _checkSafeKeyType(expression, keyType); |
| | | |
| | | final subFieldValue = context.serialize(valueType, closureArg); |
| | | final subKeyValue = context.serialize(keyType, _keyParam); |
| | | |
| | | if (closureArg == subFieldValue && _keyParam == subKeyValue) { |
| | | return expression; |
| | | } |
| | | |
| | | if (context.config.useWrappers) { |
| | | var method = '\$wrapMap'; |
| | | if (context.nullable) { |
| | | method = '${method}HandleNull'; |
| | | } |
| | | |
| | | final lambda = LambdaResult.process(subFieldValue, closureArg); |
| | | return '$method<$keyType, $valueType>($expression, $lambda)'; |
| | | } |
| | | |
| | | final optionalQuestion = context.nullable ? '?' : ''; |
| | | |
| | | return '$expression$optionalQuestion' |
| | | '.map(($_keyParam, $closureArg) => MapEntry($subKeyValue, $subFieldValue))'; |
| | | } |
| | | |
| | | @override |
| | | String deserialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConfig context) { |
| | | if (!coreMapTypeChecker.isAssignableFromType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | final typeArgs = typeArgumentsOf(targetType, coreMapTypeChecker); |
| | | assert(typeArgs.length == 2); |
| | | final keyArg = typeArgs.first; |
| | | final valueArg = typeArgs.last; |
| | | |
| | | _checkSafeKeyType(expression, keyArg); |
| | | |
| | | final valueArgIsAny = _isObjectOrDynamic(valueArg); |
| | | final isEnumKey = isEnum(keyArg); |
| | | |
| | | if (!isEnumKey) { |
| | | if (valueArgIsAny) { |
| | | if (context.config.anyMap) { |
| | | if (_isObjectOrDynamic(keyArg)) { |
| | | return '$expression as Map'; |
| | | } |
| | | } else { |
| | | // this is the trivial case. Do a runtime cast to the known type of JSON |
| | | // map values - `Map<String, dynamic>` |
| | | return '$expression as Map<String, dynamic>'; |
| | | } |
| | | } |
| | | |
| | | if (!context.nullable && |
| | | (valueArgIsAny || |
| | | simpleJsonTypeChecker.isAssignableFromType(valueArg))) { |
| | | // No mapping of the values or null check required! |
| | | return 'Map<String, $valueArg>.from($expression as Map)'; |
| | | } |
| | | } |
| | | |
| | | // In this case, we're going to create a new Map with matching reified |
| | | // types. |
| | | |
| | | final itemSubVal = context.deserialize(valueArg, closureArg); |
| | | |
| | | final optionalQuestion = context.nullable ? '?' : ''; |
| | | |
| | | final mapCast = |
| | | context.config.anyMap ? 'as Map' : 'as Map<String, dynamic>'; |
| | | |
| | | String keyUsage; |
| | | if (isEnumKey) { |
| | | keyUsage = context.deserialize(keyArg, _keyParam).toString(); |
| | | } else if (context.config.anyMap && !_isObjectOrDynamic(keyArg)) { |
| | | keyUsage = '$_keyParam as String'; |
| | | } else { |
| | | keyUsage = _keyParam; |
| | | } |
| | | |
| | | return '($expression $mapCast)$optionalQuestion.map(' |
| | | '($_keyParam, $closureArg) => MapEntry($keyUsage, $itemSubVal))'; |
| | | } |
| | | } |
| | | |
| | | bool _isObjectOrDynamic(DartType type) => type.isObject || type.isDynamic; |
| | | |
| | | void _checkSafeKeyType(String expression, DartType keyArg) { |
| | | // We're not going to handle converting key types at the moment |
| | | // So the only safe types for key are dynamic/Object/String/enum |
| | | final safeKey = _isObjectOrDynamic(keyArg) || |
| | | coreStringTypeChecker.isExactlyType(keyArg) || |
| | | isEnum(keyArg); |
| | | |
| | | if (!safeKey) { |
| | | throw UnsupportedTypeError(keyArg, expression, |
| | | 'Map keys must be of type `String`, enum, `Object` or `dynamic`.'); |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:source_gen/source_gen.dart' show TypeChecker; |
| | | |
| | | import '../type_helper.dart'; |
| | | |
| | | class UriHelper extends TypeHelper { |
| | | const UriHelper(); |
| | | |
| | | @override |
| | | String serialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (!_matchesType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | final buffer = StringBuffer(expression); |
| | | |
| | | if (context.nullable) { |
| | | buffer.write('?'); |
| | | } |
| | | |
| | | buffer.write('.toString()'); |
| | | |
| | | return buffer.toString(); |
| | | } |
| | | |
| | | @override |
| | | String deserialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (!_matchesType(targetType)) { |
| | | return null; |
| | | } |
| | | |
| | | return commonNullPrefix( |
| | | context.nullable, expression, 'Uri.parse($expression as String)') |
| | | .toString(); |
| | | } |
| | | } |
| | | |
| | | bool _matchesType(DartType type) => |
| | | const TypeChecker.fromUrl('dart:core#Uri').isExactlyType(type); |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:source_gen/source_gen.dart' show TypeChecker; |
| | | |
| | | import '../shared_checkers.dart'; |
| | | import '../type_helper.dart'; |
| | | |
| | | class ValueHelper extends TypeHelper { |
| | | const ValueHelper(); |
| | | |
| | | @override |
| | | String serialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (targetType.isUndefined) { |
| | | return null; |
| | | } |
| | | if (targetType.isDynamic || |
| | | targetType.isObject || |
| | | simpleJsonTypeChecker.isAssignableFromType(targetType)) { |
| | | return expression; |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | |
| | | @override |
| | | String deserialize( |
| | | DartType targetType, String expression, TypeHelperContext context) { |
| | | if (targetType.isUndefined) { |
| | | return null; |
| | | } |
| | | if (targetType.isDynamic || targetType.isObject) { |
| | | // just return it as-is. We'll hope it's safe. |
| | | return expression; |
| | | } else if (const TypeChecker.fromRuntime(double) |
| | | .isExactlyType(targetType)) { |
| | | return '($expression as num)${context.nullable ? '?' : ''}.toDouble()'; |
| | | } else if (simpleJsonTypeChecker.isAssignableFromType(targetType)) { |
| | | return '$expression as $targetType'; |
| | | } |
| | | |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:analyzer/dart/constant/value.dart'; |
| | | import 'package:analyzer/dart/element/element.dart'; |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:meta/meta.dart' show alwaysThrows; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | final _jsonKeyChecker = const TypeChecker.fromRuntime(JsonKey); |
| | | |
| | | DartObject jsonKeyAnnotation(FieldElement element) => |
| | | _jsonKeyChecker.firstAnnotationOfExact(element) ?? |
| | | (element.getter == null |
| | | ? null |
| | | : _jsonKeyChecker.firstAnnotationOfExact(element.getter)); |
| | | |
| | | /// Returns `true` if [element] is annotated with [JsonKey]. |
| | | bool hasJsonKeyAnnotation(FieldElement element) => |
| | | jsonKeyAnnotation(element) != null; |
| | | |
| | | final _upperCase = RegExp('[A-Z]'); |
| | | |
| | | String kebabCase(String input) => _fixCase(input, '-'); |
| | | |
| | | String snakeCase(String input) => _fixCase(input, '_'); |
| | | |
| | | String _fixCase(String input, String seperator) => |
| | | input.replaceAllMapped(_upperCase, (match) { |
| | | var lower = match.group(0).toLowerCase(); |
| | | |
| | | if (match.start > 0) { |
| | | lower = '$seperator$lower'; |
| | | } |
| | | |
| | | return lower; |
| | | }); |
| | | |
| | | @alwaysThrows |
| | | void throwUnsupported(FieldElement element, String message) => |
| | | throw InvalidGenerationSourceError( |
| | | 'Error with `@JsonKey` on `${element.name}`. $message', |
| | | element: element); |
| | | |
| | | FieldRename _fromDartObject(ConstantReader reader) => reader.isNull |
| | | ? null |
| | | : FieldRename.values[reader.objectValue.getField('index').toIntValue()]; |
| | | |
| | | /// Return an instance of [JsonSerializable] corresponding to a the provided |
| | | /// [reader]. |
| | | JsonSerializable _valueForAnnotation(ConstantReader reader) => JsonSerializable( |
| | | anyMap: reader.read('anyMap').literalValue as bool, |
| | | checked: reader.read('checked').literalValue as bool, |
| | | createFactory: reader.read('createFactory').literalValue as bool, |
| | | createToJson: reader.read('createToJson').literalValue as bool, |
| | | disallowUnrecognizedKeys: |
| | | reader.read('disallowUnrecognizedKeys').literalValue as bool, |
| | | explicitToJson: reader.read('explicitToJson').literalValue as bool, |
| | | fieldRename: _fromDartObject(reader.read('fieldRename')), |
| | | generateToJsonFunction: |
| | | reader.read('generateToJsonFunction').literalValue as bool, |
| | | includeIfNull: reader.read('includeIfNull').literalValue as bool, |
| | | nullable: reader.read('nullable').literalValue as bool, |
| | | useWrappers: reader.read('useWrappers').literalValue as bool, |
| | | ); |
| | | |
| | | /// Returns a [JsonSerializable] with values from the [JsonSerializable] instance |
| | | /// represented by [reader]. |
| | | /// |
| | | /// For fields that are not defined in [JsonSerializable] or `null` in [reader], |
| | | /// use the values in [config]. |
| | | JsonSerializable mergeConfig(JsonSerializable config, ConstantReader reader) { |
| | | final annotation = _valueForAnnotation(reader); |
| | | |
| | | return JsonSerializable( |
| | | anyMap: annotation.anyMap ?? config.anyMap, |
| | | checked: annotation.checked ?? config.checked, |
| | | createFactory: annotation.createFactory ?? config.createFactory, |
| | | createToJson: annotation.createToJson ?? config.createToJson, |
| | | disallowUnrecognizedKeys: |
| | | annotation.disallowUnrecognizedKeys ?? config.disallowUnrecognizedKeys, |
| | | explicitToJson: annotation.explicitToJson ?? config.explicitToJson, |
| | | fieldRename: annotation.fieldRename ?? config.fieldRename, |
| | | generateToJsonFunction: |
| | | annotation.generateToJsonFunction ?? config.generateToJsonFunction, |
| | | includeIfNull: annotation.includeIfNull ?? config.includeIfNull, |
| | | nullable: annotation.nullable ?? config.nullable, |
| | | useWrappers: annotation.useWrappers ?? config.useWrappers, |
| | | ); |
| | | } |
| | | |
| | | bool isEnum(DartType targetType) => |
| | | targetType is InterfaceType && targetType.element.isEnum; |
| | | |
| | | final _enumMapExpando = Expando<Map<FieldElement, dynamic>>(); |
| | | |
| | | /// If [targetType] is an enum, returns a [Map] of the [FieldElement] instances |
| | | /// associated with the enum values mapped to the [String] values that represent |
| | | /// the serialized output. |
| | | /// |
| | | /// By default, the [String] value is just the name of the enum value. |
| | | /// If the enum value is annotated with [JsonKey], then the `name` property is |
| | | /// used if it's set and not `null`. |
| | | /// |
| | | /// If [targetType] is not an enum, `null` is returned. |
| | | Map<FieldElement, dynamic> enumFieldsMap(DartType targetType) { |
| | | MapEntry<FieldElement, dynamic> _generateEntry(FieldElement fe) { |
| | | final annotation = |
| | | const TypeChecker.fromRuntime(JsonValue).firstAnnotationOfExact(fe); |
| | | |
| | | dynamic fieldValue; |
| | | if (annotation == null) { |
| | | fieldValue = fe.name; |
| | | } else { |
| | | final reader = ConstantReader(annotation); |
| | | |
| | | final valueReader = reader.read('value'); |
| | | |
| | | if (valueReader.isString || valueReader.isNull || valueReader.isInt) { |
| | | fieldValue = valueReader.literalValue; |
| | | } else { |
| | | throw InvalidGenerationSourceError( |
| | | 'The `JsonValue` annotation on `$targetType.${fe.name}` does ' |
| | | 'not have a value of type String, int, or null.', |
| | | element: fe); |
| | | } |
| | | } |
| | | |
| | | final entry = MapEntry(fe, fieldValue); |
| | | |
| | | return entry; |
| | | } |
| | | |
| | | if (targetType is InterfaceType && targetType.element.isEnum) { |
| | | return _enumMapExpando[targetType] ??= |
| | | Map<FieldElement, dynamic>.fromEntries(targetType.element.fields |
| | | .where((p) => !p.isSynthetic) |
| | | .map(_generateEntry)); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /// If [targetType] is an enum, returns the [FieldElement] instances associated |
| | | /// with its values. |
| | | /// |
| | | /// Otherwise, `null`. |
| | | Iterable<FieldElement> iterateEnumFields(DartType targetType) => |
| | | enumFieldsMap(targetType)?.keys; |
| | | |
| | | /// Returns a quoted String literal for [value] that can be used in generated |
| | | /// Dart code. |
| | | String escapeDartString(String value) { |
| | | var hasSingleQuote = false; |
| | | var hasDoubleQuote = false; |
| | | var hasDollar = false; |
| | | var canBeRaw = true; |
| | | |
| | | value = value.replaceAllMapped(_escapeRegExp, (match) { |
| | | final value = match[0]; |
| | | if (value == "'") { |
| | | hasSingleQuote = true; |
| | | return value; |
| | | } else if (value == '"') { |
| | | hasDoubleQuote = true; |
| | | return value; |
| | | } else if (value == r'$') { |
| | | hasDollar = true; |
| | | return value; |
| | | } |
| | | |
| | | canBeRaw = false; |
| | | return _escapeMap[value] ?? _getHexLiteral(value); |
| | | }); |
| | | |
| | | if (!hasDollar) { |
| | | if (hasSingleQuote) { |
| | | if (!hasDoubleQuote) { |
| | | return '"$value"'; |
| | | } |
| | | // something |
| | | } else { |
| | | // trivial! |
| | | return "'$value'"; |
| | | } |
| | | } |
| | | |
| | | if (hasDollar && canBeRaw) { |
| | | if (hasSingleQuote) { |
| | | if (!hasDoubleQuote) { |
| | | // quote it with single quotes! |
| | | return 'r"$value"'; |
| | | } |
| | | } else { |
| | | // quote it with single quotes! |
| | | return "r'$value'"; |
| | | } |
| | | } |
| | | |
| | | // The only safe way to wrap the content is to escape all of the |
| | | // problematic characters - `$`, `'`, and `"` |
| | | final string = value.replaceAll(_dollarQuoteRegexp, r'\'); |
| | | return "'$string'"; |
| | | } |
| | | |
| | | final _dollarQuoteRegexp = RegExp(r"""(?=[$'"])"""); |
| | | |
| | | /// A [Map] between whitespace characters & `\` and their escape sequences. |
| | | const _escapeMap = { |
| | | '\b': r'\b', // 08 - backspace |
| | | '\t': r'\t', // 09 - tab |
| | | '\n': r'\n', // 0A - new line |
| | | '\v': r'\v', // 0B - vertical tab |
| | | '\f': r'\f', // 0C - form feed |
| | | '\r': r'\r', // 0D - carriage return |
| | | '\x7F': r'\x7F', // delete |
| | | r'\': r'\\' // backslash |
| | | }; |
| | | |
| | | final _escapeMapRegexp = _escapeMap.keys.map(_getHexLiteral).join(); |
| | | |
| | | /// A [RegExp] that matches whitespace characters that should be escaped and |
| | | /// single-quote, double-quote, and `$` |
| | | final _escapeRegExp = RegExp('[\$\'"\\x00-\\x07\\x0E-\\x1F$_escapeMapRegexp]'); |
| | | |
| | | /// Given single-character string, return the hex-escaped equivalent. |
| | | String _getHexLiteral(String input) { |
| | | final rune = input.runes.single; |
| | | final value = rune.toRadixString(16).toUpperCase().padLeft(2, '0'); |
| | | return '\\x$value'; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | export 'src/shared_checkers.dart' show simpleJsonTypeChecker, typeArgumentsOf; |
| | | export 'src/type_helper.dart' |
| | | show TypeHelperContext, TypeHelper, UnsupportedTypeError; |
| | | export 'src/type_helpers/convert_helper.dart'; |
| | | export 'src/type_helpers/date_time_helper.dart'; |
| | | export 'src/type_helpers/enum_helper.dart'; |
| | | export 'src/type_helpers/iterable_helper.dart'; |
| | | export 'src/type_helpers/json_converter_helper.dart'; |
| | | export 'src/type_helpers/json_helper.dart'; |
| | | export 'src/type_helpers/map_helper.dart'; |
| | | export 'src/type_helpers/uri_helper.dart'; |
| | | export 'src/type_helpers/value_helper.dart'; |
| New file |
| | |
| | | # See https://github.com/dart-lang/mono_repo for details |
| | | dart: |
| | | - stable |
| | | |
| | | stages: |
| | | - analyzer_and_format: |
| | | - group: |
| | | - dartfmt |
| | | - dartanalyzer: --fatal-infos --fatal-warnings . |
| | | dart: [dev] |
| | | - analyzer_and_format_stable: |
| | | - group: |
| | | - dartfmt |
| | | - dartanalyzer: --fatal-warnings . |
| | | dart: [stable] |
| | | - unit_test: |
| | | # Run the tests -- include the default-skipped presubmit tests |
| | | - test |
| | | - test: --run-skipped test/ensure_build_test.dart |
| | | - command: pub run build_runner test -- -p chrome |
| | | |
| | | cache: |
| | | directories: |
| | | - .dart_tool/build |
| New file |
| | |
| | | name: json_serializable |
| | | version: 2.0.0 |
| | | author: Dart Team <misc@dartlang.org> |
| | | description: Generates utilities to aid in serializing to/from JSON. |
| | | homepage: https://github.com/dart-lang/json_serializable |
| | | environment: |
| | | sdk: '>=2.0.0 <3.0.0' |
| | | |
| | | dependencies: |
| | | analyzer: '>=0.32.2 <0.34.0' |
| | | build: '>=0.12.6 <2.0.0' |
| | | build_config: '>=0.2.6 <0.4.0' |
| | | |
| | | # Use a tight version constraint to ensure that a constraint on |
| | | # `json_annotation` properly constrains all features it provides. |
| | | json_annotation: '>=2.0.0 <2.1.0' |
| | | meta: ^1.1.0 |
| | | path: ^1.3.2 |
| | | source_gen: ^0.9.0 |
| | | |
| | | dev_dependencies: |
| | | build_runner: ^1.0.0 |
| | | build_test: ^0.10.0 |
| | | build_verify: ^1.1.0 |
| | | build_web_compilers: ^0.4.0+1 |
| | | collection: ^1.14.0 |
| | | dart_style: ^1.0.0 |
| | | logging: ^0.11.3+1 |
| | | test: ^1.3.3 |
| | | yaml: ^2.1.13 |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'dart:async'; |
| | | import 'dart:io'; |
| | | |
| | | import 'package:build/build.dart'; |
| | | import 'package:build_test/build_test.dart'; |
| | | import 'package:path/path.dart' as p; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | Future<LibraryReader> resolveCompilationUnit(String sourceDirectory) async { |
| | | final files = |
| | | Directory(sourceDirectory).listSync().whereType<File>().toList(); |
| | | |
| | | // Sort files to ensure the "first" one is first |
| | | files.sort((a, b) => p.basename(a.path).compareTo(p.basename(b.path))); |
| | | |
| | | final fileMap = Map<String, String>.fromEntries(files.map( |
| | | (f) => MapEntry('a|lib/${p.basename(f.path)}', f.readAsStringSync()))); |
| | | |
| | | final library = await resolveSources(fileMap, (item) async { |
| | | final assetId = AssetId.parse(fileMap.keys.first); |
| | | return await item.libraryFor(assetId); |
| | | }); |
| | | |
| | | return LibraryReader(library); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | @TestOn('vm') |
| | | import 'dart:io'; |
| | | |
| | | import 'package:build/build.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:json_serializable/builder.dart'; |
| | | import 'package:json_serializable/src/json_serializable_generator.dart'; |
| | | import 'package:test/test.dart'; |
| | | import 'package:yaml/yaml.dart'; |
| | | |
| | | import 'shared_config.dart'; |
| | | import 'test_utils.dart'; |
| | | |
| | | void main() { |
| | | test('fields in JsonSerializable are sorted', () { |
| | | expect(generatorConfigDefaultJson.keys, |
| | | orderedEquals(generatorConfigDefaultJson.keys.toList()..sort())); |
| | | }); |
| | | |
| | | test('empty', () async { |
| | | final builder = jsonSerializable(BuilderOptions.empty); |
| | | expect(builder, isNotNull); |
| | | }); |
| | | |
| | | test('valid default config', () async { |
| | | final builder = |
| | | jsonSerializable(BuilderOptions(generatorConfigDefaultJson)); |
| | | expect(builder, isNotNull); |
| | | }); |
| | | |
| | | test('valid, non-default config', () { |
| | | expect(generatorConfigNonDefaultJson.keys, |
| | | unorderedEquals(generatorConfigDefaultJson.keys)); |
| | | |
| | | for (var entry in generatorConfigDefaultJson.entries) { |
| | | expect(generatorConfigNonDefaultJson, |
| | | containsPair(entry.key, isNot(entry.value)), |
| | | reason: 'should have values that are different than the defaults'); |
| | | } |
| | | |
| | | final builder = |
| | | jsonSerializable(BuilderOptions(generatorConfigNonDefaultJson)); |
| | | expect(builder, isNotNull); |
| | | }); |
| | | |
| | | test('config is null-protected when passed to JsonSerializableGenerator', () { |
| | | final nullValueMap = Map.fromEntries( |
| | | generatorConfigDefaultJson.entries.map((e) => MapEntry(e.key, null))); |
| | | final config = JsonSerializable.fromJson(nullValueMap); |
| | | final generator = JsonSerializableGenerator(config: config); |
| | | expect(generator.config.toJson(), generatorConfigDefaultJson); |
| | | }); |
| | | |
| | | test('readme config', () async { |
| | | final configExampleContent = File('README.md') |
| | | .readAsLinesSync() |
| | | .skipWhile((line) => line != '```yaml') |
| | | .skip(1) |
| | | .takeWhile((line) => line != '```') |
| | | .join('\n'); |
| | | |
| | | var yaml = loadYaml(configExampleContent) as YamlMap; |
| | | |
| | | for (final key in [ |
| | | 'targets', |
| | | r'$default', |
| | | 'builders', |
| | | 'json_serializable', |
| | | 'options' |
| | | ]) { |
| | | yaml = yaml[key] as YamlMap; |
| | | } |
| | | |
| | | final configMap = Map<String, dynamic>.from(yaml); |
| | | |
| | | expect(configMap.keys, unorderedEquals(generatorConfigDefaultJson.keys), |
| | | reason: 'All supported keys are documented.'); |
| | | |
| | | expect(JsonSerializable.fromJson(configMap).toJson(), |
| | | generatorConfigDefaultJson, |
| | | reason: 'All keys specify their default value.'); |
| | | |
| | | final builder = jsonSerializable(BuilderOptions(configMap)); |
| | | expect(builder, isNotNull); |
| | | }); |
| | | |
| | | test('unsupported configuration', () async { |
| | | final matcher = const TypeMatcher<UnrecognizedKeysException>().having( |
| | | (e) => e.unrecognizedKeys, 'unrecognizedKeys', [ |
| | | 'unsupported' |
| | | ]).having((e) => e.allowedKeys, 'allowedKeys', |
| | | unorderedEquals(generatorConfigDefaultJson.keys)); |
| | | |
| | | expect( |
| | | () => jsonSerializable(const BuilderOptions({'unsupported': 'config'})), |
| | | throwsA(matcher)); |
| | | }); |
| | | |
| | | group('invalid config', () { |
| | | test('validated for all supported keys', () { |
| | | expect(_invalidConfig.keys, generatorConfigDefaultJson.keys); |
| | | }); |
| | | for (final entry in _invalidConfig.entries) { |
| | | test(entry.key, () { |
| | | final config = Map<String, dynamic>.from(generatorConfigDefaultJson); |
| | | config[entry.key] = entry.value; |
| | | |
| | | final matcher = (entry.key == 'field_rename') |
| | | ? isArgumentError.having((e) => e.message, 'message', |
| | | '`42` is not one of the supported values: none, kebab, snake') |
| | | : isCastError; |
| | | |
| | | expect( |
| | | () => jsonSerializable(BuilderOptions(config)), throwsA(matcher)); |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | const _invalidConfig = { |
| | | 'any_map': 42, |
| | | 'checked': 42, |
| | | 'create_factory': 42, |
| | | 'create_to_json': 42, |
| | | 'disallow_unrecognized_keys': 42, |
| | | 'explicit_to_json': 42, |
| | | 'field_rename': 42, |
| | | 'generate_to_json_function': 42, |
| | | 'include_if_null': 42, |
| | | 'nullable': 42, |
| | | 'use_wrappers': 42, |
| | | }; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _CheckedGenerator |
| | | // ************************************************************************** |
| | | |
| | | // ignore_for_file: annotate_overrides |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'default_value_interface.dart' as dvi hide Greek; |
| | | import 'default_value_interface.dart' show Greek; |
| | | |
| | | part 'default_value.checked.g.dart'; |
| | | |
| | | const _intValue = 42; |
| | | |
| | | dvi.DefaultValue fromJson(Map<String, dynamic> json) => |
| | | _$DefaultValueFromJson(json); |
| | | |
| | | @JsonSerializable( |
| | | anyMap: true, |
| | | checked: true, |
| | | ) |
| | | class DefaultValue implements dvi.DefaultValue { |
| | | @JsonKey(defaultValue: true) |
| | | bool fieldBool; |
| | | |
| | | @JsonKey(defaultValue: 'string', includeIfNull: false) |
| | | String fieldString; |
| | | |
| | | @JsonKey(defaultValue: _intValue) |
| | | int fieldInt; |
| | | |
| | | @JsonKey(defaultValue: 3.14) |
| | | double fieldDouble; |
| | | |
| | | @JsonKey(defaultValue: []) |
| | | List fieldListEmpty; |
| | | |
| | | @JsonKey(defaultValue: {}) |
| | | Map fieldMapEmpty; |
| | | |
| | | @JsonKey(defaultValue: [1, 2, 3]) |
| | | List<int> fieldListSimple; |
| | | |
| | | @JsonKey(defaultValue: {'answer': 42}) |
| | | Map<String, int> fieldMapSimple; |
| | | |
| | | @JsonKey(defaultValue: { |
| | | 'root': ['child'] |
| | | }) |
| | | Map<String, List<String>> fieldMapListString; |
| | | |
| | | @JsonKey(defaultValue: Greek.beta) |
| | | Greek fieldEnum; |
| | | |
| | | DefaultValue(); |
| | | |
| | | factory DefaultValue.fromJson(Map<String, dynamic> json) => |
| | | _$DefaultValueFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$DefaultValueToJson(this); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'default_value.checked.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | DefaultValue _$DefaultValueFromJson(Map json) { |
| | | return $checkedNew('DefaultValue', json, () { |
| | | final val = DefaultValue(); |
| | | $checkedConvert( |
| | | json, 'fieldBool', (v) => val.fieldBool = v as bool ?? true); |
| | | $checkedConvert( |
| | | json, 'fieldString', (v) => val.fieldString = v as String ?? 'string'); |
| | | $checkedConvert(json, 'fieldInt', (v) => val.fieldInt = v as int ?? 42); |
| | | $checkedConvert(json, 'fieldDouble', |
| | | (v) => val.fieldDouble = (v as num)?.toDouble() ?? 3.14); |
| | | $checkedConvert( |
| | | json, 'fieldListEmpty', (v) => val.fieldListEmpty = v as List ?? []); |
| | | $checkedConvert( |
| | | json, 'fieldMapEmpty', (v) => val.fieldMapEmpty = v as Map ?? {}); |
| | | $checkedConvert( |
| | | json, |
| | | 'fieldListSimple', |
| | | (v) => val.fieldListSimple = |
| | | (v as List)?.map((e) => e as int)?.toList() ?? [1, 2, 3]); |
| | | $checkedConvert( |
| | | json, |
| | | 'fieldMapSimple', |
| | | (v) => val.fieldMapSimple = |
| | | (v as Map)?.map((k, e) => MapEntry(k as String, e as int)) ?? |
| | | {'answer': 42}); |
| | | $checkedConvert( |
| | | json, |
| | | 'fieldMapListString', |
| | | (v) => val.fieldMapListString = (v as Map)?.map((k, e) => MapEntry( |
| | | k as String, (e as List)?.map((e) => e as String)?.toList())) ?? |
| | | { |
| | | 'root': ['child'] |
| | | }); |
| | | $checkedConvert( |
| | | json, |
| | | 'fieldEnum', |
| | | (v) => val.fieldEnum = |
| | | _$enumDecodeNullable(_$GreekEnumMap, v) ?? Greek.beta); |
| | | return val; |
| | | }); |
| | | } |
| | | |
| | | Map<String, dynamic> _$DefaultValueToJson(DefaultValue instance) { |
| | | final val = <String, dynamic>{ |
| | | 'fieldBool': instance.fieldBool, |
| | | }; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('fieldString', instance.fieldString); |
| | | val['fieldInt'] = instance.fieldInt; |
| | | val['fieldDouble'] = instance.fieldDouble; |
| | | val['fieldListEmpty'] = instance.fieldListEmpty; |
| | | val['fieldMapEmpty'] = instance.fieldMapEmpty; |
| | | val['fieldListSimple'] = instance.fieldListSimple; |
| | | val['fieldMapSimple'] = instance.fieldMapSimple; |
| | | val['fieldMapListString'] = instance.fieldMapListString; |
| | | val['fieldEnum'] = _$GreekEnumMap[instance.fieldEnum]; |
| | | return val; |
| | | } |
| | | |
| | | T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | throw ArgumentError('A value must be provided. Supported values: ' |
| | | '${enumValues.values.join(', ')}'); |
| | | } |
| | | return enumValues.entries |
| | | .singleWhere((e) => e.value == source, |
| | | orElse: () => throw ArgumentError( |
| | | '`$source` is not one of the supported values: ' |
| | | '${enumValues.values.join(', ')}')) |
| | | .key; |
| | | } |
| | | |
| | | T _$enumDecodeNullable<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | return null; |
| | | } |
| | | return _$enumDecode<T>(enumValues, source); |
| | | } |
| | | |
| | | const _$GreekEnumMap = <Greek, dynamic>{ |
| | | Greek.alpha: 'alpha', |
| | | Greek.beta: 'beta', |
| | | Greek.gamma: 'gamma', |
| | | Greek.delta: 'delta' |
| | | }; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // ignore_for_file: annotate_overrides |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'default_value_interface.dart' as dvi hide Greek; |
| | | import 'default_value_interface.dart' show Greek; |
| | | |
| | | part 'default_value.g.dart'; |
| | | |
| | | const _intValue = 42; |
| | | |
| | | dvi.DefaultValue fromJson(Map<String, dynamic> json) => |
| | | _$DefaultValueFromJson(json); |
| | | |
| | | @JsonSerializable() |
| | | class DefaultValue implements dvi.DefaultValue { |
| | | @JsonKey(defaultValue: true) |
| | | bool fieldBool; |
| | | |
| | | @JsonKey(defaultValue: 'string', includeIfNull: false) |
| | | String fieldString; |
| | | |
| | | @JsonKey(defaultValue: _intValue) |
| | | int fieldInt; |
| | | |
| | | @JsonKey(defaultValue: 3.14) |
| | | double fieldDouble; |
| | | |
| | | @JsonKey(defaultValue: []) |
| | | List fieldListEmpty; |
| | | |
| | | @JsonKey(defaultValue: {}) |
| | | Map fieldMapEmpty; |
| | | |
| | | @JsonKey(defaultValue: [1, 2, 3]) |
| | | List<int> fieldListSimple; |
| | | |
| | | @JsonKey(defaultValue: {'answer': 42}) |
| | | Map<String, int> fieldMapSimple; |
| | | |
| | | @JsonKey(defaultValue: { |
| | | 'root': ['child'] |
| | | }) |
| | | Map<String, List<String>> fieldMapListString; |
| | | |
| | | @JsonKey(defaultValue: Greek.beta) |
| | | Greek fieldEnum; |
| | | |
| | | DefaultValue(); |
| | | |
| | | factory DefaultValue.fromJson(Map<String, dynamic> json) => |
| | | _$DefaultValueFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$DefaultValueToJson(this); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'default_value.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | DefaultValue _$DefaultValueFromJson(Map<String, dynamic> json) { |
| | | return DefaultValue() |
| | | ..fieldBool = json['fieldBool'] as bool ?? true |
| | | ..fieldString = json['fieldString'] as String ?? 'string' |
| | | ..fieldInt = json['fieldInt'] as int ?? 42 |
| | | ..fieldDouble = (json['fieldDouble'] as num)?.toDouble() ?? 3.14 |
| | | ..fieldListEmpty = json['fieldListEmpty'] as List ?? [] |
| | | ..fieldMapEmpty = json['fieldMapEmpty'] as Map<String, dynamic> ?? {} |
| | | ..fieldListSimple = |
| | | (json['fieldListSimple'] as List)?.map((e) => e as int)?.toList() ?? |
| | | [1, 2, 3] |
| | | ..fieldMapSimple = (json['fieldMapSimple'] as Map<String, dynamic>) |
| | | ?.map((k, e) => MapEntry(k, e as int)) ?? |
| | | {'answer': 42} |
| | | ..fieldMapListString = (json['fieldMapListString'] as Map<String, dynamic>) |
| | | ?.map((k, e) => |
| | | MapEntry(k, (e as List)?.map((e) => e as String)?.toList())) ?? |
| | | { |
| | | 'root': ['child'] |
| | | } |
| | | ..fieldEnum = |
| | | _$enumDecodeNullable(_$GreekEnumMap, json['fieldEnum']) ?? Greek.beta; |
| | | } |
| | | |
| | | Map<String, dynamic> _$DefaultValueToJson(DefaultValue instance) { |
| | | final val = <String, dynamic>{ |
| | | 'fieldBool': instance.fieldBool, |
| | | }; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('fieldString', instance.fieldString); |
| | | val['fieldInt'] = instance.fieldInt; |
| | | val['fieldDouble'] = instance.fieldDouble; |
| | | val['fieldListEmpty'] = instance.fieldListEmpty; |
| | | val['fieldMapEmpty'] = instance.fieldMapEmpty; |
| | | val['fieldListSimple'] = instance.fieldListSimple; |
| | | val['fieldMapSimple'] = instance.fieldMapSimple; |
| | | val['fieldMapListString'] = instance.fieldMapListString; |
| | | val['fieldEnum'] = _$GreekEnumMap[instance.fieldEnum]; |
| | | return val; |
| | | } |
| | | |
| | | T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | throw ArgumentError('A value must be provided. Supported values: ' |
| | | '${enumValues.values.join(', ')}'); |
| | | } |
| | | return enumValues.entries |
| | | .singleWhere((e) => e.value == source, |
| | | orElse: () => throw ArgumentError( |
| | | '`$source` is not one of the supported values: ' |
| | | '${enumValues.values.join(', ')}')) |
| | | .key; |
| | | } |
| | | |
| | | T _$enumDecodeNullable<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | return null; |
| | | } |
| | | return _$enumDecode<T>(enumValues, source); |
| | | } |
| | | |
| | | const _$GreekEnumMap = <Greek, dynamic>{ |
| | | Greek.alpha: 'alpha', |
| | | Greek.beta: 'beta', |
| | | Greek.gamma: 'gamma', |
| | | Greek.delta: 'delta' |
| | | }; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | abstract class DefaultValue { |
| | | bool fieldBool; |
| | | String fieldString; |
| | | int fieldInt; |
| | | double fieldDouble; |
| | | List fieldListEmpty; |
| | | Map fieldMapEmpty; |
| | | List<int> fieldListSimple; |
| | | Map<String, int> fieldMapSimple; |
| | | Map<String, List<String>> fieldMapListString; |
| | | Greek fieldEnum; |
| | | } |
| | | |
| | | enum Greek { alpha, beta, gamma, delta } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:test/test.dart'; |
| | | |
| | | import '../test_utils.dart'; |
| | | import 'default_value.checked.dart' as checked; |
| | | import 'default_value.dart' as normal; |
| | | import 'default_value_interface.dart'; |
| | | |
| | | const _defaultInstance = { |
| | | 'fieldBool': true, |
| | | 'fieldString': 'string', |
| | | 'fieldInt': 42, |
| | | 'fieldDouble': 3.14, |
| | | 'fieldListEmpty': [], |
| | | 'fieldMapEmpty': <String, dynamic>{}, |
| | | 'fieldListSimple': [1, 2, 3], |
| | | 'fieldMapSimple': <String, dynamic>{'answer': 42}, |
| | | 'fieldMapListString': { |
| | | 'root': ['child'] |
| | | }, |
| | | 'fieldEnum': 'beta' |
| | | }; |
| | | |
| | | const _otherValues = { |
| | | 'fieldBool': false, |
| | | 'fieldString': 'other string', |
| | | 'fieldInt': 43, |
| | | 'fieldDouble': 2.718, |
| | | 'fieldListEmpty': [42], |
| | | 'fieldMapEmpty': {'question': false}, |
| | | 'fieldListSimple': [4, 5, 6], |
| | | 'fieldMapSimple': <String, dynamic>{}, |
| | | 'fieldMapListString': { |
| | | 'root2': ['alpha'] |
| | | }, |
| | | 'fieldEnum': 'delta' |
| | | }; |
| | | |
| | | void main() { |
| | | group('nullable', () => _test(normal.fromJson)); |
| | | group('non-nullable', () => _test(checked.fromJson)); |
| | | } |
| | | |
| | | void _test(DefaultValue fromJson(Map<String, dynamic> json)) { |
| | | test('empty map yields all default values', () { |
| | | final object = fromJson({}); |
| | | expect(loudEncode(object), loudEncode(_defaultInstance)); |
| | | }); |
| | | test('default value input round-trips', () { |
| | | final object = fromJson(_defaultInstance); |
| | | expect(loudEncode(object), loudEncode(_defaultInstance)); |
| | | }); |
| | | test('non-default values round-trip', () { |
| | | final object = fromJson(_otherValues); |
| | | expect(loudEncode(object), loudEncode(_otherValues)); |
| | | }); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | @TestOn('vm') |
| | | @Tags(['presubmit-only']) |
| | | import 'package:build_verify/build_verify.dart'; |
| | | import 'package:test/test.dart'; |
| | | |
| | | void main() { |
| | | test('ensure_build', |
| | | () => expectBuildClean(packageRelativeDirectory: 'json_serializable')); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | @TestOn('vm') |
| | | |
| | | import 'package:test/test.dart'; |
| | | import 'package:json_serializable/src/type_helpers/enum_helper.dart'; |
| | | |
| | | void main() { |
| | | group('expression test', () { |
| | | group('simple', () { |
| | | for (final expression in [ |
| | | 'hello', |
| | | 'HELLO', |
| | | 'hi_to', |
| | | '_private', |
| | | 'weird_' |
| | | ]) { |
| | | test(expression, () { |
| | | expect(simpleExpression.hasMatch(expression), isTrue); |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | group('not simple', () { |
| | | for (final expression in ['nice[thing]', 'a.b']) { |
| | | test(expression, () { |
| | | expect(simpleExpression.hasMatch(expression), isFalse); |
| | | }); |
| | | } |
| | | }); |
| | | }); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | part 'generic_class.g.dart'; |
| | | |
| | | @JsonSerializable() |
| | | class GenericClass<T extends num, S> { |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | Object fieldObject; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | dynamic fieldDynamic; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | int fieldInt; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | T fieldT; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | S fieldS; |
| | | |
| | | GenericClass(); |
| | | |
| | | factory GenericClass.fromJson(Map<String, dynamic> json) => |
| | | _$GenericClassFromJson<T, S>(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$GenericClassToJson(this); |
| | | |
| | | static T _dataFromJson<T, S, U>(Map<String, dynamic> input, |
| | | [S other1, U other2]) => |
| | | input['value'] as T; |
| | | |
| | | static Map<String, dynamic> _dataToJson<T, S, U>(T input, |
| | | [S other1, U other2]) => |
| | | {'value': input}; |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | @_DurationMillisecondConverter() |
| | | @_DurationListMillisecondConverter() |
| | | class GenericClassWithConverter<T extends num, S> { |
| | | @_SimpleConverter() |
| | | Object fieldObject; |
| | | |
| | | @_SimpleConverter() |
| | | dynamic fieldDynamic; |
| | | |
| | | @_SimpleConverter() |
| | | int fieldInt; |
| | | |
| | | @_SimpleConverter() |
| | | T fieldT; |
| | | |
| | | @_SimpleConverter() |
| | | S fieldS; |
| | | |
| | | Duration duration; |
| | | |
| | | List<Duration> listDuration; |
| | | |
| | | GenericClassWithConverter(); |
| | | |
| | | factory GenericClassWithConverter.fromJson(Map<String, dynamic> json) => |
| | | _$GenericClassWithConverterFromJson<T, S>(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$GenericClassWithConverterToJson(this); |
| | | } |
| | | |
| | | class _SimpleConverter<T> implements JsonConverter<T, Map<String, dynamic>> { |
| | | const _SimpleConverter(); |
| | | |
| | | @override |
| | | T fromJson(Map<String, dynamic> json) => json['value'] as T; |
| | | |
| | | @override |
| | | Map<String, dynamic> toJson(T object) => {'value': object}; |
| | | } |
| | | |
| | | class _DurationMillisecondConverter implements JsonConverter<Duration, int> { |
| | | const _DurationMillisecondConverter(); |
| | | |
| | | const _DurationMillisecondConverter.named(); |
| | | |
| | | @override |
| | | Duration fromJson(int json) => |
| | | json == null ? null : Duration(milliseconds: json); |
| | | |
| | | @override |
| | | int toJson(Duration object) => object?.inMilliseconds; |
| | | } |
| | | |
| | | class _DurationListMillisecondConverter |
| | | implements JsonConverter<List<Duration>, int> { |
| | | const _DurationListMillisecondConverter(); |
| | | |
| | | @override |
| | | List<Duration> fromJson(int json) => [Duration(milliseconds: json)]; |
| | | |
| | | @override |
| | | int toJson(List<Duration> object) => object?.fold<int>(0, (sum, obj) { |
| | | return sum + obj.inMilliseconds; |
| | | }); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'generic_class.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | GenericClass<T, S> _$GenericClassFromJson<T extends num, S>( |
| | | Map<String, dynamic> json) { |
| | | return GenericClass<T, S>() |
| | | ..fieldObject = json['fieldObject'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson( |
| | | json['fieldObject'] as Map<String, dynamic>) |
| | | ..fieldDynamic = json['fieldDynamic'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson( |
| | | json['fieldDynamic'] as Map<String, dynamic>) |
| | | ..fieldInt = json['fieldInt'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson(json['fieldInt'] as Map<String, dynamic>) |
| | | ..fieldT = json['fieldT'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson(json['fieldT'] as Map<String, dynamic>) |
| | | ..fieldS = json['fieldS'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson(json['fieldS'] as Map<String, dynamic>); |
| | | } |
| | | |
| | | Map<String, dynamic> _$GenericClassToJson<T extends num, S>( |
| | | GenericClass<T, S> instance) => |
| | | <String, dynamic>{ |
| | | 'fieldObject': instance.fieldObject == null |
| | | ? null |
| | | : GenericClass._dataToJson(instance.fieldObject), |
| | | 'fieldDynamic': instance.fieldDynamic == null |
| | | ? null |
| | | : GenericClass._dataToJson(instance.fieldDynamic), |
| | | 'fieldInt': instance.fieldInt == null |
| | | ? null |
| | | : GenericClass._dataToJson(instance.fieldInt), |
| | | 'fieldT': instance.fieldT == null |
| | | ? null |
| | | : GenericClass._dataToJson(instance.fieldT), |
| | | 'fieldS': instance.fieldS == null |
| | | ? null |
| | | : GenericClass._dataToJson(instance.fieldS) |
| | | }; |
| | | |
| | | GenericClassWithConverter<T, S> |
| | | _$GenericClassWithConverterFromJson<T extends num, S>( |
| | | Map<String, dynamic> json) { |
| | | return GenericClassWithConverter<T, S>() |
| | | ..fieldObject = json['fieldObject'] |
| | | ..fieldDynamic = json['fieldDynamic'] |
| | | ..fieldInt = json['fieldInt'] as int |
| | | ..fieldT = json['fieldT'] == null |
| | | ? null |
| | | : _SimpleConverter<T>().fromJson(json['fieldT'] as Map<String, dynamic>) |
| | | ..fieldS = json['fieldS'] == null |
| | | ? null |
| | | : _SimpleConverter<S>().fromJson(json['fieldS'] as Map<String, dynamic>) |
| | | ..duration = json['duration'] == null |
| | | ? null |
| | | : const _DurationMillisecondConverter() |
| | | .fromJson(json['duration'] as int) |
| | | ..listDuration = json['listDuration'] == null |
| | | ? null |
| | | : const _DurationListMillisecondConverter() |
| | | .fromJson(json['listDuration'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$GenericClassWithConverterToJson<T extends num, S>( |
| | | GenericClassWithConverter<T, S> instance) => |
| | | <String, dynamic>{ |
| | | 'fieldObject': instance.fieldObject, |
| | | 'fieldDynamic': instance.fieldDynamic, |
| | | 'fieldInt': instance.fieldInt, |
| | | 'fieldT': instance.fieldT == null |
| | | ? null |
| | | : _SimpleConverter<T>().toJson(instance.fieldT), |
| | | 'fieldS': instance.fieldS == null |
| | | ? null |
| | | : _SimpleConverter<S>().toJson(instance.fieldS), |
| | | 'duration': instance.duration == null |
| | | ? null |
| | | : const _DurationMillisecondConverter().toJson(instance.duration), |
| | | 'listDuration': instance.listDuration == null |
| | | ? null |
| | | : const _DurationListMillisecondConverter() |
| | | .toJson(instance.listDuration) |
| | | }; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _WrappedGenerator |
| | | // ************************************************************************** |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | part 'generic_class.wrapped.g.dart'; |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | ) |
| | | class GenericClass<T extends num, S> { |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | Object fieldObject; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | dynamic fieldDynamic; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | int fieldInt; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | T fieldT; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | S fieldS; |
| | | |
| | | GenericClass(); |
| | | |
| | | factory GenericClass.fromJson(Map<String, dynamic> json) => |
| | | _$GenericClassFromJson<T, S>(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$GenericClassToJson(this); |
| | | |
| | | static T _dataFromJson<T, S, U>(Map<String, dynamic> input, |
| | | [S other1, U other2]) => |
| | | input['value'] as T; |
| | | |
| | | static Map<String, dynamic> _dataToJson<T, S, U>(T input, |
| | | [S other1, U other2]) => |
| | | {'value': input}; |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | ) |
| | | @_DurationMillisecondConverter() |
| | | @_DurationListMillisecondConverter() |
| | | class GenericClassWithConverter<T extends num, S> { |
| | | @_SimpleConverter() |
| | | Object fieldObject; |
| | | |
| | | @_SimpleConverter() |
| | | dynamic fieldDynamic; |
| | | |
| | | @_SimpleConverter() |
| | | int fieldInt; |
| | | |
| | | @_SimpleConverter() |
| | | T fieldT; |
| | | |
| | | @_SimpleConverter() |
| | | S fieldS; |
| | | |
| | | Duration duration; |
| | | |
| | | List<Duration> listDuration; |
| | | |
| | | GenericClassWithConverter(); |
| | | |
| | | factory GenericClassWithConverter.fromJson(Map<String, dynamic> json) => |
| | | _$GenericClassWithConverterFromJson<T, S>(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$GenericClassWithConverterToJson(this); |
| | | } |
| | | |
| | | class _SimpleConverter<T> implements JsonConverter<T, Map<String, dynamic>> { |
| | | const _SimpleConverter(); |
| | | |
| | | @override |
| | | T fromJson(Map<String, dynamic> json) => json['value'] as T; |
| | | |
| | | @override |
| | | Map<String, dynamic> toJson(T object) => {'value': object}; |
| | | } |
| | | |
| | | class _DurationMillisecondConverter implements JsonConverter<Duration, int> { |
| | | const _DurationMillisecondConverter(); |
| | | |
| | | const _DurationMillisecondConverter.named(); |
| | | |
| | | @override |
| | | Duration fromJson(int json) => |
| | | json == null ? null : Duration(milliseconds: json); |
| | | |
| | | @override |
| | | int toJson(Duration object) => object?.inMilliseconds; |
| | | } |
| | | |
| | | class _DurationListMillisecondConverter |
| | | implements JsonConverter<List<Duration>, int> { |
| | | const _DurationListMillisecondConverter(); |
| | | |
| | | @override |
| | | List<Duration> fromJson(int json) => [Duration(milliseconds: json)]; |
| | | |
| | | @override |
| | | int toJson(List<Duration> object) => object?.fold<int>(0, (sum, obj) { |
| | | return sum + obj.inMilliseconds; |
| | | }); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'generic_class.wrapped.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | GenericClass<T, S> _$GenericClassFromJson<T extends num, S>( |
| | | Map<String, dynamic> json) { |
| | | return GenericClass<T, S>() |
| | | ..fieldObject = json['fieldObject'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson( |
| | | json['fieldObject'] as Map<String, dynamic>) |
| | | ..fieldDynamic = json['fieldDynamic'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson( |
| | | json['fieldDynamic'] as Map<String, dynamic>) |
| | | ..fieldInt = json['fieldInt'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson(json['fieldInt'] as Map<String, dynamic>) |
| | | ..fieldT = json['fieldT'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson(json['fieldT'] as Map<String, dynamic>) |
| | | ..fieldS = json['fieldS'] == null |
| | | ? null |
| | | : GenericClass._dataFromJson(json['fieldS'] as Map<String, dynamic>); |
| | | } |
| | | |
| | | Map<String, dynamic> _$GenericClassToJson<T extends num, S>( |
| | | GenericClass<T, S> instance) => |
| | | _$GenericClassJsonMapWrapper<T, S>(instance); |
| | | |
| | | class _$GenericClassJsonMapWrapper<T extends num, S> extends $JsonMapWrapper { |
| | | final GenericClass<T, S> _v; |
| | | _$GenericClassJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => |
| | | const ['fieldObject', 'fieldDynamic', 'fieldInt', 'fieldT', 'fieldS']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'fieldObject': |
| | | return _v.fieldObject == null |
| | | ? null |
| | | : GenericClass._dataToJson(_v.fieldObject); |
| | | case 'fieldDynamic': |
| | | return _v.fieldDynamic == null |
| | | ? null |
| | | : GenericClass._dataToJson(_v.fieldDynamic); |
| | | case 'fieldInt': |
| | | return _v.fieldInt == null |
| | | ? null |
| | | : GenericClass._dataToJson(_v.fieldInt); |
| | | case 'fieldT': |
| | | return _v.fieldT == null ? null : GenericClass._dataToJson(_v.fieldT); |
| | | case 'fieldS': |
| | | return _v.fieldS == null ? null : GenericClass._dataToJson(_v.fieldS); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | GenericClassWithConverter<T, S> |
| | | _$GenericClassWithConverterFromJson<T extends num, S>( |
| | | Map<String, dynamic> json) { |
| | | return GenericClassWithConverter<T, S>() |
| | | ..fieldObject = json['fieldObject'] |
| | | ..fieldDynamic = json['fieldDynamic'] |
| | | ..fieldInt = json['fieldInt'] as int |
| | | ..fieldT = json['fieldT'] == null |
| | | ? null |
| | | : _SimpleConverter<T>().fromJson(json['fieldT'] as Map<String, dynamic>) |
| | | ..fieldS = json['fieldS'] == null |
| | | ? null |
| | | : _SimpleConverter<S>().fromJson(json['fieldS'] as Map<String, dynamic>) |
| | | ..duration = json['duration'] == null |
| | | ? null |
| | | : const _DurationMillisecondConverter() |
| | | .fromJson(json['duration'] as int) |
| | | ..listDuration = json['listDuration'] == null |
| | | ? null |
| | | : const _DurationListMillisecondConverter() |
| | | .fromJson(json['listDuration'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$GenericClassWithConverterToJson<T extends num, S>( |
| | | GenericClassWithConverter<T, S> instance) => |
| | | _$GenericClassWithConverterJsonMapWrapper<T, S>(instance); |
| | | |
| | | class _$GenericClassWithConverterJsonMapWrapper<T extends num, S> |
| | | extends $JsonMapWrapper { |
| | | final GenericClassWithConverter<T, S> _v; |
| | | _$GenericClassWithConverterJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const [ |
| | | 'fieldObject', |
| | | 'fieldDynamic', |
| | | 'fieldInt', |
| | | 'fieldT', |
| | | 'fieldS', |
| | | 'duration', |
| | | 'listDuration' |
| | | ]; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'fieldObject': |
| | | return _v.fieldObject; |
| | | case 'fieldDynamic': |
| | | return _v.fieldDynamic; |
| | | case 'fieldInt': |
| | | return _v.fieldInt; |
| | | case 'fieldT': |
| | | return _v.fieldT == null |
| | | ? null |
| | | : _SimpleConverter<T>().toJson(_v.fieldT); |
| | | case 'fieldS': |
| | | return _v.fieldS == null |
| | | ? null |
| | | : _SimpleConverter<S>().toJson(_v.fieldS); |
| | | case 'duration': |
| | | return _v.duration == null |
| | | ? null |
| | | : const _DurationMillisecondConverter().toJson(_v.duration); |
| | | case 'listDuration': |
| | | return _v.listDuration == null |
| | | ? null |
| | | : const _DurationListMillisecondConverter() |
| | | .toJson(_v.listDuration); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'dart:convert'; |
| | | import 'package:test/test.dart'; |
| | | |
| | | import '../test_utils.dart'; |
| | | import 'generic_class.dart'; |
| | | |
| | | void main() { |
| | | group('generic', () { |
| | | GenericClass<T, S> roundTripGenericClass<T extends num, S>( |
| | | GenericClass<T, S> p) { |
| | | final outputJson = loudEncode(p); |
| | | final p2 = GenericClass<T, S>.fromJson( |
| | | jsonDecode(outputJson) as Map<String, dynamic>); |
| | | final outputJson2 = loudEncode(p2); |
| | | expect(outputJson2, outputJson); |
| | | return p2; |
| | | } |
| | | |
| | | test('no type args', () { |
| | | roundTripGenericClass(GenericClass() |
| | | ..fieldDynamic = 1 |
| | | ..fieldInt = 2 |
| | | ..fieldObject = 3 |
| | | ..fieldT = 5 |
| | | ..fieldS = 'six'); |
| | | }); |
| | | test('with type arguments', () { |
| | | roundTripGenericClass(GenericClass<double, String>() |
| | | ..fieldDynamic = 1 |
| | | ..fieldInt = 2 |
| | | ..fieldObject = 3 |
| | | ..fieldT = 5.0 |
| | | ..fieldS = 'six'); |
| | | }); |
| | | test('with bad arguments', () { |
| | | expect( |
| | | () => GenericClass<double, String>() |
| | | ..fieldT = (true as dynamic) as double, |
| | | throwsCastError); |
| | | }); |
| | | test('with bad arguments', () { |
| | | expect( |
| | | () => |
| | | GenericClass<double, String>()..fieldS = (5 as dynamic) as String, |
| | | throwsCastError); |
| | | }); |
| | | }); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:test/test.dart'; |
| | | |
| | | import '../test_utils.dart'; |
| | | import 'json_test_common.dart' show Category, Platform, StatusCode; |
| | | import 'json_test_example.dart'; |
| | | |
| | | Matcher _throwsArgumentError(matcher) => |
| | | throwsA(isArgumentError.having((e) => e.message, 'message', matcher)); |
| | | |
| | | void main() { |
| | | group('Person', () { |
| | | void roundTripPerson(Person p) { |
| | | roundTripObject(p, (json) => Person.fromJson(json)); |
| | | } |
| | | |
| | | test('null', () { |
| | | roundTripPerson(Person(null, null, null)); |
| | | }); |
| | | |
| | | test('empty', () { |
| | | roundTripPerson(Person('', '', null, |
| | | middleName: '', dateOfBirth: DateTime.fromMillisecondsSinceEpoch(0))); |
| | | }); |
| | | |
| | | test('now', () { |
| | | roundTripPerson(Person('a', 'b', Category.charmed, |
| | | middleName: 'c', dateOfBirth: DateTime.now())); |
| | | }); |
| | | |
| | | test('now toUtc', () { |
| | | roundTripPerson(Person('a', 'b', Category.bottom, |
| | | middleName: 'c', dateOfBirth: DateTime.now().toUtc())); |
| | | }); |
| | | |
| | | test('empty json', () { |
| | | final person = Person.fromJson({}); |
| | | expect(person.dateOfBirth, isNull); |
| | | roundTripPerson(person); |
| | | }); |
| | | |
| | | test('enum map', () { |
| | | final person = Person(null, null, null) |
| | | ..houseMap = {'bob': Category.strange} |
| | | ..categoryCounts = {Category.strange: 1}; |
| | | expect(person.dateOfBirth, isNull); |
| | | roundTripPerson(person); |
| | | }); |
| | | }); |
| | | |
| | | group('Order', () { |
| | | void roundTripOrder(Order p) { |
| | | roundTripObject(p, (json) => Order.fromJson(json)); |
| | | } |
| | | |
| | | test('null', () { |
| | | roundTripOrder(Order(Category.charmed)..statusCode = StatusCode.success); |
| | | }); |
| | | |
| | | test('empty', () { |
| | | roundTripOrder(Order(Category.strange, const []) |
| | | ..statusCode = StatusCode.success |
| | | ..count = 0 |
| | | ..isRushed = false); |
| | | }); |
| | | |
| | | test('simple', () { |
| | | roundTripOrder(Order(Category.top, <Item>[ |
| | | Item(24) |
| | | ..itemNumber = 42 |
| | | ..saleDates = [DateTime.now()] |
| | | ]) |
| | | ..statusCode = StatusCode.success |
| | | ..count = 42 |
| | | ..isRushed = true); |
| | | }); |
| | | |
| | | test('almost empty json', () { |
| | | final order = Order.fromJson({'category': 'not_discovered_yet'}); |
| | | expect(order.items, isEmpty); |
| | | expect(order.category, Category.notDiscoveredYet); |
| | | expect(order.statusCode, StatusCode.success); |
| | | roundTripOrder(order); |
| | | }); |
| | | |
| | | test('required, but missing enum value fails', () { |
| | | expect( |
| | | () => Order.fromJson({}), |
| | | _throwsArgumentError('A value must be provided. Supported values: ' |
| | | 'top, bottom, strange, charmed, up, down, not_discovered_yet')); |
| | | }); |
| | | |
| | | test('mismatched enum value fails', () { |
| | | expect( |
| | | () => Order.fromJson({'category': 'weird'}), |
| | | _throwsArgumentError('`weird` is not one of the supported values: ' |
| | | 'top, bottom, strange, charmed, up, down, not_discovered_yet')); |
| | | }); |
| | | |
| | | test('platform', () { |
| | | final order = Order(Category.charmed) |
| | | ..statusCode = StatusCode.success |
| | | ..platform = Platform.undefined |
| | | ..altPlatforms = { |
| | | 'u': Platform.undefined, |
| | | 'f': Platform.foo, |
| | | 'null': null |
| | | }; |
| | | |
| | | roundTripOrder(order); |
| | | }); |
| | | |
| | | test('homepage', () { |
| | | final order = Order(Category.charmed) |
| | | ..platform = Platform.undefined |
| | | ..statusCode = StatusCode.success |
| | | ..altPlatforms = { |
| | | 'u': Platform.undefined, |
| | | 'f': Platform.foo, |
| | | 'null': null |
| | | } |
| | | ..homepage = Uri.parse('https://dartlang.org'); |
| | | |
| | | roundTripOrder(order); |
| | | }); |
| | | |
| | | test('statusCode', () { |
| | | final order = Order.fromJson( |
| | | {'category': 'not_discovered_yet', 'status_code': 404}); |
| | | expect(order.statusCode, StatusCode.notFound); |
| | | roundTripOrder(order); |
| | | }); |
| | | |
| | | test('duration toJson', () { |
| | | final order = Order(Category.notDiscoveredYet) |
| | | ..statusCode = StatusCode.success |
| | | ..duration = const Duration( |
| | | days: 2, |
| | | hours: 4, |
| | | minutes: 54, |
| | | seconds: 33, |
| | | milliseconds: 23, |
| | | microseconds: 12, |
| | | ); |
| | | expect(order.toJson()['duration'], equals(190473023012)); |
| | | roundTripOrder(order); |
| | | }); |
| | | |
| | | test('duration fromJson', () { |
| | | final order = Order.fromJson({ |
| | | 'category': 'not_discovered_yet', |
| | | 'duration': 190473023012, |
| | | }); |
| | | expect( |
| | | order.duration, |
| | | equals(const Duration( |
| | | days: 2, |
| | | hours: 4, |
| | | minutes: 54, |
| | | seconds: 33, |
| | | milliseconds: 23, |
| | | microseconds: 12, |
| | | ))); |
| | | roundTripOrder(order); |
| | | }); |
| | | }); |
| | | |
| | | group('Item', () { |
| | | void roundTripItem(Item p) { |
| | | roundTripObject(p, (json) => Item.fromJson(json)); |
| | | } |
| | | |
| | | test('empty json', () { |
| | | final item = Item.fromJson({}); |
| | | expect(item.saleDates, isNull); |
| | | roundTripItem(item); |
| | | |
| | | expect(item.toJson().keys, orderedEquals(['price', 'saleDates', 'rates']), |
| | | reason: 'Omits null `itemNumber`'); |
| | | }); |
| | | |
| | | test('set itemNumber - with custom JSON key', () { |
| | | final item = Item.fromJson({'item-number': 42}); |
| | | expect(item.itemNumber, 42); |
| | | roundTripItem(item); |
| | | |
| | | expect(item.toJson().keys, |
| | | orderedEquals(['price', 'item-number', 'saleDates', 'rates']), |
| | | reason: 'Includes non-null `itemNumber` - with custom key'); |
| | | }); |
| | | }); |
| | | |
| | | group('Numbers', () { |
| | | void roundTripNumber(Numbers p) { |
| | | roundTripObject(p, (json) => Numbers.fromJson(json)); |
| | | } |
| | | |
| | | test('simple', () { |
| | | roundTripNumber(Numbers() |
| | | ..nums = [0, 0.0] |
| | | ..doubles = [0.0] |
| | | ..nnDoubles = [0.0] |
| | | ..ints = [0] |
| | | ..duration = const Duration(seconds: 1) |
| | | ..date = DateTime.now()); |
| | | }); |
| | | |
| | | test('custom DateTime', () { |
| | | final instance = Numbers() |
| | | ..date = DateTime.fromMillisecondsSinceEpoch(42); |
| | | final json = instance.toJson(); |
| | | expect(json, containsPair('date', 42000)); |
| | | }); |
| | | |
| | | test('support ints as doubles', () { |
| | | final value = { |
| | | 'doubles': [0, 0.0, null], |
| | | 'nnDoubles': [0, 0.0] |
| | | }; |
| | | |
| | | roundTripNumber(Numbers.fromJson(value)); |
| | | }); |
| | | |
| | | test('does not support doubles as ints', () { |
| | | final value = { |
| | | 'ints': [3.14, 0], |
| | | }; |
| | | |
| | | expect(() => Numbers.fromJson(value), throwsCastError); |
| | | }); |
| | | }); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:collection/collection.dart'; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | enum Category { |
| | | top, |
| | | bottom, |
| | | strange, |
| | | charmed, |
| | | up, |
| | | down, |
| | | @JsonValue('not_discovered_yet') |
| | | notDiscoveredYet |
| | | } |
| | | |
| | | enum StatusCode { |
| | | @JsonValue(200) |
| | | success, |
| | | @JsonValue(404) |
| | | notFound |
| | | } |
| | | |
| | | Duration durationFromInt(int ms) => Duration(milliseconds: ms); |
| | | int durationToInt(Duration duration) => duration.inMilliseconds; |
| | | |
| | | DateTime dateTimeFromEpochUs(int us) => DateTime.fromMicrosecondsSinceEpoch(us); |
| | | int dateTimeToEpochUs(DateTime dateTime) => dateTime.microsecondsSinceEpoch; |
| | | |
| | | bool deepEquals(a, b) => const DeepCollectionEquality().equals(a, b); |
| | | |
| | | class Platform { |
| | | final String description; |
| | | |
| | | static const Platform foo = Platform._('foo'); |
| | | static const Platform undefined = Platform._('undefined'); |
| | | const Platform._(this.description); |
| | | |
| | | factory Platform.fromJson(String value) { |
| | | switch (value) { |
| | | case 'foo': |
| | | return foo; |
| | | case 'undefined': |
| | | return undefined; |
| | | default: |
| | | throw ArgumentError.value(value, 'value', 'Not a supported value.'); |
| | | } |
| | | } |
| | | |
| | | String toJson() => description; |
| | | } |
| | | |
| | | abstract class ItemCore { |
| | | final int price; |
| | | |
| | | ItemCore(this.price); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // ignore_for_file: hash_and_equals |
| | | import 'dart:collection'; |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'json_test_common.dart'; |
| | | |
| | | part 'json_test_example.g.dart'; |
| | | |
| | | @JsonSerializable() |
| | | class Person { |
| | | final String firstName, middleName, lastName; |
| | | final DateTime dateOfBirth; |
| | | @JsonKey(name: '\$house') |
| | | final Category house; |
| | | |
| | | Order order; |
| | | |
| | | Map<String, Category> houseMap; |
| | | Map<Category, int> categoryCounts; |
| | | |
| | | Person(this.firstName, this.lastName, this.house, |
| | | {this.middleName, this.dateOfBirth}); |
| | | |
| | | factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$PersonToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Person && |
| | | firstName == other.firstName && |
| | | middleName == other.middleName && |
| | | lastName == other.lastName && |
| | | dateOfBirth == other.dateOfBirth && |
| | | house == other.house && |
| | | deepEquals(houseMap, other.houseMap); |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class Order { |
| | | /// Used to test that `disallowNullValues: true` forces `includeIfNull: false` |
| | | @JsonKey(disallowNullValue: true) |
| | | int count; |
| | | bool isRushed; |
| | | |
| | | Duration duration; |
| | | |
| | | @JsonKey(nullable: false) |
| | | final Category category; |
| | | final UnmodifiableListView<Item> items; |
| | | Platform platform; |
| | | Map<String, Platform> altPlatforms; |
| | | |
| | | Uri homepage; |
| | | |
| | | @JsonKey( |
| | | name: 'status_code', defaultValue: StatusCode.success, nullable: true) |
| | | StatusCode statusCode; |
| | | |
| | | @JsonKey(ignore: true) |
| | | String get platformValue => platform?.description; |
| | | |
| | | set platformValue(String value) { |
| | | throw UnimplementedError('not impld'); |
| | | } |
| | | |
| | | // Ignored getter without value set in ctor |
| | | int get price => items.fold(0, (total, item) => item.price + total); |
| | | |
| | | @JsonKey(ignore: true) |
| | | bool shouldBeCached; |
| | | |
| | | Order(this.category, [Iterable<Item> items]) |
| | | : items = UnmodifiableListView<Item>( |
| | | List<Item>.unmodifiable(items ?? const <Item>[])); |
| | | |
| | | factory Order.fromJson(Map<String, dynamic> json) => _$OrderFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$OrderToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Order && |
| | | count == other.count && |
| | | isRushed == other.isRushed && |
| | | deepEquals(items, other.items) && |
| | | deepEquals(altPlatforms, other.altPlatforms); |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class Item extends ItemCore { |
| | | @JsonKey(includeIfNull: false, name: 'item-number') |
| | | int itemNumber; |
| | | List<DateTime> saleDates; |
| | | List<int> rates; |
| | | |
| | | Item([int price]) : super(price); |
| | | |
| | | factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$ItemToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Item && |
| | | price == other.price && |
| | | itemNumber == other.itemNumber && |
| | | deepEquals(saleDates, other.saleDates); |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class Numbers { |
| | | List<int> ints; |
| | | List<num> nums; |
| | | List<double> doubles; |
| | | |
| | | @JsonKey(nullable: false) |
| | | List<double> nnDoubles; |
| | | |
| | | @JsonKey(fromJson: durationFromInt, toJson: durationToInt) |
| | | Duration duration; |
| | | |
| | | @JsonKey(fromJson: dateTimeFromEpochUs, toJson: dateTimeToEpochUs) |
| | | DateTime date; |
| | | |
| | | Numbers(); |
| | | |
| | | factory Numbers.fromJson(Map<String, dynamic> json) => |
| | | _$NumbersFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$NumbersToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Numbers && |
| | | deepEquals(ints, other.ints) && |
| | | deepEquals(nums, other.nums) && |
| | | deepEquals(doubles, other.doubles) && |
| | | deepEquals(nnDoubles, other.nnDoubles) && |
| | | deepEquals(duration, other.duration) && |
| | | deepEquals(date, other.date); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'json_test_example.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | Person _$PersonFromJson(Map<String, dynamic> json) { |
| | | return Person(json['firstName'] as String, json['lastName'] as String, |
| | | _$enumDecodeNullable(_$CategoryEnumMap, json[r'$house']), |
| | | middleName: json['middleName'] as String, |
| | | dateOfBirth: json['dateOfBirth'] == null |
| | | ? null |
| | | : DateTime.parse(json['dateOfBirth'] as String)) |
| | | ..order = json['order'] == null |
| | | ? null |
| | | : Order.fromJson(json['order'] as Map<String, dynamic>) |
| | | ..houseMap = (json['houseMap'] as Map<String, dynamic>) |
| | | ?.map((k, e) => MapEntry(k, _$enumDecodeNullable(_$CategoryEnumMap, e))) |
| | | ..categoryCounts = (json['categoryCounts'] as Map<String, dynamic>)?.map( |
| | | (k, e) => |
| | | MapEntry(_$enumDecodeNullable(_$CategoryEnumMap, k), e as int)); |
| | | } |
| | | |
| | | Map<String, dynamic> _$PersonToJson(Person instance) => <String, dynamic>{ |
| | | 'firstName': instance.firstName, |
| | | 'middleName': instance.middleName, |
| | | 'lastName': instance.lastName, |
| | | 'dateOfBirth': instance.dateOfBirth?.toIso8601String(), |
| | | r'$house': _$CategoryEnumMap[instance.house], |
| | | 'order': instance.order, |
| | | 'houseMap': |
| | | instance.houseMap?.map((k, e) => MapEntry(k, _$CategoryEnumMap[e])), |
| | | 'categoryCounts': instance.categoryCounts |
| | | ?.map((k, e) => MapEntry(_$CategoryEnumMap[k], e)) |
| | | }; |
| | | |
| | | T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | throw ArgumentError('A value must be provided. Supported values: ' |
| | | '${enumValues.values.join(', ')}'); |
| | | } |
| | | return enumValues.entries |
| | | .singleWhere((e) => e.value == source, |
| | | orElse: () => throw ArgumentError( |
| | | '`$source` is not one of the supported values: ' |
| | | '${enumValues.values.join(', ')}')) |
| | | .key; |
| | | } |
| | | |
| | | T _$enumDecodeNullable<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | return null; |
| | | } |
| | | return _$enumDecode<T>(enumValues, source); |
| | | } |
| | | |
| | | const _$CategoryEnumMap = <Category, dynamic>{ |
| | | Category.top: 'top', |
| | | Category.bottom: 'bottom', |
| | | Category.strange: 'strange', |
| | | Category.charmed: 'charmed', |
| | | Category.up: 'up', |
| | | Category.down: 'down', |
| | | Category.notDiscoveredYet: 'not_discovered_yet' |
| | | }; |
| | | |
| | | Order _$OrderFromJson(Map<String, dynamic> json) { |
| | | $checkKeys(json, disallowNullValues: const ['count']); |
| | | return Order( |
| | | _$enumDecode(_$CategoryEnumMap, json['category']), |
| | | (json['items'] as List)?.map( |
| | | (e) => e == null ? null : Item.fromJson(e as Map<String, dynamic>))) |
| | | ..count = json['count'] as int |
| | | ..isRushed = json['isRushed'] as bool |
| | | ..duration = json['duration'] == null |
| | | ? null |
| | | : Duration(microseconds: json['duration'] as int) |
| | | ..platform = json['platform'] == null |
| | | ? null |
| | | : Platform.fromJson(json['platform'] as String) |
| | | ..altPlatforms = (json['altPlatforms'] as Map<String, dynamic>)?.map( |
| | | (k, e) => |
| | | MapEntry(k, e == null ? null : Platform.fromJson(e as String))) |
| | | ..homepage = |
| | | json['homepage'] == null ? null : Uri.parse(json['homepage'] as String) |
| | | ..statusCode = |
| | | _$enumDecodeNullable(_$StatusCodeEnumMap, json['status_code']) ?? |
| | | StatusCode.success; |
| | | } |
| | | |
| | | Map<String, dynamic> _$OrderToJson(Order instance) { |
| | | final val = <String, dynamic>{}; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('count', instance.count); |
| | | val['isRushed'] = instance.isRushed; |
| | | val['duration'] = instance.duration?.inMicroseconds; |
| | | val['category'] = _$CategoryEnumMap[instance.category]; |
| | | val['items'] = instance.items; |
| | | val['platform'] = instance.platform; |
| | | val['altPlatforms'] = instance.altPlatforms; |
| | | val['homepage'] = instance.homepage?.toString(); |
| | | val['status_code'] = _$StatusCodeEnumMap[instance.statusCode]; |
| | | return val; |
| | | } |
| | | |
| | | const _$StatusCodeEnumMap = <StatusCode, dynamic>{ |
| | | StatusCode.success: 200, |
| | | StatusCode.notFound: 404 |
| | | }; |
| | | |
| | | Item _$ItemFromJson(Map<String, dynamic> json) { |
| | | return Item(json['price'] as int) |
| | | ..itemNumber = json['item-number'] as int |
| | | ..saleDates = (json['saleDates'] as List) |
| | | ?.map((e) => e == null ? null : DateTime.parse(e as String)) |
| | | ?.toList() |
| | | ..rates = (json['rates'] as List)?.map((e) => e as int)?.toList(); |
| | | } |
| | | |
| | | Map<String, dynamic> _$ItemToJson(Item instance) { |
| | | final val = <String, dynamic>{ |
| | | 'price': instance.price, |
| | | }; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('item-number', instance.itemNumber); |
| | | val['saleDates'] = |
| | | instance.saleDates?.map((e) => e?.toIso8601String())?.toList(); |
| | | val['rates'] = instance.rates; |
| | | return val; |
| | | } |
| | | |
| | | Numbers _$NumbersFromJson(Map<String, dynamic> json) { |
| | | return Numbers() |
| | | ..ints = (json['ints'] as List)?.map((e) => e as int)?.toList() |
| | | ..nums = (json['nums'] as List)?.map((e) => e as num)?.toList() |
| | | ..doubles = |
| | | (json['doubles'] as List)?.map((e) => (e as num)?.toDouble())?.toList() |
| | | ..nnDoubles = |
| | | (json['nnDoubles'] as List).map((e) => (e as num).toDouble()).toList() |
| | | ..duration = json['duration'] == null |
| | | ? null |
| | | : durationFromInt(json['duration'] as int) |
| | | ..date = |
| | | json['date'] == null ? null : dateTimeFromEpochUs(json['date'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$NumbersToJson(Numbers instance) => <String, dynamic>{ |
| | | 'ints': instance.ints, |
| | | 'nums': instance.nums, |
| | | 'doubles': instance.doubles, |
| | | 'nnDoubles': instance.nnDoubles, |
| | | 'duration': |
| | | instance.duration == null ? null : durationToInt(instance.duration), |
| | | 'date': instance.date == null ? null : dateTimeToEpochUs(instance.date) |
| | | }; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _NonNullableGenerator |
| | | // ************************************************************************** |
| | | |
| | | // ignore_for_file: hash_and_equals |
| | | import 'dart:collection'; |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'json_test_common.dart'; |
| | | |
| | | part 'json_test_example.non_nullable.g.dart'; |
| | | |
| | | @JsonSerializable( |
| | | nullable: false, |
| | | ) |
| | | class Person { |
| | | final String firstName, middleName, lastName; |
| | | final DateTime dateOfBirth; |
| | | @JsonKey(name: '\$house') |
| | | final Category house; |
| | | |
| | | Order order; |
| | | |
| | | Map<String, Category> houseMap; |
| | | Map<Category, int> categoryCounts; |
| | | |
| | | Person(this.firstName, this.lastName, this.house, |
| | | {this.middleName, this.dateOfBirth}); |
| | | |
| | | factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$PersonToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Person && |
| | | firstName == other.firstName && |
| | | middleName == other.middleName && |
| | | lastName == other.lastName && |
| | | dateOfBirth == other.dateOfBirth && |
| | | house == other.house && |
| | | deepEquals(houseMap, other.houseMap); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | nullable: false, |
| | | ) |
| | | class Order { |
| | | /// Used to test that `disallowNullValues: true` forces `includeIfNull: false` |
| | | @JsonKey(disallowNullValue: true) |
| | | int count; |
| | | bool isRushed; |
| | | |
| | | Duration duration; |
| | | |
| | | @JsonKey(nullable: false) |
| | | final Category category; |
| | | final UnmodifiableListView<Item> items; |
| | | Platform platform; |
| | | Map<String, Platform> altPlatforms; |
| | | |
| | | Uri homepage; |
| | | |
| | | @JsonKey( |
| | | name: 'status_code', defaultValue: StatusCode.success, nullable: true) |
| | | StatusCode statusCode; |
| | | |
| | | @JsonKey(ignore: true) |
| | | String get platformValue => platform?.description; |
| | | |
| | | set platformValue(String value) { |
| | | throw UnimplementedError('not impld'); |
| | | } |
| | | |
| | | // Ignored getter without value set in ctor |
| | | int get price => items.fold(0, (total, item) => item.price + total); |
| | | |
| | | @JsonKey(ignore: true) |
| | | bool shouldBeCached; |
| | | |
| | | Order(this.category, [Iterable<Item> items]) |
| | | : items = UnmodifiableListView<Item>( |
| | | List<Item>.unmodifiable(items ?? const <Item>[])); |
| | | |
| | | factory Order.fromJson(Map<String, dynamic> json) => _$OrderFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$OrderToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Order && |
| | | count == other.count && |
| | | isRushed == other.isRushed && |
| | | deepEquals(items, other.items) && |
| | | deepEquals(altPlatforms, other.altPlatforms); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | nullable: false, |
| | | ) |
| | | class Item extends ItemCore { |
| | | @JsonKey(includeIfNull: false, name: 'item-number') |
| | | int itemNumber; |
| | | List<DateTime> saleDates; |
| | | List<int> rates; |
| | | |
| | | Item([int price]) : super(price); |
| | | |
| | | factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$ItemToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Item && |
| | | price == other.price && |
| | | itemNumber == other.itemNumber && |
| | | deepEquals(saleDates, other.saleDates); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | nullable: false, |
| | | ) |
| | | class Numbers { |
| | | List<int> ints; |
| | | List<num> nums; |
| | | List<double> doubles; |
| | | |
| | | @JsonKey(nullable: false) |
| | | List<double> nnDoubles; |
| | | |
| | | @JsonKey(fromJson: durationFromInt, toJson: durationToInt) |
| | | Duration duration; |
| | | |
| | | @JsonKey(fromJson: dateTimeFromEpochUs, toJson: dateTimeToEpochUs) |
| | | DateTime date; |
| | | |
| | | Numbers(); |
| | | |
| | | factory Numbers.fromJson(Map<String, dynamic> json) => |
| | | _$NumbersFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$NumbersToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Numbers && |
| | | deepEquals(ints, other.ints) && |
| | | deepEquals(nums, other.nums) && |
| | | deepEquals(doubles, other.doubles) && |
| | | deepEquals(nnDoubles, other.nnDoubles) && |
| | | deepEquals(duration, other.duration) && |
| | | deepEquals(date, other.date); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'json_test_example.non_nullable.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | Person _$PersonFromJson(Map<String, dynamic> json) { |
| | | return Person(json['firstName'] as String, json['lastName'] as String, |
| | | _$enumDecode(_$CategoryEnumMap, json[r'$house']), |
| | | middleName: json['middleName'] as String, |
| | | dateOfBirth: DateTime.parse(json['dateOfBirth'] as String)) |
| | | ..order = Order.fromJson(json['order'] as Map<String, dynamic>) |
| | | ..houseMap = (json['houseMap'] as Map<String, dynamic>) |
| | | .map((k, e) => MapEntry(k, _$enumDecode(_$CategoryEnumMap, e))) |
| | | ..categoryCounts = (json['categoryCounts'] as Map<String, dynamic>) |
| | | .map((k, e) => MapEntry(_$enumDecode(_$CategoryEnumMap, k), e as int)); |
| | | } |
| | | |
| | | Map<String, dynamic> _$PersonToJson(Person instance) => <String, dynamic>{ |
| | | 'firstName': instance.firstName, |
| | | 'middleName': instance.middleName, |
| | | 'lastName': instance.lastName, |
| | | 'dateOfBirth': instance.dateOfBirth.toIso8601String(), |
| | | r'$house': _$CategoryEnumMap[instance.house], |
| | | 'order': instance.order, |
| | | 'houseMap': |
| | | instance.houseMap.map((k, e) => MapEntry(k, _$CategoryEnumMap[e])), |
| | | 'categoryCounts': instance.categoryCounts |
| | | .map((k, e) => MapEntry(_$CategoryEnumMap[k], e)) |
| | | }; |
| | | |
| | | T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | throw ArgumentError('A value must be provided. Supported values: ' |
| | | '${enumValues.values.join(', ')}'); |
| | | } |
| | | return enumValues.entries |
| | | .singleWhere((e) => e.value == source, |
| | | orElse: () => throw ArgumentError( |
| | | '`$source` is not one of the supported values: ' |
| | | '${enumValues.values.join(', ')}')) |
| | | .key; |
| | | } |
| | | |
| | | const _$CategoryEnumMap = <Category, dynamic>{ |
| | | Category.top: 'top', |
| | | Category.bottom: 'bottom', |
| | | Category.strange: 'strange', |
| | | Category.charmed: 'charmed', |
| | | Category.up: 'up', |
| | | Category.down: 'down', |
| | | Category.notDiscoveredYet: 'not_discovered_yet' |
| | | }; |
| | | |
| | | Order _$OrderFromJson(Map<String, dynamic> json) { |
| | | $checkKeys(json, disallowNullValues: const ['count']); |
| | | return Order( |
| | | _$enumDecode(_$CategoryEnumMap, json['category']), |
| | | (json['items'] as List) |
| | | .map((e) => Item.fromJson(e as Map<String, dynamic>))) |
| | | ..count = json['count'] as int |
| | | ..isRushed = json['isRushed'] as bool |
| | | ..duration = Duration(microseconds: json['duration'] as int) |
| | | ..platform = Platform.fromJson(json['platform'] as String) |
| | | ..altPlatforms = (json['altPlatforms'] as Map<String, dynamic>) |
| | | .map((k, e) => MapEntry(k, Platform.fromJson(e as String))) |
| | | ..homepage = Uri.parse(json['homepage'] as String) |
| | | ..statusCode = |
| | | _$enumDecodeNullable(_$StatusCodeEnumMap, json['status_code']) ?? |
| | | StatusCode.success; |
| | | } |
| | | |
| | | Map<String, dynamic> _$OrderToJson(Order instance) => <String, dynamic>{ |
| | | 'count': instance.count, |
| | | 'isRushed': instance.isRushed, |
| | | 'duration': instance.duration.inMicroseconds, |
| | | 'category': _$CategoryEnumMap[instance.category], |
| | | 'items': instance.items, |
| | | 'platform': instance.platform, |
| | | 'altPlatforms': instance.altPlatforms, |
| | | 'homepage': instance.homepage.toString(), |
| | | 'status_code': _$StatusCodeEnumMap[instance.statusCode] |
| | | }; |
| | | |
| | | T _$enumDecodeNullable<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | return null; |
| | | } |
| | | return _$enumDecode<T>(enumValues, source); |
| | | } |
| | | |
| | | const _$StatusCodeEnumMap = <StatusCode, dynamic>{ |
| | | StatusCode.success: 200, |
| | | StatusCode.notFound: 404 |
| | | }; |
| | | |
| | | Item _$ItemFromJson(Map<String, dynamic> json) { |
| | | return Item(json['price'] as int) |
| | | ..itemNumber = json['item-number'] as int |
| | | ..saleDates = (json['saleDates'] as List) |
| | | .map((e) => DateTime.parse(e as String)) |
| | | .toList() |
| | | ..rates = (json['rates'] as List).map((e) => e as int).toList(); |
| | | } |
| | | |
| | | Map<String, dynamic> _$ItemToJson(Item instance) => <String, dynamic>{ |
| | | 'price': instance.price, |
| | | 'item-number': instance.itemNumber, |
| | | 'saleDates': instance.saleDates.map((e) => e.toIso8601String()).toList(), |
| | | 'rates': instance.rates |
| | | }; |
| | | |
| | | Numbers _$NumbersFromJson(Map<String, dynamic> json) { |
| | | return Numbers() |
| | | ..ints = (json['ints'] as List).map((e) => e as int).toList() |
| | | ..nums = (json['nums'] as List).map((e) => e as num).toList() |
| | | ..doubles = |
| | | (json['doubles'] as List).map((e) => (e as num).toDouble()).toList() |
| | | ..nnDoubles = |
| | | (json['nnDoubles'] as List).map((e) => (e as num).toDouble()).toList() |
| | | ..duration = durationFromInt(json['duration'] as int) |
| | | ..date = dateTimeFromEpochUs(json['date'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$NumbersToJson(Numbers instance) => <String, dynamic>{ |
| | | 'ints': instance.ints, |
| | | 'nums': instance.nums, |
| | | 'doubles': instance.doubles, |
| | | 'nnDoubles': instance.nnDoubles, |
| | | 'duration': durationToInt(instance.duration), |
| | | 'date': dateTimeToEpochUs(instance.date) |
| | | }; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _WrappedGenerator |
| | | // ************************************************************************** |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _NonNullableGenerator |
| | | // ************************************************************************** |
| | | |
| | | // ignore_for_file: hash_and_equals |
| | | import 'dart:collection'; |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'json_test_common.dart'; |
| | | |
| | | part 'json_test_example.non_nullable.wrapped.g.dart'; |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | nullable: false, |
| | | ) |
| | | class Person { |
| | | final String firstName, middleName, lastName; |
| | | final DateTime dateOfBirth; |
| | | @JsonKey(name: '\$house') |
| | | final Category house; |
| | | |
| | | Order order; |
| | | |
| | | Map<String, Category> houseMap; |
| | | Map<Category, int> categoryCounts; |
| | | |
| | | Person(this.firstName, this.lastName, this.house, |
| | | {this.middleName, this.dateOfBirth}); |
| | | |
| | | factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$PersonToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Person && |
| | | firstName == other.firstName && |
| | | middleName == other.middleName && |
| | | lastName == other.lastName && |
| | | dateOfBirth == other.dateOfBirth && |
| | | house == other.house && |
| | | deepEquals(houseMap, other.houseMap); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | nullable: false, |
| | | ) |
| | | class Order { |
| | | /// Used to test that `disallowNullValues: true` forces `includeIfNull: false` |
| | | @JsonKey(disallowNullValue: true) |
| | | int count; |
| | | bool isRushed; |
| | | |
| | | Duration duration; |
| | | |
| | | @JsonKey(nullable: false) |
| | | final Category category; |
| | | final UnmodifiableListView<Item> items; |
| | | Platform platform; |
| | | Map<String, Platform> altPlatforms; |
| | | |
| | | Uri homepage; |
| | | |
| | | @JsonKey( |
| | | name: 'status_code', defaultValue: StatusCode.success, nullable: true) |
| | | StatusCode statusCode; |
| | | |
| | | @JsonKey(ignore: true) |
| | | String get platformValue => platform?.description; |
| | | |
| | | set platformValue(String value) { |
| | | throw UnimplementedError('not impld'); |
| | | } |
| | | |
| | | // Ignored getter without value set in ctor |
| | | int get price => items.fold(0, (total, item) => item.price + total); |
| | | |
| | | @JsonKey(ignore: true) |
| | | bool shouldBeCached; |
| | | |
| | | Order(this.category, [Iterable<Item> items]) |
| | | : items = UnmodifiableListView<Item>( |
| | | List<Item>.unmodifiable(items ?? const <Item>[])); |
| | | |
| | | factory Order.fromJson(Map<String, dynamic> json) => _$OrderFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$OrderToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Order && |
| | | count == other.count && |
| | | isRushed == other.isRushed && |
| | | deepEquals(items, other.items) && |
| | | deepEquals(altPlatforms, other.altPlatforms); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | nullable: false, |
| | | ) |
| | | class Item extends ItemCore { |
| | | @JsonKey(includeIfNull: false, name: 'item-number') |
| | | int itemNumber; |
| | | List<DateTime> saleDates; |
| | | List<int> rates; |
| | | |
| | | Item([int price]) : super(price); |
| | | |
| | | factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$ItemToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Item && |
| | | price == other.price && |
| | | itemNumber == other.itemNumber && |
| | | deepEquals(saleDates, other.saleDates); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | nullable: false, |
| | | ) |
| | | class Numbers { |
| | | List<int> ints; |
| | | List<num> nums; |
| | | List<double> doubles; |
| | | |
| | | @JsonKey(nullable: false) |
| | | List<double> nnDoubles; |
| | | |
| | | @JsonKey(fromJson: durationFromInt, toJson: durationToInt) |
| | | Duration duration; |
| | | |
| | | @JsonKey(fromJson: dateTimeFromEpochUs, toJson: dateTimeToEpochUs) |
| | | DateTime date; |
| | | |
| | | Numbers(); |
| | | |
| | | factory Numbers.fromJson(Map<String, dynamic> json) => |
| | | _$NumbersFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$NumbersToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Numbers && |
| | | deepEquals(ints, other.ints) && |
| | | deepEquals(nums, other.nums) && |
| | | deepEquals(doubles, other.doubles) && |
| | | deepEquals(nnDoubles, other.nnDoubles) && |
| | | deepEquals(duration, other.duration) && |
| | | deepEquals(date, other.date); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'json_test_example.non_nullable.wrapped.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | Person _$PersonFromJson(Map<String, dynamic> json) { |
| | | return Person(json['firstName'] as String, json['lastName'] as String, |
| | | _$enumDecode(_$CategoryEnumMap, json[r'$house']), |
| | | middleName: json['middleName'] as String, |
| | | dateOfBirth: DateTime.parse(json['dateOfBirth'] as String)) |
| | | ..order = Order.fromJson(json['order'] as Map<String, dynamic>) |
| | | ..houseMap = (json['houseMap'] as Map<String, dynamic>) |
| | | .map((k, e) => MapEntry(k, _$enumDecode(_$CategoryEnumMap, e))) |
| | | ..categoryCounts = (json['categoryCounts'] as Map<String, dynamic>) |
| | | .map((k, e) => MapEntry(_$enumDecode(_$CategoryEnumMap, k), e as int)); |
| | | } |
| | | |
| | | Map<String, dynamic> _$PersonToJson(Person instance) => |
| | | _$PersonJsonMapWrapper(instance); |
| | | |
| | | class _$PersonJsonMapWrapper extends $JsonMapWrapper { |
| | | final Person _v; |
| | | _$PersonJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const [ |
| | | 'firstName', |
| | | 'middleName', |
| | | 'lastName', |
| | | 'dateOfBirth', |
| | | r'$house', |
| | | 'order', |
| | | 'houseMap', |
| | | 'categoryCounts' |
| | | ]; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'firstName': |
| | | return _v.firstName; |
| | | case 'middleName': |
| | | return _v.middleName; |
| | | case 'lastName': |
| | | return _v.lastName; |
| | | case 'dateOfBirth': |
| | | return _v.dateOfBirth.toIso8601String(); |
| | | case r'$house': |
| | | return _$CategoryEnumMap[_v.house]; |
| | | case 'order': |
| | | return _v.order; |
| | | case 'houseMap': |
| | | return $wrapMap<String, Category>( |
| | | _v.houseMap, (e) => _$CategoryEnumMap[e]); |
| | | case 'categoryCounts': |
| | | return $wrapMap<Category, int>(_v.categoryCounts, (e) => e); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | throw ArgumentError('A value must be provided. Supported values: ' |
| | | '${enumValues.values.join(', ')}'); |
| | | } |
| | | return enumValues.entries |
| | | .singleWhere((e) => e.value == source, |
| | | orElse: () => throw ArgumentError( |
| | | '`$source` is not one of the supported values: ' |
| | | '${enumValues.values.join(', ')}')) |
| | | .key; |
| | | } |
| | | |
| | | const _$CategoryEnumMap = <Category, dynamic>{ |
| | | Category.top: 'top', |
| | | Category.bottom: 'bottom', |
| | | Category.strange: 'strange', |
| | | Category.charmed: 'charmed', |
| | | Category.up: 'up', |
| | | Category.down: 'down', |
| | | Category.notDiscoveredYet: 'not_discovered_yet' |
| | | }; |
| | | |
| | | Order _$OrderFromJson(Map<String, dynamic> json) { |
| | | $checkKeys(json, disallowNullValues: const ['count']); |
| | | return Order( |
| | | _$enumDecode(_$CategoryEnumMap, json['category']), |
| | | (json['items'] as List) |
| | | .map((e) => Item.fromJson(e as Map<String, dynamic>))) |
| | | ..count = json['count'] as int |
| | | ..isRushed = json['isRushed'] as bool |
| | | ..duration = Duration(microseconds: json['duration'] as int) |
| | | ..platform = Platform.fromJson(json['platform'] as String) |
| | | ..altPlatforms = (json['altPlatforms'] as Map<String, dynamic>) |
| | | .map((k, e) => MapEntry(k, Platform.fromJson(e as String))) |
| | | ..homepage = Uri.parse(json['homepage'] as String) |
| | | ..statusCode = |
| | | _$enumDecodeNullable(_$StatusCodeEnumMap, json['status_code']) ?? |
| | | StatusCode.success; |
| | | } |
| | | |
| | | Map<String, dynamic> _$OrderToJson(Order instance) => |
| | | _$OrderJsonMapWrapper(instance); |
| | | |
| | | class _$OrderJsonMapWrapper extends $JsonMapWrapper { |
| | | final Order _v; |
| | | _$OrderJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const [ |
| | | 'count', |
| | | 'isRushed', |
| | | 'duration', |
| | | 'category', |
| | | 'items', |
| | | 'platform', |
| | | 'altPlatforms', |
| | | 'homepage', |
| | | 'status_code' |
| | | ]; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'count': |
| | | return _v.count; |
| | | case 'isRushed': |
| | | return _v.isRushed; |
| | | case 'duration': |
| | | return _v.duration.inMicroseconds; |
| | | case 'category': |
| | | return _$CategoryEnumMap[_v.category]; |
| | | case 'items': |
| | | return _v.items; |
| | | case 'platform': |
| | | return _v.platform; |
| | | case 'altPlatforms': |
| | | return _v.altPlatforms; |
| | | case 'homepage': |
| | | return _v.homepage.toString(); |
| | | case 'status_code': |
| | | return _$StatusCodeEnumMap[_v.statusCode]; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | T _$enumDecodeNullable<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | return null; |
| | | } |
| | | return _$enumDecode<T>(enumValues, source); |
| | | } |
| | | |
| | | const _$StatusCodeEnumMap = <StatusCode, dynamic>{ |
| | | StatusCode.success: 200, |
| | | StatusCode.notFound: 404 |
| | | }; |
| | | |
| | | Item _$ItemFromJson(Map<String, dynamic> json) { |
| | | return Item(json['price'] as int) |
| | | ..itemNumber = json['item-number'] as int |
| | | ..saleDates = (json['saleDates'] as List) |
| | | .map((e) => DateTime.parse(e as String)) |
| | | .toList() |
| | | ..rates = (json['rates'] as List).map((e) => e as int).toList(); |
| | | } |
| | | |
| | | Map<String, dynamic> _$ItemToJson(Item instance) => |
| | | _$ItemJsonMapWrapper(instance); |
| | | |
| | | class _$ItemJsonMapWrapper extends $JsonMapWrapper { |
| | | final Item _v; |
| | | _$ItemJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => |
| | | const ['price', 'item-number', 'saleDates', 'rates']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'price': |
| | | return _v.price; |
| | | case 'item-number': |
| | | return _v.itemNumber; |
| | | case 'saleDates': |
| | | return $wrapList<DateTime>(_v.saleDates, (e) => e.toIso8601String()); |
| | | case 'rates': |
| | | return _v.rates; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | Numbers _$NumbersFromJson(Map<String, dynamic> json) { |
| | | return Numbers() |
| | | ..ints = (json['ints'] as List).map((e) => e as int).toList() |
| | | ..nums = (json['nums'] as List).map((e) => e as num).toList() |
| | | ..doubles = |
| | | (json['doubles'] as List).map((e) => (e as num).toDouble()).toList() |
| | | ..nnDoubles = |
| | | (json['nnDoubles'] as List).map((e) => (e as num).toDouble()).toList() |
| | | ..duration = durationFromInt(json['duration'] as int) |
| | | ..date = dateTimeFromEpochUs(json['date'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$NumbersToJson(Numbers instance) => |
| | | _$NumbersJsonMapWrapper(instance); |
| | | |
| | | class _$NumbersJsonMapWrapper extends $JsonMapWrapper { |
| | | final Numbers _v; |
| | | _$NumbersJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => |
| | | const ['ints', 'nums', 'doubles', 'nnDoubles', 'duration', 'date']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'ints': |
| | | return _v.ints; |
| | | case 'nums': |
| | | return _v.nums; |
| | | case 'doubles': |
| | | return _v.doubles; |
| | | case 'nnDoubles': |
| | | return _v.nnDoubles; |
| | | case 'duration': |
| | | return durationToInt(_v.duration); |
| | | case 'date': |
| | | return dateTimeToEpochUs(_v.date); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _WrappedGenerator |
| | | // ************************************************************************** |
| | | |
| | | // ignore_for_file: hash_and_equals |
| | | import 'dart:collection'; |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'json_test_common.dart'; |
| | | |
| | | part 'json_test_example.wrapped.g.dart'; |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | ) |
| | | class Person { |
| | | final String firstName, middleName, lastName; |
| | | final DateTime dateOfBirth; |
| | | @JsonKey(name: '\$house') |
| | | final Category house; |
| | | |
| | | Order order; |
| | | |
| | | Map<String, Category> houseMap; |
| | | Map<Category, int> categoryCounts; |
| | | |
| | | Person(this.firstName, this.lastName, this.house, |
| | | {this.middleName, this.dateOfBirth}); |
| | | |
| | | factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$PersonToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Person && |
| | | firstName == other.firstName && |
| | | middleName == other.middleName && |
| | | lastName == other.lastName && |
| | | dateOfBirth == other.dateOfBirth && |
| | | house == other.house && |
| | | deepEquals(houseMap, other.houseMap); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | ) |
| | | class Order { |
| | | /// Used to test that `disallowNullValues: true` forces `includeIfNull: false` |
| | | @JsonKey(disallowNullValue: true) |
| | | int count; |
| | | bool isRushed; |
| | | |
| | | Duration duration; |
| | | |
| | | @JsonKey(nullable: false) |
| | | final Category category; |
| | | final UnmodifiableListView<Item> items; |
| | | Platform platform; |
| | | Map<String, Platform> altPlatforms; |
| | | |
| | | Uri homepage; |
| | | |
| | | @JsonKey( |
| | | name: 'status_code', defaultValue: StatusCode.success, nullable: true) |
| | | StatusCode statusCode; |
| | | |
| | | @JsonKey(ignore: true) |
| | | String get platformValue => platform?.description; |
| | | |
| | | set platformValue(String value) { |
| | | throw UnimplementedError('not impld'); |
| | | } |
| | | |
| | | // Ignored getter without value set in ctor |
| | | int get price => items.fold(0, (total, item) => item.price + total); |
| | | |
| | | @JsonKey(ignore: true) |
| | | bool shouldBeCached; |
| | | |
| | | Order(this.category, [Iterable<Item> items]) |
| | | : items = UnmodifiableListView<Item>( |
| | | List<Item>.unmodifiable(items ?? const <Item>[])); |
| | | |
| | | factory Order.fromJson(Map<String, dynamic> json) => _$OrderFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$OrderToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Order && |
| | | count == other.count && |
| | | isRushed == other.isRushed && |
| | | deepEquals(items, other.items) && |
| | | deepEquals(altPlatforms, other.altPlatforms); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | ) |
| | | class Item extends ItemCore { |
| | | @JsonKey(includeIfNull: false, name: 'item-number') |
| | | int itemNumber; |
| | | List<DateTime> saleDates; |
| | | List<int> rates; |
| | | |
| | | Item([int price]) : super(price); |
| | | |
| | | factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$ItemToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Item && |
| | | price == other.price && |
| | | itemNumber == other.itemNumber && |
| | | deepEquals(saleDates, other.saleDates); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | ) |
| | | class Numbers { |
| | | List<int> ints; |
| | | List<num> nums; |
| | | List<double> doubles; |
| | | |
| | | @JsonKey(nullable: false) |
| | | List<double> nnDoubles; |
| | | |
| | | @JsonKey(fromJson: durationFromInt, toJson: durationToInt) |
| | | Duration duration; |
| | | |
| | | @JsonKey(fromJson: dateTimeFromEpochUs, toJson: dateTimeToEpochUs) |
| | | DateTime date; |
| | | |
| | | Numbers(); |
| | | |
| | | factory Numbers.fromJson(Map<String, dynamic> json) => |
| | | _$NumbersFromJson(json); |
| | | |
| | | Map<String, dynamic> toJson() => _$NumbersToJson(this); |
| | | |
| | | @override |
| | | bool operator ==(Object other) => |
| | | other is Numbers && |
| | | deepEquals(ints, other.ints) && |
| | | deepEquals(nums, other.nums) && |
| | | deepEquals(doubles, other.doubles) && |
| | | deepEquals(nnDoubles, other.nnDoubles) && |
| | | deepEquals(duration, other.duration) && |
| | | deepEquals(date, other.date); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'json_test_example.wrapped.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | Person _$PersonFromJson(Map<String, dynamic> json) { |
| | | return Person(json['firstName'] as String, json['lastName'] as String, |
| | | _$enumDecodeNullable(_$CategoryEnumMap, json[r'$house']), |
| | | middleName: json['middleName'] as String, |
| | | dateOfBirth: json['dateOfBirth'] == null |
| | | ? null |
| | | : DateTime.parse(json['dateOfBirth'] as String)) |
| | | ..order = json['order'] == null |
| | | ? null |
| | | : Order.fromJson(json['order'] as Map<String, dynamic>) |
| | | ..houseMap = (json['houseMap'] as Map<String, dynamic>) |
| | | ?.map((k, e) => MapEntry(k, _$enumDecodeNullable(_$CategoryEnumMap, e))) |
| | | ..categoryCounts = (json['categoryCounts'] as Map<String, dynamic>)?.map( |
| | | (k, e) => |
| | | MapEntry(_$enumDecodeNullable(_$CategoryEnumMap, k), e as int)); |
| | | } |
| | | |
| | | Map<String, dynamic> _$PersonToJson(Person instance) => |
| | | _$PersonJsonMapWrapper(instance); |
| | | |
| | | class _$PersonJsonMapWrapper extends $JsonMapWrapper { |
| | | final Person _v; |
| | | _$PersonJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const [ |
| | | 'firstName', |
| | | 'middleName', |
| | | 'lastName', |
| | | 'dateOfBirth', |
| | | r'$house', |
| | | 'order', |
| | | 'houseMap', |
| | | 'categoryCounts' |
| | | ]; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'firstName': |
| | | return _v.firstName; |
| | | case 'middleName': |
| | | return _v.middleName; |
| | | case 'lastName': |
| | | return _v.lastName; |
| | | case 'dateOfBirth': |
| | | return _v.dateOfBirth?.toIso8601String(); |
| | | case r'$house': |
| | | return _$CategoryEnumMap[_v.house]; |
| | | case 'order': |
| | | return _v.order; |
| | | case 'houseMap': |
| | | return $wrapMapHandleNull<String, Category>( |
| | | _v.houseMap, (e) => _$CategoryEnumMap[e]); |
| | | case 'categoryCounts': |
| | | return $wrapMapHandleNull<Category, int>(_v.categoryCounts, (e) => e); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | throw ArgumentError('A value must be provided. Supported values: ' |
| | | '${enumValues.values.join(', ')}'); |
| | | } |
| | | return enumValues.entries |
| | | .singleWhere((e) => e.value == source, |
| | | orElse: () => throw ArgumentError( |
| | | '`$source` is not one of the supported values: ' |
| | | '${enumValues.values.join(', ')}')) |
| | | .key; |
| | | } |
| | | |
| | | T _$enumDecodeNullable<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | return null; |
| | | } |
| | | return _$enumDecode<T>(enumValues, source); |
| | | } |
| | | |
| | | const _$CategoryEnumMap = <Category, dynamic>{ |
| | | Category.top: 'top', |
| | | Category.bottom: 'bottom', |
| | | Category.strange: 'strange', |
| | | Category.charmed: 'charmed', |
| | | Category.up: 'up', |
| | | Category.down: 'down', |
| | | Category.notDiscoveredYet: 'not_discovered_yet' |
| | | }; |
| | | |
| | | Order _$OrderFromJson(Map<String, dynamic> json) { |
| | | $checkKeys(json, disallowNullValues: const ['count']); |
| | | return Order( |
| | | _$enumDecode(_$CategoryEnumMap, json['category']), |
| | | (json['items'] as List)?.map( |
| | | (e) => e == null ? null : Item.fromJson(e as Map<String, dynamic>))) |
| | | ..count = json['count'] as int |
| | | ..isRushed = json['isRushed'] as bool |
| | | ..duration = json['duration'] == null |
| | | ? null |
| | | : Duration(microseconds: json['duration'] as int) |
| | | ..platform = json['platform'] == null |
| | | ? null |
| | | : Platform.fromJson(json['platform'] as String) |
| | | ..altPlatforms = (json['altPlatforms'] as Map<String, dynamic>)?.map( |
| | | (k, e) => |
| | | MapEntry(k, e == null ? null : Platform.fromJson(e as String))) |
| | | ..homepage = |
| | | json['homepage'] == null ? null : Uri.parse(json['homepage'] as String) |
| | | ..statusCode = |
| | | _$enumDecodeNullable(_$StatusCodeEnumMap, json['status_code']) ?? |
| | | StatusCode.success; |
| | | } |
| | | |
| | | Map<String, dynamic> _$OrderToJson(Order instance) => |
| | | _$OrderJsonMapWrapper(instance); |
| | | |
| | | class _$OrderJsonMapWrapper extends $JsonMapWrapper { |
| | | final Order _v; |
| | | _$OrderJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys sync* { |
| | | if (_v.count != null) { |
| | | yield 'count'; |
| | | } |
| | | yield 'isRushed'; |
| | | yield 'duration'; |
| | | yield 'category'; |
| | | yield 'items'; |
| | | yield 'platform'; |
| | | yield 'altPlatforms'; |
| | | yield 'homepage'; |
| | | yield 'status_code'; |
| | | } |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'count': |
| | | return _v.count; |
| | | case 'isRushed': |
| | | return _v.isRushed; |
| | | case 'duration': |
| | | return _v.duration?.inMicroseconds; |
| | | case 'category': |
| | | return _$CategoryEnumMap[_v.category]; |
| | | case 'items': |
| | | return _v.items; |
| | | case 'platform': |
| | | return _v.platform; |
| | | case 'altPlatforms': |
| | | return _v.altPlatforms; |
| | | case 'homepage': |
| | | return _v.homepage?.toString(); |
| | | case 'status_code': |
| | | return _$StatusCodeEnumMap[_v.statusCode]; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | const _$StatusCodeEnumMap = <StatusCode, dynamic>{ |
| | | StatusCode.success: 200, |
| | | StatusCode.notFound: 404 |
| | | }; |
| | | |
| | | Item _$ItemFromJson(Map<String, dynamic> json) { |
| | | return Item(json['price'] as int) |
| | | ..itemNumber = json['item-number'] as int |
| | | ..saleDates = (json['saleDates'] as List) |
| | | ?.map((e) => e == null ? null : DateTime.parse(e as String)) |
| | | ?.toList() |
| | | ..rates = (json['rates'] as List)?.map((e) => e as int)?.toList(); |
| | | } |
| | | |
| | | Map<String, dynamic> _$ItemToJson(Item instance) => |
| | | _$ItemJsonMapWrapper(instance); |
| | | |
| | | class _$ItemJsonMapWrapper extends $JsonMapWrapper { |
| | | final Item _v; |
| | | _$ItemJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys sync* { |
| | | yield 'price'; |
| | | if (_v.itemNumber != null) { |
| | | yield 'item-number'; |
| | | } |
| | | yield 'saleDates'; |
| | | yield 'rates'; |
| | | } |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'price': |
| | | return _v.price; |
| | | case 'item-number': |
| | | return _v.itemNumber; |
| | | case 'saleDates': |
| | | return $wrapListHandleNull<DateTime>( |
| | | _v.saleDates, (e) => e?.toIso8601String()); |
| | | case 'rates': |
| | | return _v.rates; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | Numbers _$NumbersFromJson(Map<String, dynamic> json) { |
| | | return Numbers() |
| | | ..ints = (json['ints'] as List)?.map((e) => e as int)?.toList() |
| | | ..nums = (json['nums'] as List)?.map((e) => e as num)?.toList() |
| | | ..doubles = |
| | | (json['doubles'] as List)?.map((e) => (e as num)?.toDouble())?.toList() |
| | | ..nnDoubles = |
| | | (json['nnDoubles'] as List).map((e) => (e as num).toDouble()).toList() |
| | | ..duration = json['duration'] == null |
| | | ? null |
| | | : durationFromInt(json['duration'] as int) |
| | | ..date = |
| | | json['date'] == null ? null : dateTimeFromEpochUs(json['date'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$NumbersToJson(Numbers instance) => |
| | | _$NumbersJsonMapWrapper(instance); |
| | | |
| | | class _$NumbersJsonMapWrapper extends $JsonMapWrapper { |
| | | final Numbers _v; |
| | | _$NumbersJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => |
| | | const ['ints', 'nums', 'doubles', 'nnDoubles', 'duration', 'date']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'ints': |
| | | return _v.ints; |
| | | case 'nums': |
| | | return _v.nums; |
| | | case 'doubles': |
| | | return _v.doubles; |
| | | case 'nnDoubles': |
| | | return _v.nnDoubles; |
| | | case 'duration': |
| | | return _v.duration == null ? null : durationToInt(_v.duration); |
| | | case 'date': |
| | | return _v.date == null ? null : dateTimeToEpochUs(_v.date); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | @TestOn('vm') |
| | | import 'dart:async'; |
| | | |
| | | import 'package:analyzer/dart/element/type.dart'; |
| | | import 'package:build/build.dart'; |
| | | import 'package:dart_style/dart_style.dart' as dart_style; |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:json_serializable/json_serializable.dart'; |
| | | import 'package:json_serializable/src/constants.dart'; |
| | | import 'package:json_serializable/src/type_helper.dart'; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | import 'package:test/test.dart'; |
| | | |
| | | import 'analysis_utils.dart'; |
| | | import 'shared_config.dart'; |
| | | import 'test_file_utils.dart'; |
| | | |
| | | Matcher _matcherFromShouldGenerateAnnotation(ConstantReader reader, |
| | | {bool wrapped = false}) { |
| | | String expectedOutput; |
| | | if (wrapped) { |
| | | final expectedWrappedOutput = reader.read('expectedWrappedOutput'); |
| | | if (expectedWrappedOutput.isNull) { |
| | | return null; |
| | | } |
| | | expectedOutput = expectedWrappedOutput.stringValue; |
| | | } else { |
| | | expectedOutput = reader.read('expectedOutput').stringValue; |
| | | } |
| | | |
| | | final isContains = reader.read('contains').boolValue; |
| | | |
| | | if (isContains) { |
| | | return contains(expectedOutput); |
| | | } |
| | | return equals(expectedOutput); |
| | | } |
| | | |
| | | Matcher _throwsInvalidGenerationSourceError(messageMatcher, todoMatcher) => |
| | | throwsA(const TypeMatcher<InvalidGenerationSourceError>() |
| | | .having((e) => e.message, 'message', messageMatcher) |
| | | .having((e) => e.todo, 'todo', todoMatcher) |
| | | .having((e) => e.element, 'element', isNotNull)); |
| | | |
| | | Matcher _throwsUnsupportedError(matcher) => |
| | | throwsA(const TypeMatcher<UnsupportedError>() |
| | | .having((e) => e.message, 'message', matcher)); |
| | | |
| | | final _formatter = dart_style.DartFormatter(); |
| | | |
| | | LibraryReader _library; |
| | | |
| | | final _buildLogItems = <String>[]; |
| | | |
| | | const _expectedAnnotatedTests = { |
| | | '_json_serializable_test_input.dart': [ |
| | | 'theAnswer', |
| | | 'annotatedMethod', |
| | | 'Person', |
| | | 'Order', |
| | | 'FinalFields', |
| | | 'FinalFieldsNotSetInCtor', |
| | | 'SetSupport', |
| | | 'IncludeIfNullOverride', |
| | | 'KeyDupesField', |
| | | 'DupeKeys', |
| | | 'IgnoredFieldClass', |
| | | 'IgnoredFieldCtorClass', |
| | | 'PrivateFieldCtorClass', |
| | | 'IncludeIfNullDisallowNullClass', |
| | | 'JsonValueWithBool', |
| | | 'JsonValueValid' |
| | | ], |
| | | 'checked_test_input.dart': [ |
| | | 'WithANonCtorGetterChecked', |
| | | 'WithANonCtorGetter' |
| | | ], |
| | | 'default_value_input.dart': [ |
| | | 'DefaultWithSymbol', |
| | | 'DefaultWithFunction', |
| | | 'DefaultWithType', |
| | | 'DefaultWithConstObject', |
| | | 'DefaultWithNestedEnum', |
| | | 'DefaultWithNonNullableField', |
| | | 'DefaultWithNonNullableClass' |
| | | ], |
| | | 'field_namer_input.dart': [ |
| | | 'FieldNamerNone', |
| | | 'FieldNamerKebab', |
| | | 'FieldNamerSnake' |
| | | ], |
| | | 'generic_test_input.dart': ['GenericClass'], |
| | | 'inheritance_test_input.dart': [ |
| | | 'SubType', |
| | | 'SubTypeWithAnnotatedFieldOverrideExtends', |
| | | 'SubTypeWithAnnotatedFieldOverrideExtendsWithOverrides', |
| | | 'SubTypeWithAnnotatedFieldOverrideImplements' |
| | | ], |
| | | 'json_converter_test_input.dart': [ |
| | | 'JsonConverterNamedCtor', |
| | | 'JsonConvertOnField', |
| | | 'JsonConverterWithBadTypeArg', |
| | | 'JsonConverterDuplicateAnnotations', |
| | | 'JsonConverterCtorParams', |
| | | ], |
| | | 'setter_test_input.dart': [ |
| | | 'JustSetter', |
| | | 'JustSetterNoToJson', |
| | | 'JustSetterNoFromJson' |
| | | ], |
| | | 'to_from_json_test_input.dart': [ |
| | | 'BadFromFuncReturnType', |
| | | 'InvalidFromFunc2Args', |
| | | 'ValidToFromFuncClassStatic', |
| | | 'BadToFuncReturnType', |
| | | 'InvalidToFunc2Args', |
| | | 'ObjectConvertMethods', |
| | | 'DynamicConvertMethods', |
| | | 'TypedConvertMethods', |
| | | 'FromDynamicCollection', |
| | | 'BadNoArgs', |
| | | 'BadTwoRequiredPositional', |
| | | 'BadOneNamed', |
| | | 'OkayOneNormalOptionalPositional', |
| | | 'OkayOneNormalOptionalNamed', |
| | | 'OkayOnlyOptionalPositional' |
| | | ], |
| | | }; |
| | | |
| | | void main() async { |
| | | final path = testFilePath('test', 'src'); |
| | | _library = await resolveCompilationUnit(path); |
| | | |
| | | StreamSubscription logSubscription; |
| | | |
| | | setUp(() { |
| | | assert(_buildLogItems.isEmpty); |
| | | assert(logSubscription == null); |
| | | logSubscription = log.onRecord.listen((r) => _buildLogItems.add(r.message)); |
| | | }); |
| | | |
| | | tearDown(() async { |
| | | if (logSubscription != null) { |
| | | await logSubscription.cancel(); |
| | | logSubscription = null; |
| | | } |
| | | |
| | | final remainingItems = _buildLogItems.toList(); |
| | | _buildLogItems.clear(); |
| | | expect(remainingItems, isEmpty, |
| | | reason: |
| | | 'Tests should validate entries and clear this before `tearDown`.'); |
| | | _buildLogItems.clear(); |
| | | }); |
| | | |
| | | // Only need to run this check once! |
| | | test('[all expected files]', () { |
| | | expect(_annotatedElements.keys, _expectedAnnotatedTests.keys); |
| | | }); |
| | | |
| | | for (final entry in _annotatedElements.entries) { |
| | | group(entry.key, () { |
| | | test('[all expected classes]', () { |
| | | expect(_expectedAnnotatedTests, |
| | | containsPair(entry.key, entry.value.map((ae) => ae.element.name))); |
| | | }); |
| | | |
| | | for (final annotatedElement in entry.value) { |
| | | _testAnnotatedClass(annotatedElement); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | group('without wrappers', () { |
| | | _registerTests(JsonSerializable.defaults); |
| | | }); |
| | | group( |
| | | 'with wrapper', |
| | | () => _registerTests( |
| | | const JsonSerializable(useWrappers: true).withDefaults())); |
| | | |
| | | group('configuration', () { |
| | | void runWithConfigAndLogger(JsonSerializable config, String className) { |
| | | _runForElementNamedWithGenerator( |
| | | JsonSerializableGenerator( |
| | | config: config, typeHelpers: const [_ConfigLogger()]), |
| | | className); |
| | | } |
| | | |
| | | setUp(_ConfigLogger.configurations.clear); |
| | | |
| | | group('defaults', () { |
| | | for (var className in [ |
| | | 'ConfigurationImplicitDefaults', |
| | | 'ConfigurationExplicitDefaults', |
| | | ]) { |
| | | for (var nullConfig in [true, false]) { |
| | | final testDescription = |
| | | '$className with ${nullConfig ? 'null' : 'default'} config'; |
| | | |
| | | test(testDescription, () { |
| | | runWithConfigAndLogger( |
| | | nullConfig ? null : const JsonSerializable(), className); |
| | | |
| | | expect(_ConfigLogger.configurations, hasLength(2)); |
| | | expect(_ConfigLogger.configurations.first, |
| | | same(_ConfigLogger.configurations.last)); |
| | | expect(_ConfigLogger.configurations.first.toJson(), |
| | | generatorConfigDefaultJson); |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | test( |
| | | 'values in config override unconfigured (default) values in annotation', |
| | | () { |
| | | runWithConfigAndLogger( |
| | | JsonSerializable.fromJson(generatorConfigNonDefaultJson), |
| | | 'ConfigurationImplicitDefaults'); |
| | | |
| | | expect(_ConfigLogger.configurations, isEmpty, |
| | | reason: 'all generation is disabled'); |
| | | |
| | | // Create a configuration with just `create_to_json` set to true so we |
| | | // can validate the configuration that is run with |
| | | final configMap = |
| | | Map<String, dynamic>.from(generatorConfigNonDefaultJson); |
| | | configMap['create_to_json'] = true; |
| | | |
| | | runWithConfigAndLogger(JsonSerializable.fromJson(configMap), |
| | | 'ConfigurationImplicitDefaults'); |
| | | }); |
| | | |
| | | test( |
| | | 'explicit values in annotation override corresponding settings in config', |
| | | () { |
| | | runWithConfigAndLogger( |
| | | JsonSerializable.fromJson(generatorConfigNonDefaultJson), |
| | | 'ConfigurationExplicitDefaults'); |
| | | |
| | | expect(_ConfigLogger.configurations, hasLength(2)); |
| | | expect(_ConfigLogger.configurations.first, |
| | | same(_ConfigLogger.configurations.last)); |
| | | |
| | | // The effective configuration should be non-Default configuration, but |
| | | // with all fields set from JsonSerializable as the defaults |
| | | |
| | | final expected = Map.from(generatorConfigNonDefaultJson); |
| | | for (var jsonSerialKey in jsonSerializableFields) { |
| | | expected[jsonSerialKey] = generatorConfigDefaultJson[jsonSerialKey]; |
| | | } |
| | | |
| | | expect(_ConfigLogger.configurations.first.toJson(), expected); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | void _testAnnotatedClass(AnnotatedElement annotatedElement) { |
| | | final annotationName = annotatedElement.annotation.objectValue.type.name; |
| | | switch (annotationName) { |
| | | case 'ShouldThrow': |
| | | _testShouldThrow(annotatedElement); |
| | | break; |
| | | case 'ShouldGenerate': |
| | | _testShouldGenerate(annotatedElement); |
| | | break; |
| | | default: |
| | | throw UnsupportedError("We don't support $annotationName"); |
| | | } |
| | | } |
| | | |
| | | void _testShouldThrow(AnnotatedElement annotatedElement) { |
| | | final element = annotatedElement.element; |
| | | final constReader = annotatedElement.annotation; |
| | | final messageMatcher = constReader.read('errorMessage').stringValue; |
| | | var todoMatcher = constReader.read('todo').literalValue; |
| | | |
| | | test(element.name, () { |
| | | todoMatcher ??= isEmpty; |
| | | |
| | | expect( |
| | | () => _runForElementNamed( |
| | | const JsonSerializable(useWrappers: false), element.name), |
| | | _throwsInvalidGenerationSourceError(messageMatcher, todoMatcher), |
| | | reason: 'Should fail without wrappers.'); |
| | | |
| | | expect( |
| | | () => _runForElementNamed( |
| | | const JsonSerializable(useWrappers: true), element.name), |
| | | _throwsInvalidGenerationSourceError(messageMatcher, todoMatcher), |
| | | reason: 'Should fail with wrappers.'); |
| | | }); |
| | | } |
| | | |
| | | void _testShouldGenerate(AnnotatedElement annotatedElement) { |
| | | final element = annotatedElement.element; |
| | | |
| | | final matcher = |
| | | _matcherFromShouldGenerateAnnotation(annotatedElement.annotation); |
| | | |
| | | final expectedLogItems = annotatedElement.annotation |
| | | .read('expectedLogItems') |
| | | .listValue |
| | | .map((obj) => obj.toStringValue()) |
| | | .toList(); |
| | | |
| | | final checked = annotatedElement.annotation.read('checked').boolValue; |
| | | |
| | | test(element.name, () { |
| | | final output = |
| | | _runForElementNamed(JsonSerializable(checked: checked), element.name); |
| | | expect(output, matcher); |
| | | |
| | | expect(_buildLogItems, expectedLogItems); |
| | | _buildLogItems.clear(); |
| | | }); |
| | | |
| | | final wrappedMatcher = _matcherFromShouldGenerateAnnotation( |
| | | annotatedElement.annotation, |
| | | wrapped: true); |
| | | if (wrappedMatcher != null) { |
| | | test('${element.name} - (wrapped)', () { |
| | | final output = _runForElementNamed( |
| | | JsonSerializable(checked: checked, useWrappers: true), element.name); |
| | | expect(output, wrappedMatcher); |
| | | |
| | | expect(_buildLogItems, expectedLogItems); |
| | | _buildLogItems.clear(); |
| | | }); |
| | | } |
| | | } |
| | | |
| | | String _runForElementNamed(JsonSerializable config, String name) { |
| | | final generator = JsonSerializableGenerator(config: config); |
| | | return _runForElementNamedWithGenerator(generator, name); |
| | | } |
| | | |
| | | String _runForElementNamedWithGenerator( |
| | | JsonSerializableGenerator generator, String name) { |
| | | final element = _library.allElements.singleWhere((e) => e.name == name); |
| | | final annotation = generator.typeChecker.firstAnnotationOf(element); |
| | | final generated = generator |
| | | .generateForAnnotatedElement(element, ConstantReader(annotation), null) |
| | | .map((e) => e.trim()) |
| | | .where((e) => e.isNotEmpty) |
| | | .map((e) => '$e\n\n') |
| | | .join(); |
| | | |
| | | final output = _formatter.format(generated); |
| | | printOnFailure("r'''\n$output'''"); |
| | | return output; |
| | | } |
| | | |
| | | final _annotatedElements = _library.allElements |
| | | .map<AnnotatedElement>((e) { |
| | | for (final md in e.metadata) { |
| | | final reader = ConstantReader(md.constantValue); |
| | | if (const ['ShouldGenerate', 'ShouldThrow'] |
| | | .contains(reader.objectValue.type.name)) { |
| | | return AnnotatedElement(reader, e); |
| | | } |
| | | } |
| | | return null; |
| | | }) |
| | | .where((ae) => ae != null) |
| | | .fold<Map<String, List<AnnotatedElement>>>( |
| | | <String, List<AnnotatedElement>>{}, (map, annotatedElement) { |
| | | final list = map.putIfAbsent( |
| | | annotatedElement.element.source.uri.pathSegments.last, |
| | | () => <AnnotatedElement>[]); |
| | | list.add(annotatedElement); |
| | | return map; |
| | | }); |
| | | |
| | | void _registerTests(JsonSerializable generator) { |
| | | String runForElementNamed(String name) => |
| | | _runForElementNamed(generator, name); |
| | | |
| | | void expectThrows(String elementName, messageMatcher, [todoMatcher]) { |
| | | todoMatcher ??= isEmpty; |
| | | expect(() => runForElementNamed(elementName), |
| | | _throwsInvalidGenerationSourceError(messageMatcher, todoMatcher)); |
| | | } |
| | | |
| | | group('explicit toJson', () { |
| | | test('nullable', () { |
| | | final output = _runForElementNamed( |
| | | JsonSerializable( |
| | | explicitToJson: true, useWrappers: generator.useWrappers), |
| | | 'TrivialNestedNullable'); |
| | | |
| | | final expected = generator.useWrappers |
| | | ? r''' |
| | | Map<String, dynamic> _$TrivialNestedNullableToJson( |
| | | TrivialNestedNullable instance) => |
| | | _$TrivialNestedNullableJsonMapWrapper(instance); |
| | | |
| | | class _$TrivialNestedNullableJsonMapWrapper extends $JsonMapWrapper { |
| | | final TrivialNestedNullable _v; |
| | | _$TrivialNestedNullableJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const ['child', 'otherField']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'child': |
| | | return _v.child?.toJson(); |
| | | case 'otherField': |
| | | return _v.otherField; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | ''' |
| | | : r''' |
| | | Map<String, dynamic> _$TrivialNestedNullableToJson( |
| | | TrivialNestedNullable instance) => |
| | | <String, dynamic>{ |
| | | 'child': instance.child?.toJson(), |
| | | 'otherField': instance.otherField |
| | | }; |
| | | '''; |
| | | |
| | | expect(output, expected); |
| | | }); |
| | | test('non-nullable', () { |
| | | final output = _runForElementNamed( |
| | | JsonSerializable( |
| | | explicitToJson: true, useWrappers: generator.useWrappers), |
| | | 'TrivialNestedNonNullable'); |
| | | |
| | | final expected = generator.useWrappers |
| | | ? r''' |
| | | Map<String, dynamic> _$TrivialNestedNonNullableToJson( |
| | | TrivialNestedNonNullable instance) => |
| | | _$TrivialNestedNonNullableJsonMapWrapper(instance); |
| | | |
| | | class _$TrivialNestedNonNullableJsonMapWrapper extends $JsonMapWrapper { |
| | | final TrivialNestedNonNullable _v; |
| | | _$TrivialNestedNonNullableJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const ['child', 'otherField']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'child': |
| | | return _v.child.toJson(); |
| | | case 'otherField': |
| | | return _v.otherField; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | ''' |
| | | : r''' |
| | | Map<String, dynamic> _$TrivialNestedNonNullableToJson( |
| | | TrivialNestedNonNullable instance) => |
| | | <String, dynamic>{ |
| | | 'child': instance.child.toJson(), |
| | | 'otherField': instance.otherField |
| | | }; |
| | | '''; |
| | | |
| | | expect(output, expected); |
| | | }); |
| | | }); |
| | | |
| | | group('unknown types', () { |
| | | tearDown(() { |
| | | expect(_buildLogItems, hasLength(1)); |
| | | expect(_buildLogItems.first, |
| | | startsWith('This element has an undefined type.')); |
| | | _buildLogItems.clear(); |
| | | }); |
| | | String flavorMessage(String flavor) => |
| | | 'Could not generate `$flavor` code for `number` ' |
| | | 'because the type is undefined.'; |
| | | |
| | | String flavorTodo(String flavor) => |
| | | 'Check your imports. If you\'re trying to generate code for a ' |
| | | 'Platform-provided type, you may have to specify a custom `$flavor` ' |
| | | 'in the associated `@JsonKey` annotation.'; |
| | | |
| | | group('fromJson', () { |
| | | final msg = flavorMessage('fromJson'); |
| | | final todo = flavorTodo('fromJson'); |
| | | test('in constructor arguments', () { |
| | | expectThrows('UnknownCtorParamType', msg, todo); |
| | | }); |
| | | |
| | | test('in fields', () { |
| | | expectThrows('UnknownFieldType', msg, todo); |
| | | }); |
| | | }); |
| | | |
| | | group('toJson', () { |
| | | test('in fields', () { |
| | | expectThrows('UnknownFieldTypeToJsonOnly', flavorMessage('toJson'), |
| | | flavorTodo('toJson')); |
| | | }); |
| | | }); |
| | | |
| | | test('with proper convert methods', () { |
| | | final output = runForElementNamed('UnknownFieldTypeWithConvert'); |
| | | expect(output, contains("_everythingIs42(json['number'])")); |
| | | if (generator.useWrappers) { |
| | | expect(output, contains('_everythingIs42(_v.number)')); |
| | | } else { |
| | | expect(output, contains('_everythingIs42(instance.number)')); |
| | | } |
| | | }); |
| | | }); |
| | | |
| | | group('unserializable types', () { |
| | | final noSupportHelperFyi = 'Could not generate `toJson` code for `watch`.\n' |
| | | 'None of the provided `TypeHelper` instances support the defined type.'; |
| | | |
| | | test('for toJson', () { |
| | | expectThrows('NoSerializeFieldType', noSupportHelperFyi, |
| | | 'Make sure all of the types are serializable.'); |
| | | }); |
| | | |
| | | test('for fromJson', () { |
| | | expectThrows( |
| | | 'NoDeserializeFieldType', |
| | | noSupportHelperFyi.replaceFirst('toJson', 'fromJson'), |
| | | 'Make sure all of the types are serializable.'); |
| | | }); |
| | | |
| | | final mapKeyFyi = 'Could not generate `toJson` code for `intDateTimeMap` ' |
| | | 'because of type `int`.\nMap keys must be of type ' |
| | | '`String`, enum, `Object` or `dynamic`.'; |
| | | |
| | | test('for toJson in Map key', () { |
| | | expectThrows('NoSerializeBadKey', mapKeyFyi, |
| | | 'Make sure all of the types are serializable.'); |
| | | }); |
| | | |
| | | test('for fromJson', () { |
| | | expectThrows( |
| | | 'NoDeserializeBadKey', |
| | | mapKeyFyi.replaceFirst('toJson', 'fromJson'), |
| | | 'Make sure all of the types are serializable.'); |
| | | }); |
| | | }); |
| | | |
| | | test('class with final fields', () { |
| | | final generateResult = runForElementNamed('FinalFields'); |
| | | expect( |
| | | generateResult, |
| | | contains( |
| | | r'Map<String, dynamic> _$FinalFieldsToJson(FinalFields instance)')); |
| | | }); |
| | | |
| | | group('valid inputs', () { |
| | | test('class with fromJson() constructor with optional parameters', () { |
| | | final output = runForElementNamed('FromJsonOptionalParameters'); |
| | | |
| | | expect(output, contains('ChildWithFromJson.fromJson')); |
| | | }); |
| | | |
| | | test('class with child json-able object', () { |
| | | final output = runForElementNamed('ParentObject'); |
| | | |
| | | expect( |
| | | output, |
| | | contains("ChildObject.fromJson(json['child'] " |
| | | 'as Map<String, dynamic>)')); |
| | | }); |
| | | |
| | | test('class with child json-able object - anyMap', () { |
| | | final output = _runForElementNamed( |
| | | JsonSerializable(anyMap: true, useWrappers: generator.useWrappers), |
| | | 'ParentObject'); |
| | | |
| | | expect(output, contains("ChildObject.fromJson(json['child'] as Map)")); |
| | | }); |
| | | |
| | | test('class with child list of json-able objects', () { |
| | | final output = runForElementNamed('ParentObjectWithChildren'); |
| | | |
| | | expect(output, contains('.toList()')); |
| | | expect(output, contains('ChildObject.fromJson')); |
| | | }); |
| | | |
| | | test('class with child list of dynamic objects is left alone', () { |
| | | final output = runForElementNamed('ParentObjectWithDynamicChildren'); |
| | | |
| | | expect(output, contains('children = json[\'children\'] as List;')); |
| | | }); |
| | | |
| | | test('class with list of int is cast for strong mode', () { |
| | | final output = runForElementNamed('Person'); |
| | | |
| | | expect(output, |
| | | contains("json['listOfInts'] as List)?.map((e) => e as int)")); |
| | | }); |
| | | }); |
| | | |
| | | group('includeIfNull', () { |
| | | test('some', () { |
| | | final output = runForElementNamed('IncludeIfNullAll'); |
| | | expect(output, isNot(contains(generatedLocalVarName))); |
| | | expect(output, isNot(contains(toJsonMapHelperName))); |
| | | }); |
| | | }); |
| | | |
| | | test('missing default ctor with a factory', () { |
| | | expect( |
| | | () => runForElementNamed('NoCtorClass'), |
| | | _throwsUnsupportedError( |
| | | 'The class `NoCtorClass` has no default constructor.')); |
| | | }); |
| | | } |
| | | |
| | | class _ConfigLogger implements TypeHelper<TypeHelperContextWithConfig> { |
| | | static final configurations = <JsonSerializable>[]; |
| | | |
| | | const _ConfigLogger(); |
| | | |
| | | @override |
| | | Object deserialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConfig context) { |
| | | configurations.add(context.config); |
| | | return null; |
| | | } |
| | | |
| | | @override |
| | | Object serialize(DartType targetType, String expression, |
| | | TypeHelperContextWithConfig context) { |
| | | configurations.add(context.config); |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | class GenericConverter<T> implements JsonConverter<T, Map<String, dynamic>> { |
| | | const GenericConverter(); |
| | | |
| | | @override |
| | | T fromJson(Map<String, dynamic> json) => null; |
| | | |
| | | @override |
| | | Map<String, dynamic> toJson(T object) => {}; |
| | | } |
| | | |
| | | class TrivialNumber { |
| | | final int value; |
| | | |
| | | TrivialNumber(this.value); |
| | | } |
| | | |
| | | class TrivialNumberConverter implements JsonConverter<TrivialNumber, int> { |
| | | static const instance = TrivialNumberConverter(); |
| | | |
| | | const TrivialNumberConverter(); |
| | | |
| | | @override |
| | | TrivialNumber fromJson(int json) => TrivialNumber(json); |
| | | |
| | | @override |
| | | int toJson(TrivialNumber object) => object.value; |
| | | } |
| | | |
| | | class BigIntStringConverter implements JsonConverter<BigInt, String> { |
| | | const BigIntStringConverter(); |
| | | |
| | | @override |
| | | BigInt fromJson(String json) => BigInt.parse(json); |
| | | |
| | | @override |
| | | String toJson(BigInt object) => object.toString(); |
| | | } |
| | | |
| | | const durationConverter = DurationMillisecondConverter(); |
| | | |
| | | class DurationMillisecondConverter implements JsonConverter<Duration, int> { |
| | | const DurationMillisecondConverter(); |
| | | |
| | | @override |
| | | Duration fromJson(int json) => Duration(milliseconds: json); |
| | | |
| | | @override |
| | | int toJson(Duration object) => object.inMilliseconds; |
| | | } |
| | | |
| | | class EpochDateTimeConverter implements JsonConverter<DateTime, int> { |
| | | const EpochDateTimeConverter(); |
| | | |
| | | @override |
| | | DateTime fromJson(int json) => DateTime.fromMillisecondsSinceEpoch(json); |
| | | |
| | | @override |
| | | int toJson(DateTime object) => object.millisecondsSinceEpoch; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // ignore_for_file: annotate_overrides, hash_and_equals |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'json_converters.dart'; |
| | | import 'kitchen_sink_interface.dart' as k; |
| | | import 'simple_object.dart'; |
| | | import 'strict_keys_object.dart'; |
| | | |
| | | part 'kitchen_sink.g.dart'; |
| | | |
| | | // NOTE: these methods are replaced in the `non_nullable` cases to return |
| | | // non-null values. |
| | | List<T> _defaultList<T>() => null; |
| | | Set<T> _defaultSet<T>() => null; |
| | | Map _defaultMap() => null; |
| | | SimpleObject _defaultSimpleObject() => null; |
| | | StrictKeysObject _defaultStrictKeysObject() => null; |
| | | |
| | | k.KitchenSink testFactory( |
| | | {int ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) => |
| | | KitchenSink( |
| | | ctorValidatedNo42: ctorValidatedNo42, |
| | | iterable: iterable, |
| | | dynamicIterable: dynamicIterable, |
| | | objectIterable: objectIterable, |
| | | intIterable: intIterable, |
| | | dateTimeIterable: dateTimeIterable); |
| | | |
| | | k.KitchenSink testFromJson(Map json) => KitchenSink.fromJson(json); |
| | | |
| | | @JsonSerializable(anyMap: true, generateToJsonFunction: false) |
| | | class KitchenSink extends Object |
| | | with _$KitchenSinkSerializerMixin |
| | | implements k.KitchenSink { |
| | | // To ensure static members are not considered for serialization. |
| | | static const answer = 42; |
| | | static final reason = 42; |
| | | static int get understand => 42; |
| | | |
| | | // NOTE: exposing these as Iterable, but storing the values as List |
| | | // to make the equality test work trivially. |
| | | final Iterable _iterable; |
| | | final Iterable<dynamic> _dynamicIterable; |
| | | final Iterable<Object> _objectIterable; |
| | | final Iterable<int> _intIterable; |
| | | final Iterable<DateTime> _dateTimeIterable; |
| | | |
| | | @JsonKey(name: 'no-42') |
| | | final int ctorValidatedNo42; |
| | | |
| | | KitchenSink( |
| | | {this.ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) |
| | | : _iterable = iterable?.toList() ?? _defaultList(), |
| | | _dynamicIterable = dynamicIterable?.toList() ?? _defaultList(), |
| | | _objectIterable = objectIterable?.toList() ?? _defaultList(), |
| | | _intIterable = intIterable?.toList() ?? _defaultList(), |
| | | _dateTimeIterable = dateTimeIterable?.toList() ?? _defaultList() { |
| | | if (ctorValidatedNo42 == 42) { |
| | | throw ArgumentError.value( |
| | | 42, 'ctorValidatedNo42', 'The value `42` is not allowed.'); |
| | | } |
| | | } |
| | | |
| | | factory KitchenSink.fromJson(Map json) => _$KitchenSinkFromJson(json); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | DateTime dateTime; |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | Iterable get iterable => _iterable; |
| | | Iterable<dynamic> get dynamicIterable => _dynamicIterable; |
| | | Iterable<Object> get objectIterable => _objectIterable; |
| | | Iterable<int> get intIterable => _intIterable; |
| | | |
| | | Set set = _defaultSet(); |
| | | Set<dynamic> dynamicSet = _defaultSet(); |
| | | Set<Object> objectSet = _defaultSet(); |
| | | Set<int> intSet = _defaultSet(); |
| | | Set<DateTime> dateTimeSet = _defaultSet(); |
| | | |
| | | // Added a one-off annotation on a property (not a field) |
| | | @JsonKey(name: 'datetime-iterable') |
| | | Iterable<DateTime> get dateTimeIterable => _dateTimeIterable; |
| | | |
| | | List list = _defaultList(); |
| | | List<dynamic> dynamicList = _defaultList(); |
| | | List<Object> objectList = _defaultList(); |
| | | List<int> intList = _defaultList(); |
| | | @JsonKey(includeIfNull: false) |
| | | List<DateTime> dateTimeList = _defaultList(); |
| | | |
| | | Map map = _defaultMap(); |
| | | Map<String, String> stringStringMap = _defaultMap(); |
| | | Map<dynamic, int> dynamicIntMap = _defaultMap(); |
| | | Map<Object, DateTime> objectDateTimeMap = _defaultMap(); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> crazyComplex = |
| | | _defaultList(); |
| | | |
| | | // Handle fields with names that collide with helper names |
| | | @JsonKey(includeIfNull: false) |
| | | Map<String, bool> val = _defaultMap(); |
| | | bool writeNotNull; |
| | | @JsonKey(name: r'$string') |
| | | String string; |
| | | |
| | | SimpleObject simpleObject = _defaultSimpleObject(); |
| | | |
| | | StrictKeysObject strictKeysObject = _defaultStrictKeysObject(); |
| | | |
| | | int _validatedPropertyNo42; |
| | | int get validatedPropertyNo42 => _validatedPropertyNo42; |
| | | |
| | | set validatedPropertyNo42(int value) { |
| | | if (value == 42) { |
| | | throw StateError('Cannot be 42!'); |
| | | } |
| | | _validatedPropertyNo42 = value; |
| | | } |
| | | |
| | | bool operator ==(Object other) => k.sinkEquals(this, other); |
| | | } |
| | | |
| | | @JsonSerializable(anyMap: true, generateToJsonFunction: false) |
| | | // referencing a top-level field should work |
| | | @durationConverter |
| | | // referencing via a const constructor should work |
| | | @BigIntStringConverter() |
| | | @TrivialNumberConverter.instance |
| | | @EpochDateTimeConverter() |
| | | class JsonConverterTestClass extends Object |
| | | with _$JsonConverterTestClassSerializerMixin { |
| | | JsonConverterTestClass(); |
| | | |
| | | factory JsonConverterTestClass.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterTestClassFromJson(json); |
| | | |
| | | Duration duration; |
| | | List<Duration> durationList; |
| | | |
| | | BigInt bigInt; |
| | | Map<String, BigInt> bigIntMap; |
| | | |
| | | TrivialNumber numberSilly; |
| | | Set<TrivialNumber> numberSillySet; |
| | | |
| | | DateTime dateTime; |
| | | } |
| | | |
| | | @JsonSerializable(anyMap: true, generateToJsonFunction: false) |
| | | @GenericConverter() |
| | | class JsonConverterGeneric<S, T, U> extends Object |
| | | with _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S item; |
| | | List<T> itemList; |
| | | Map<String, U> itemMap; |
| | | |
| | | JsonConverterGeneric(); |
| | | |
| | | factory JsonConverterGeneric.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterGenericFromJson(json); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'kitchen_sink.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | KitchenSink _$KitchenSinkFromJson(Map json) { |
| | | return KitchenSink( |
| | | ctorValidatedNo42: json['no-42'] as int, |
| | | iterable: json['iterable'] as List, |
| | | dynamicIterable: json['dynamicIterable'] as List, |
| | | objectIterable: json['objectIterable'] as List, |
| | | intIterable: (json['intIterable'] as List)?.map((e) => e as int), |
| | | dateTimeIterable: (json['datetime-iterable'] as List) |
| | | ?.map((e) => e == null ? null : DateTime.parse(e as String))) |
| | | ..dateTime = json['dateTime'] == null |
| | | ? null |
| | | : DateTime.parse(json['dateTime'] as String) |
| | | ..set = (json['set'] as List)?.map((e) => e)?.toSet() |
| | | ..dynamicSet = (json['dynamicSet'] as List)?.map((e) => e)?.toSet() |
| | | ..objectSet = (json['objectSet'] as List)?.map((e) => e)?.toSet() |
| | | ..intSet = (json['intSet'] as List)?.map((e) => e as int)?.toSet() |
| | | ..dateTimeSet = (json['dateTimeSet'] as List) |
| | | ?.map((e) => e == null ? null : DateTime.parse(e as String)) |
| | | ?.toSet() |
| | | ..list = json['list'] as List |
| | | ..dynamicList = json['dynamicList'] as List |
| | | ..objectList = json['objectList'] as List |
| | | ..intList = (json['intList'] as List)?.map((e) => e as int)?.toList() |
| | | ..dateTimeList = (json['dateTimeList'] as List) |
| | | ?.map((e) => e == null ? null : DateTime.parse(e as String)) |
| | | ?.toList() |
| | | ..map = json['map'] as Map |
| | | ..stringStringMap = (json['stringStringMap'] as Map) |
| | | ?.map((k, e) => MapEntry(k as String, e as String)) |
| | | ..dynamicIntMap = |
| | | (json['dynamicIntMap'] as Map)?.map((k, e) => MapEntry(k, e as int)) |
| | | ..objectDateTimeMap = (json['objectDateTimeMap'] as Map)?.map( |
| | | (k, e) => MapEntry(k, e == null ? null : DateTime.parse(e as String))) |
| | | ..crazyComplex = (json['crazyComplex'] as List) |
| | | ?.map((e) => (e as Map)?.map((k, e) => MapEntry( |
| | | k as String, |
| | | (e as Map)?.map((k, e) => MapEntry(k as String, |
| | | (e as List)?.map((e) => (e as List)?.map((e) => e == null ? null : DateTime.parse(e as String))?.toList())?.toList()))))) |
| | | ?.toList() |
| | | ..val = (json['val'] as Map)?.map((k, e) => MapEntry(k as String, e as bool)) |
| | | ..writeNotNull = json['writeNotNull'] as bool |
| | | ..string = json[r'$string'] as String |
| | | ..simpleObject = json['simpleObject'] == null ? null : SimpleObject.fromJson(json['simpleObject'] as Map) |
| | | ..strictKeysObject = json['strictKeysObject'] == null ? null : StrictKeysObject.fromJson(json['strictKeysObject'] as Map) |
| | | ..validatedPropertyNo42 = json['validatedPropertyNo42'] as int; |
| | | } |
| | | |
| | | abstract class _$KitchenSinkSerializerMixin { |
| | | int get ctorValidatedNo42; |
| | | DateTime get dateTime; |
| | | Iterable<dynamic> get iterable; |
| | | Iterable<dynamic> get dynamicIterable; |
| | | Iterable<Object> get objectIterable; |
| | | Iterable<int> get intIterable; |
| | | Set<dynamic> get set; |
| | | Set<dynamic> get dynamicSet; |
| | | Set<Object> get objectSet; |
| | | Set<int> get intSet; |
| | | Set<DateTime> get dateTimeSet; |
| | | Iterable<DateTime> get dateTimeIterable; |
| | | List<dynamic> get list; |
| | | List<dynamic> get dynamicList; |
| | | List<Object> get objectList; |
| | | List<int> get intList; |
| | | List<DateTime> get dateTimeList; |
| | | Map<dynamic, dynamic> get map; |
| | | Map<String, String> get stringStringMap; |
| | | Map<dynamic, int> get dynamicIntMap; |
| | | Map<Object, DateTime> get objectDateTimeMap; |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> get crazyComplex; |
| | | Map<String, bool> get val; |
| | | bool get writeNotNull; |
| | | String get string; |
| | | SimpleObject get simpleObject; |
| | | StrictKeysObject get strictKeysObject; |
| | | int get validatedPropertyNo42; |
| | | Map<String, dynamic> toJson() { |
| | | final val = <String, dynamic>{ |
| | | 'no-42': ctorValidatedNo42, |
| | | }; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('dateTime', dateTime?.toIso8601String()); |
| | | writeNotNull('iterable', iterable?.toList()); |
| | | val['dynamicIterable'] = dynamicIterable?.toList(); |
| | | val['objectIterable'] = objectIterable?.toList(); |
| | | val['intIterable'] = intIterable?.toList(); |
| | | val['set'] = set?.toList(); |
| | | val['dynamicSet'] = dynamicSet?.toList(); |
| | | val['objectSet'] = objectSet?.toList(); |
| | | val['intSet'] = intSet?.toList(); |
| | | val['dateTimeSet'] = |
| | | dateTimeSet?.map((e) => e?.toIso8601String())?.toList(); |
| | | val['datetime-iterable'] = |
| | | dateTimeIterable?.map((e) => e?.toIso8601String())?.toList(); |
| | | val['list'] = list; |
| | | val['dynamicList'] = dynamicList; |
| | | val['objectList'] = objectList; |
| | | val['intList'] = intList; |
| | | writeNotNull('dateTimeList', |
| | | dateTimeList?.map((e) => e?.toIso8601String())?.toList()); |
| | | val['map'] = map; |
| | | val['stringStringMap'] = stringStringMap; |
| | | val['dynamicIntMap'] = dynamicIntMap; |
| | | val['objectDateTimeMap'] = |
| | | objectDateTimeMap?.map((k, e) => MapEntry(k, e?.toIso8601String())); |
| | | writeNotNull( |
| | | 'crazyComplex', |
| | | crazyComplex |
| | | ?.map((e) => e?.map((k, e) => MapEntry( |
| | | k, |
| | | e?.map((k, e) => MapEntry( |
| | | k, |
| | | e |
| | | ?.map((e) => |
| | | e?.map((e) => e?.toIso8601String())?.toList()) |
| | | ?.toList()))))) |
| | | ?.toList()); |
| | | writeNotNull('val', this.val); |
| | | val['writeNotNull'] = this.writeNotNull; |
| | | val[r'$string'] = string; |
| | | val['simpleObject'] = simpleObject; |
| | | val['strictKeysObject'] = strictKeysObject; |
| | | val['validatedPropertyNo42'] = validatedPropertyNo42; |
| | | return val; |
| | | } |
| | | } |
| | | |
| | | JsonConverterTestClass _$JsonConverterTestClassFromJson(Map json) { |
| | | return JsonConverterTestClass() |
| | | ..duration = json['duration'] == null |
| | | ? null |
| | | : durationConverter.fromJson(json['duration'] as int) |
| | | ..durationList = (json['durationList'] as List) |
| | | ?.map((e) => e == null ? null : durationConverter.fromJson(e as int)) |
| | | ?.toList() |
| | | ..bigInt = json['bigInt'] == null |
| | | ? null |
| | | : const BigIntStringConverter().fromJson(json['bigInt'] as String) |
| | | ..bigIntMap = (json['bigIntMap'] as Map)?.map((k, e) => MapEntry( |
| | | k as String, |
| | | e == null ? null : const BigIntStringConverter().fromJson(e as String))) |
| | | ..numberSilly = json['numberSilly'] == null |
| | | ? null |
| | | : TrivialNumberConverter.instance.fromJson(json['numberSilly'] as int) |
| | | ..numberSillySet = (json['numberSillySet'] as List) |
| | | ?.map((e) => e == null |
| | | ? null |
| | | : TrivialNumberConverter.instance.fromJson(e as int)) |
| | | ?.toSet() |
| | | ..dateTime = json['dateTime'] == null |
| | | ? null |
| | | : const EpochDateTimeConverter().fromJson(json['dateTime'] as int); |
| | | } |
| | | |
| | | abstract class _$JsonConverterTestClassSerializerMixin { |
| | | Duration get duration; |
| | | List<Duration> get durationList; |
| | | BigInt get bigInt; |
| | | Map<String, BigInt> get bigIntMap; |
| | | TrivialNumber get numberSilly; |
| | | Set<TrivialNumber> get numberSillySet; |
| | | DateTime get dateTime; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{ |
| | | 'duration': |
| | | duration == null ? null : durationConverter.toJson(duration), |
| | | 'durationList': durationList |
| | | ?.map((e) => e == null ? null : durationConverter.toJson(e)) |
| | | ?.toList(), |
| | | 'bigInt': bigInt == null |
| | | ? null |
| | | : const BigIntStringConverter().toJson(bigInt), |
| | | 'bigIntMap': bigIntMap?.map((k, e) => MapEntry( |
| | | k, e == null ? null : const BigIntStringConverter().toJson(e))), |
| | | 'numberSilly': numberSilly == null |
| | | ? null |
| | | : TrivialNumberConverter.instance.toJson(numberSilly), |
| | | 'numberSillySet': numberSillySet |
| | | ?.map((e) => |
| | | e == null ? null : TrivialNumberConverter.instance.toJson(e)) |
| | | ?.toList(), |
| | | 'dateTime': dateTime == null |
| | | ? null |
| | | : const EpochDateTimeConverter().toJson(dateTime) |
| | | }; |
| | | } |
| | | |
| | | JsonConverterGeneric<S, T, U> _$JsonConverterGenericFromJson<S, T, U>( |
| | | Map json) { |
| | | return JsonConverterGeneric<S, T, U>() |
| | | ..item = json['item'] == null |
| | | ? null |
| | | : GenericConverter<S>().fromJson(json['item'] as Map<String, dynamic>) |
| | | ..itemList = (json['itemList'] as List) |
| | | ?.map((e) => e == null |
| | | ? null |
| | | : GenericConverter<T>().fromJson(e as Map<String, dynamic>)) |
| | | ?.toList() |
| | | ..itemMap = (json['itemMap'] as Map)?.map((k, e) => MapEntry( |
| | | k as String, |
| | | e == null |
| | | ? null |
| | | : GenericConverter<U>().fromJson(e as Map<String, dynamic>))); |
| | | } |
| | | |
| | | abstract class _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S get item; |
| | | List<T> get itemList; |
| | | Map<String, U> get itemMap; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{ |
| | | 'item': item == null ? null : GenericConverter<S>().toJson(item), |
| | | 'itemList': itemList |
| | | ?.map((e) => e == null ? null : GenericConverter<T>().toJson(e)) |
| | | ?.toList(), |
| | | 'itemMap': itemMap?.map((k, e) => |
| | | MapEntry(k, e == null ? null : GenericConverter<U>().toJson(e))) |
| | | }; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _CheckedGenerator |
| | | // ************************************************************************** |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _NonNullableGenerator |
| | | // ************************************************************************** |
| | | |
| | | // ignore_for_file: annotate_overrides, hash_and_equals |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'json_converters.dart'; |
| | | import 'kitchen_sink_interface.dart' as k; |
| | | import 'simple_object.dart'; |
| | | import 'strict_keys_object.dart'; |
| | | |
| | | part 'kitchen_sink.non_nullable.checked.g.dart'; |
| | | |
| | | // NOTE: these methods are replaced in the `non_nullable` cases to return |
| | | // non-null values. |
| | | List<T> _defaultList<T>() => <T>[]; |
| | | Set<T> _defaultSet<T>() => Set<T>(); |
| | | Map<String, T> _defaultMap<T>() => <String, T>{}; |
| | | SimpleObject _defaultSimpleObject() => SimpleObject(42); |
| | | StrictKeysObject _defaultStrictKeysObject() => StrictKeysObject(10, 'cool'); |
| | | |
| | | k.KitchenSink testFactory( |
| | | {int ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) => |
| | | KitchenSink( |
| | | ctorValidatedNo42: ctorValidatedNo42, |
| | | iterable: iterable, |
| | | dynamicIterable: dynamicIterable, |
| | | objectIterable: objectIterable, |
| | | intIterable: intIterable, |
| | | dateTimeIterable: dateTimeIterable); |
| | | |
| | | k.KitchenSink testFromJson(Map json) => KitchenSink.fromJson(json); |
| | | |
| | | @JsonSerializable( |
| | | checked: true, nullable: false, anyMap: true, generateToJsonFunction: false) |
| | | class KitchenSink extends Object |
| | | with _$KitchenSinkSerializerMixin |
| | | implements k.KitchenSink { |
| | | // To ensure static members are not considered for serialization. |
| | | static const answer = 42; |
| | | static final reason = 42; |
| | | static int get understand => 42; |
| | | |
| | | // NOTE: exposing these as Iterable, but storing the values as List |
| | | // to make the equality test work trivially. |
| | | final Iterable _iterable; |
| | | final Iterable<dynamic> _dynamicIterable; |
| | | final Iterable<Object> _objectIterable; |
| | | final Iterable<int> _intIterable; |
| | | final Iterable<DateTime> _dateTimeIterable; |
| | | |
| | | @JsonKey(name: 'no-42') |
| | | final int ctorValidatedNo42; |
| | | |
| | | KitchenSink( |
| | | {this.ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) |
| | | : _iterable = iterable?.toList() ?? _defaultList(), |
| | | _dynamicIterable = dynamicIterable?.toList() ?? _defaultList(), |
| | | _objectIterable = objectIterable?.toList() ?? _defaultList(), |
| | | _intIterable = intIterable?.toList() ?? _defaultList(), |
| | | _dateTimeIterable = dateTimeIterable?.toList() ?? _defaultList() { |
| | | if (ctorValidatedNo42 == 42) { |
| | | throw ArgumentError.value( |
| | | 42, 'ctorValidatedNo42', 'The value `42` is not allowed.'); |
| | | } |
| | | } |
| | | |
| | | factory KitchenSink.fromJson(Map json) => _$KitchenSinkFromJson(json); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | DateTime dateTime = DateTime(1981, 6, 5); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | Iterable get iterable => _iterable; |
| | | Iterable<dynamic> get dynamicIterable => _dynamicIterable; |
| | | Iterable<Object> get objectIterable => _objectIterable; |
| | | Iterable<int> get intIterable => _intIterable; |
| | | |
| | | Set set = _defaultSet(); |
| | | Set<dynamic> dynamicSet = _defaultSet(); |
| | | Set<Object> objectSet = _defaultSet(); |
| | | Set<int> intSet = _defaultSet(); |
| | | Set<DateTime> dateTimeSet = _defaultSet(); |
| | | |
| | | // Added a one-off annotation on a property (not a field) |
| | | @JsonKey(name: 'datetime-iterable') |
| | | Iterable<DateTime> get dateTimeIterable => _dateTimeIterable; |
| | | |
| | | List list = _defaultList(); |
| | | List<dynamic> dynamicList = _defaultList(); |
| | | List<Object> objectList = _defaultList(); |
| | | List<int> intList = _defaultList(); |
| | | @JsonKey(includeIfNull: false) |
| | | List<DateTime> dateTimeList = _defaultList(); |
| | | |
| | | Map map = _defaultMap(); |
| | | Map<String, String> stringStringMap = _defaultMap(); |
| | | Map<dynamic, int> dynamicIntMap = _defaultMap(); |
| | | Map<Object, DateTime> objectDateTimeMap = _defaultMap(); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> crazyComplex = |
| | | _defaultList(); |
| | | |
| | | // Handle fields with names that collide with helper names |
| | | @JsonKey(includeIfNull: false) |
| | | Map<String, bool> val = _defaultMap(); |
| | | bool writeNotNull; |
| | | @JsonKey(name: r'$string') |
| | | String string; |
| | | |
| | | SimpleObject simpleObject = _defaultSimpleObject(); |
| | | |
| | | StrictKeysObject strictKeysObject = _defaultStrictKeysObject(); |
| | | |
| | | int _validatedPropertyNo42; |
| | | int get validatedPropertyNo42 => _validatedPropertyNo42; |
| | | |
| | | set validatedPropertyNo42(int value) { |
| | | if (value == 42) { |
| | | throw StateError('Cannot be 42!'); |
| | | } |
| | | _validatedPropertyNo42 = value; |
| | | } |
| | | |
| | | bool operator ==(Object other) => k.sinkEquals(this, other); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | checked: true, nullable: false, anyMap: true, generateToJsonFunction: false) |
| | | // referencing a top-level field should work |
| | | @durationConverter |
| | | // referencing via a const constructor should work |
| | | @BigIntStringConverter() |
| | | @TrivialNumberConverter.instance |
| | | @EpochDateTimeConverter() |
| | | class JsonConverterTestClass extends Object |
| | | with _$JsonConverterTestClassSerializerMixin { |
| | | JsonConverterTestClass(); |
| | | |
| | | factory JsonConverterTestClass.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterTestClassFromJson(json); |
| | | |
| | | Duration duration; |
| | | List<Duration> durationList; |
| | | |
| | | BigInt bigInt; |
| | | Map<String, BigInt> bigIntMap; |
| | | |
| | | TrivialNumber numberSilly; |
| | | Set<TrivialNumber> numberSillySet; |
| | | |
| | | DateTime dateTime = DateTime(1981, 6, 5); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | checked: true, nullable: false, anyMap: true, generateToJsonFunction: false) |
| | | @GenericConverter() |
| | | class JsonConverterGeneric<S, T, U> extends Object |
| | | with _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S item; |
| | | List<T> itemList; |
| | | Map<String, U> itemMap; |
| | | |
| | | JsonConverterGeneric(); |
| | | |
| | | factory JsonConverterGeneric.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterGenericFromJson(json); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'kitchen_sink.non_nullable.checked.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | KitchenSink _$KitchenSinkFromJson(Map json) { |
| | | return $checkedNew('KitchenSink', json, () { |
| | | final val = KitchenSink( |
| | | ctorValidatedNo42: $checkedConvert(json, 'no-42', (v) => v as int), |
| | | iterable: $checkedConvert(json, 'iterable', (v) => v as List), |
| | | dynamicIterable: |
| | | $checkedConvert(json, 'dynamicIterable', (v) => v as List), |
| | | objectIterable: |
| | | $checkedConvert(json, 'objectIterable', (v) => v as List), |
| | | intIterable: $checkedConvert( |
| | | json, 'intIterable', (v) => (v as List).map((e) => e as int)), |
| | | dateTimeIterable: $checkedConvert(json, 'datetime-iterable', |
| | | (v) => (v as List).map((e) => DateTime.parse(e as String)))); |
| | | $checkedConvert( |
| | | json, 'dateTime', (v) => val.dateTime = DateTime.parse(v as String)); |
| | | $checkedConvert( |
| | | json, 'set', (v) => val.set = (v as List).map((e) => e).toSet()); |
| | | $checkedConvert(json, 'dynamicSet', |
| | | (v) => val.dynamicSet = (v as List).map((e) => e).toSet()); |
| | | $checkedConvert(json, 'objectSet', |
| | | (v) => val.objectSet = (v as List).map((e) => e).toSet()); |
| | | $checkedConvert(json, 'intSet', |
| | | (v) => val.intSet = (v as List).map((e) => e as int).toSet()); |
| | | $checkedConvert( |
| | | json, |
| | | 'dateTimeSet', |
| | | (v) => val.dateTimeSet = |
| | | (v as List).map((e) => DateTime.parse(e as String)).toSet()); |
| | | $checkedConvert(json, 'list', (v) => val.list = v as List); |
| | | $checkedConvert(json, 'dynamicList', (v) => val.dynamicList = v as List); |
| | | $checkedConvert(json, 'objectList', (v) => val.objectList = v as List); |
| | | $checkedConvert(json, 'intList', |
| | | (v) => val.intList = (v as List).map((e) => e as int).toList()); |
| | | $checkedConvert( |
| | | json, |
| | | 'dateTimeList', |
| | | (v) => val.dateTimeList = |
| | | (v as List).map((e) => DateTime.parse(e as String)).toList()); |
| | | $checkedConvert(json, 'map', (v) => val.map = v as Map); |
| | | $checkedConvert(json, 'stringStringMap', |
| | | (v) => val.stringStringMap = Map<String, String>.from(v as Map)); |
| | | $checkedConvert(json, 'dynamicIntMap', |
| | | (v) => val.dynamicIntMap = Map<String, int>.from(v as Map)); |
| | | $checkedConvert( |
| | | json, |
| | | 'objectDateTimeMap', |
| | | (v) => val.objectDateTimeMap = |
| | | (v as Map).map((k, e) => MapEntry(k, DateTime.parse(e as String)))); |
| | | $checkedConvert( |
| | | json, |
| | | 'crazyComplex', |
| | | (v) => val.crazyComplex = (v as List) |
| | | .map((e) => (e as Map).map((k, e) => MapEntry( |
| | | k as String, |
| | | (e as Map).map((k, e) => MapEntry( |
| | | k as String, |
| | | (e as List) |
| | | .map((e) => (e as List) |
| | | .map((e) => DateTime.parse(e as String)) |
| | | .toList()) |
| | | .toList()))))) |
| | | .toList()); |
| | | $checkedConvert( |
| | | json, 'val', (v) => val.val = Map<String, bool>.from(v as Map)); |
| | | $checkedConvert(json, 'writeNotNull', (v) => val.writeNotNull = v as bool); |
| | | $checkedConvert(json, r'$string', (v) => val.string = v as String); |
| | | $checkedConvert(json, 'simpleObject', |
| | | (v) => val.simpleObject = SimpleObject.fromJson(v as Map)); |
| | | $checkedConvert(json, 'strictKeysObject', |
| | | (v) => val.strictKeysObject = StrictKeysObject.fromJson(v as Map)); |
| | | $checkedConvert(json, 'validatedPropertyNo42', |
| | | (v) => val.validatedPropertyNo42 = v as int); |
| | | return val; |
| | | }, fieldKeyMap: const { |
| | | 'ctorValidatedNo42': 'no-42', |
| | | 'dateTimeIterable': 'datetime-iterable', |
| | | 'string': r'$string' |
| | | }); |
| | | } |
| | | |
| | | abstract class _$KitchenSinkSerializerMixin { |
| | | int get ctorValidatedNo42; |
| | | DateTime get dateTime; |
| | | Iterable<dynamic> get iterable; |
| | | Iterable<dynamic> get dynamicIterable; |
| | | Iterable<Object> get objectIterable; |
| | | Iterable<int> get intIterable; |
| | | Set<dynamic> get set; |
| | | Set<dynamic> get dynamicSet; |
| | | Set<Object> get objectSet; |
| | | Set<int> get intSet; |
| | | Set<DateTime> get dateTimeSet; |
| | | Iterable<DateTime> get dateTimeIterable; |
| | | List<dynamic> get list; |
| | | List<dynamic> get dynamicList; |
| | | List<Object> get objectList; |
| | | List<int> get intList; |
| | | List<DateTime> get dateTimeList; |
| | | Map<dynamic, dynamic> get map; |
| | | Map<String, String> get stringStringMap; |
| | | Map<dynamic, int> get dynamicIntMap; |
| | | Map<Object, DateTime> get objectDateTimeMap; |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> get crazyComplex; |
| | | Map<String, bool> get val; |
| | | bool get writeNotNull; |
| | | String get string; |
| | | SimpleObject get simpleObject; |
| | | StrictKeysObject get strictKeysObject; |
| | | int get validatedPropertyNo42; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{ |
| | | 'no-42': ctorValidatedNo42, |
| | | 'dateTime': dateTime.toIso8601String(), |
| | | 'iterable': iterable.toList(), |
| | | 'dynamicIterable': dynamicIterable.toList(), |
| | | 'objectIterable': objectIterable.toList(), |
| | | 'intIterable': intIterable.toList(), |
| | | 'set': set.toList(), |
| | | 'dynamicSet': dynamicSet.toList(), |
| | | 'objectSet': objectSet.toList(), |
| | | 'intSet': intSet.toList(), |
| | | 'dateTimeSet': dateTimeSet.map((e) => e.toIso8601String()).toList(), |
| | | 'datetime-iterable': |
| | | dateTimeIterable.map((e) => e.toIso8601String()).toList(), |
| | | 'list': list, |
| | | 'dynamicList': dynamicList, |
| | | 'objectList': objectList, |
| | | 'intList': intList, |
| | | 'dateTimeList': dateTimeList.map((e) => e.toIso8601String()).toList(), |
| | | 'map': map, |
| | | 'stringStringMap': stringStringMap, |
| | | 'dynamicIntMap': dynamicIntMap, |
| | | 'objectDateTimeMap': |
| | | objectDateTimeMap.map((k, e) => MapEntry(k, e.toIso8601String())), |
| | | 'crazyComplex': crazyComplex |
| | | .map((e) => e.map((k, e) => MapEntry( |
| | | k, |
| | | e.map((k, e) => MapEntry( |
| | | k, |
| | | e |
| | | .map((e) => e.map((e) => e.toIso8601String()).toList()) |
| | | .toList()))))) |
| | | .toList(), |
| | | 'val': val, |
| | | 'writeNotNull': writeNotNull, |
| | | r'$string': string, |
| | | 'simpleObject': simpleObject, |
| | | 'strictKeysObject': strictKeysObject, |
| | | 'validatedPropertyNo42': validatedPropertyNo42 |
| | | }; |
| | | } |
| | | |
| | | JsonConverterTestClass _$JsonConverterTestClassFromJson(Map json) { |
| | | return $checkedNew('JsonConverterTestClass', json, () { |
| | | final val = JsonConverterTestClass(); |
| | | $checkedConvert(json, 'duration', |
| | | (v) => val.duration = durationConverter.fromJson(v as int)); |
| | | $checkedConvert( |
| | | json, |
| | | 'durationList', |
| | | (v) => val.durationList = (v as List) |
| | | .map((e) => durationConverter.fromJson(e as int)) |
| | | .toList()); |
| | | $checkedConvert( |
| | | json, |
| | | 'bigInt', |
| | | (v) => |
| | | val.bigInt = const BigIntStringConverter().fromJson(v as String)); |
| | | $checkedConvert( |
| | | json, |
| | | 'bigIntMap', |
| | | (v) => val.bigIntMap = (v as Map).map((k, e) => MapEntry( |
| | | k as String, const BigIntStringConverter().fromJson(e as String)))); |
| | | $checkedConvert( |
| | | json, |
| | | 'numberSilly', |
| | | (v) => val.numberSilly = |
| | | TrivialNumberConverter.instance.fromJson(v as int)); |
| | | $checkedConvert( |
| | | json, |
| | | 'numberSillySet', |
| | | (v) => val.numberSillySet = (v as List) |
| | | .map((e) => TrivialNumberConverter.instance.fromJson(e as int)) |
| | | .toSet()); |
| | | $checkedConvert( |
| | | json, |
| | | 'dateTime', |
| | | (v) => |
| | | val.dateTime = const EpochDateTimeConverter().fromJson(v as int)); |
| | | return val; |
| | | }); |
| | | } |
| | | |
| | | abstract class _$JsonConverterTestClassSerializerMixin { |
| | | Duration get duration; |
| | | List<Duration> get durationList; |
| | | BigInt get bigInt; |
| | | Map<String, BigInt> get bigIntMap; |
| | | TrivialNumber get numberSilly; |
| | | Set<TrivialNumber> get numberSillySet; |
| | | DateTime get dateTime; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{ |
| | | 'duration': durationConverter.toJson(duration), |
| | | 'durationList': durationList.map(durationConverter.toJson).toList(), |
| | | 'bigInt': const BigIntStringConverter().toJson(bigInt), |
| | | 'bigIntMap': bigIntMap.map( |
| | | (k, e) => MapEntry(k, const BigIntStringConverter().toJson(e))), |
| | | 'numberSilly': TrivialNumberConverter.instance.toJson(numberSilly), |
| | | 'numberSillySet': |
| | | numberSillySet.map(TrivialNumberConverter.instance.toJson).toList(), |
| | | 'dateTime': const EpochDateTimeConverter().toJson(dateTime) |
| | | }; |
| | | } |
| | | |
| | | JsonConverterGeneric<S, T, U> _$JsonConverterGenericFromJson<S, T, U>( |
| | | Map json) { |
| | | return $checkedNew('JsonConverterGeneric', json, () { |
| | | final val = JsonConverterGeneric<S, T, U>(); |
| | | $checkedConvert( |
| | | json, |
| | | 'item', |
| | | (v) => val.item = |
| | | GenericConverter<S>().fromJson(v as Map<String, dynamic>)); |
| | | $checkedConvert( |
| | | json, |
| | | 'itemList', |
| | | (v) => val.itemList = (v as List) |
| | | .map((e) => |
| | | GenericConverter<T>().fromJson(e as Map<String, dynamic>)) |
| | | .toList()); |
| | | $checkedConvert( |
| | | json, |
| | | 'itemMap', |
| | | (v) => val.itemMap = (v as Map).map((k, e) => MapEntry(k as String, |
| | | GenericConverter<U>().fromJson(e as Map<String, dynamic>)))); |
| | | return val; |
| | | }); |
| | | } |
| | | |
| | | abstract class _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S get item; |
| | | List<T> get itemList; |
| | | Map<String, U> get itemMap; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{ |
| | | 'item': GenericConverter<S>().toJson(item), |
| | | 'itemList': itemList.map(GenericConverter<T>().toJson).toList(), |
| | | 'itemMap': |
| | | itemMap.map((k, e) => MapEntry(k, GenericConverter<U>().toJson(e))) |
| | | }; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _NonNullableGenerator |
| | | // ************************************************************************** |
| | | |
| | | // ignore_for_file: annotate_overrides, hash_and_equals |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'json_converters.dart'; |
| | | import 'kitchen_sink_interface.dart' as k; |
| | | import 'simple_object.dart'; |
| | | import 'strict_keys_object.dart'; |
| | | |
| | | part 'kitchen_sink.non_nullable.g.dart'; |
| | | |
| | | // NOTE: these methods are replaced in the `non_nullable` cases to return |
| | | // non-null values. |
| | | List<T> _defaultList<T>() => <T>[]; |
| | | Set<T> _defaultSet<T>() => Set<T>(); |
| | | Map<String, T> _defaultMap<T>() => <String, T>{}; |
| | | SimpleObject _defaultSimpleObject() => SimpleObject(42); |
| | | StrictKeysObject _defaultStrictKeysObject() => StrictKeysObject(10, 'cool'); |
| | | |
| | | k.KitchenSink testFactory( |
| | | {int ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) => |
| | | KitchenSink( |
| | | ctorValidatedNo42: ctorValidatedNo42, |
| | | iterable: iterable, |
| | | dynamicIterable: dynamicIterable, |
| | | objectIterable: objectIterable, |
| | | intIterable: intIterable, |
| | | dateTimeIterable: dateTimeIterable); |
| | | |
| | | k.KitchenSink testFromJson(Map json) => KitchenSink.fromJson(json); |
| | | |
| | | @JsonSerializable(nullable: false, anyMap: true, generateToJsonFunction: false) |
| | | class KitchenSink extends Object |
| | | with _$KitchenSinkSerializerMixin |
| | | implements k.KitchenSink { |
| | | // To ensure static members are not considered for serialization. |
| | | static const answer = 42; |
| | | static final reason = 42; |
| | | static int get understand => 42; |
| | | |
| | | // NOTE: exposing these as Iterable, but storing the values as List |
| | | // to make the equality test work trivially. |
| | | final Iterable _iterable; |
| | | final Iterable<dynamic> _dynamicIterable; |
| | | final Iterable<Object> _objectIterable; |
| | | final Iterable<int> _intIterable; |
| | | final Iterable<DateTime> _dateTimeIterable; |
| | | |
| | | @JsonKey(name: 'no-42') |
| | | final int ctorValidatedNo42; |
| | | |
| | | KitchenSink( |
| | | {this.ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) |
| | | : _iterable = iterable?.toList() ?? _defaultList(), |
| | | _dynamicIterable = dynamicIterable?.toList() ?? _defaultList(), |
| | | _objectIterable = objectIterable?.toList() ?? _defaultList(), |
| | | _intIterable = intIterable?.toList() ?? _defaultList(), |
| | | _dateTimeIterable = dateTimeIterable?.toList() ?? _defaultList() { |
| | | if (ctorValidatedNo42 == 42) { |
| | | throw ArgumentError.value( |
| | | 42, 'ctorValidatedNo42', 'The value `42` is not allowed.'); |
| | | } |
| | | } |
| | | |
| | | factory KitchenSink.fromJson(Map json) => _$KitchenSinkFromJson(json); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | DateTime dateTime = DateTime(1981, 6, 5); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | Iterable get iterable => _iterable; |
| | | Iterable<dynamic> get dynamicIterable => _dynamicIterable; |
| | | Iterable<Object> get objectIterable => _objectIterable; |
| | | Iterable<int> get intIterable => _intIterable; |
| | | |
| | | Set set = _defaultSet(); |
| | | Set<dynamic> dynamicSet = _defaultSet(); |
| | | Set<Object> objectSet = _defaultSet(); |
| | | Set<int> intSet = _defaultSet(); |
| | | Set<DateTime> dateTimeSet = _defaultSet(); |
| | | |
| | | // Added a one-off annotation on a property (not a field) |
| | | @JsonKey(name: 'datetime-iterable') |
| | | Iterable<DateTime> get dateTimeIterable => _dateTimeIterable; |
| | | |
| | | List list = _defaultList(); |
| | | List<dynamic> dynamicList = _defaultList(); |
| | | List<Object> objectList = _defaultList(); |
| | | List<int> intList = _defaultList(); |
| | | @JsonKey(includeIfNull: false) |
| | | List<DateTime> dateTimeList = _defaultList(); |
| | | |
| | | Map map = _defaultMap(); |
| | | Map<String, String> stringStringMap = _defaultMap(); |
| | | Map<dynamic, int> dynamicIntMap = _defaultMap(); |
| | | Map<Object, DateTime> objectDateTimeMap = _defaultMap(); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> crazyComplex = |
| | | _defaultList(); |
| | | |
| | | // Handle fields with names that collide with helper names |
| | | @JsonKey(includeIfNull: false) |
| | | Map<String, bool> val = _defaultMap(); |
| | | bool writeNotNull; |
| | | @JsonKey(name: r'$string') |
| | | String string; |
| | | |
| | | SimpleObject simpleObject = _defaultSimpleObject(); |
| | | |
| | | StrictKeysObject strictKeysObject = _defaultStrictKeysObject(); |
| | | |
| | | int _validatedPropertyNo42; |
| | | int get validatedPropertyNo42 => _validatedPropertyNo42; |
| | | |
| | | set validatedPropertyNo42(int value) { |
| | | if (value == 42) { |
| | | throw StateError('Cannot be 42!'); |
| | | } |
| | | _validatedPropertyNo42 = value; |
| | | } |
| | | |
| | | bool operator ==(Object other) => k.sinkEquals(this, other); |
| | | } |
| | | |
| | | @JsonSerializable(nullable: false, anyMap: true, generateToJsonFunction: false) |
| | | // referencing a top-level field should work |
| | | @durationConverter |
| | | // referencing via a const constructor should work |
| | | @BigIntStringConverter() |
| | | @TrivialNumberConverter.instance |
| | | @EpochDateTimeConverter() |
| | | class JsonConverterTestClass extends Object |
| | | with _$JsonConverterTestClassSerializerMixin { |
| | | JsonConverterTestClass(); |
| | | |
| | | factory JsonConverterTestClass.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterTestClassFromJson(json); |
| | | |
| | | Duration duration; |
| | | List<Duration> durationList; |
| | | |
| | | BigInt bigInt; |
| | | Map<String, BigInt> bigIntMap; |
| | | |
| | | TrivialNumber numberSilly; |
| | | Set<TrivialNumber> numberSillySet; |
| | | |
| | | DateTime dateTime = DateTime(1981, 6, 5); |
| | | } |
| | | |
| | | @JsonSerializable(nullable: false, anyMap: true, generateToJsonFunction: false) |
| | | @GenericConverter() |
| | | class JsonConverterGeneric<S, T, U> extends Object |
| | | with _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S item; |
| | | List<T> itemList; |
| | | Map<String, U> itemMap; |
| | | |
| | | JsonConverterGeneric(); |
| | | |
| | | factory JsonConverterGeneric.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterGenericFromJson(json); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'kitchen_sink.non_nullable.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | KitchenSink _$KitchenSinkFromJson(Map json) { |
| | | return KitchenSink( |
| | | ctorValidatedNo42: json['no-42'] as int, |
| | | iterable: json['iterable'] as List, |
| | | dynamicIterable: json['dynamicIterable'] as List, |
| | | objectIterable: json['objectIterable'] as List, |
| | | intIterable: (json['intIterable'] as List).map((e) => e as int), |
| | | dateTimeIterable: (json['datetime-iterable'] as List) |
| | | .map((e) => DateTime.parse(e as String))) |
| | | ..dateTime = DateTime.parse(json['dateTime'] as String) |
| | | ..set = (json['set'] as List).map((e) => e).toSet() |
| | | ..dynamicSet = (json['dynamicSet'] as List).map((e) => e).toSet() |
| | | ..objectSet = (json['objectSet'] as List).map((e) => e).toSet() |
| | | ..intSet = (json['intSet'] as List).map((e) => e as int).toSet() |
| | | ..dateTimeSet = (json['dateTimeSet'] as List) |
| | | .map((e) => DateTime.parse(e as String)) |
| | | .toSet() |
| | | ..list = json['list'] as List |
| | | ..dynamicList = json['dynamicList'] as List |
| | | ..objectList = json['objectList'] as List |
| | | ..intList = (json['intList'] as List).map((e) => e as int).toList() |
| | | ..dateTimeList = (json['dateTimeList'] as List) |
| | | .map((e) => DateTime.parse(e as String)) |
| | | .toList() |
| | | ..map = json['map'] as Map |
| | | ..stringStringMap = Map<String, String>.from(json['stringStringMap'] as Map) |
| | | ..dynamicIntMap = Map<String, int>.from(json['dynamicIntMap'] as Map) |
| | | ..objectDateTimeMap = (json['objectDateTimeMap'] as Map) |
| | | .map((k, e) => MapEntry(k, DateTime.parse(e as String))) |
| | | ..crazyComplex = (json['crazyComplex'] as List) |
| | | .map((e) => (e as Map).map((k, e) => MapEntry( |
| | | k as String, |
| | | (e as Map).map((k, e) => MapEntry( |
| | | k as String, |
| | | (e as List) |
| | | .map((e) => |
| | | (e as List).map((e) => DateTime.parse(e as String)).toList()) |
| | | .toList()))))) |
| | | .toList() |
| | | ..val = Map<String, bool>.from(json['val'] as Map) |
| | | ..writeNotNull = json['writeNotNull'] as bool |
| | | ..string = json[r'$string'] as String |
| | | ..simpleObject = SimpleObject.fromJson(json['simpleObject'] as Map) |
| | | ..strictKeysObject = StrictKeysObject.fromJson(json['strictKeysObject'] as Map) |
| | | ..validatedPropertyNo42 = json['validatedPropertyNo42'] as int; |
| | | } |
| | | |
| | | abstract class _$KitchenSinkSerializerMixin { |
| | | int get ctorValidatedNo42; |
| | | DateTime get dateTime; |
| | | Iterable<dynamic> get iterable; |
| | | Iterable<dynamic> get dynamicIterable; |
| | | Iterable<Object> get objectIterable; |
| | | Iterable<int> get intIterable; |
| | | Set<dynamic> get set; |
| | | Set<dynamic> get dynamicSet; |
| | | Set<Object> get objectSet; |
| | | Set<int> get intSet; |
| | | Set<DateTime> get dateTimeSet; |
| | | Iterable<DateTime> get dateTimeIterable; |
| | | List<dynamic> get list; |
| | | List<dynamic> get dynamicList; |
| | | List<Object> get objectList; |
| | | List<int> get intList; |
| | | List<DateTime> get dateTimeList; |
| | | Map<dynamic, dynamic> get map; |
| | | Map<String, String> get stringStringMap; |
| | | Map<dynamic, int> get dynamicIntMap; |
| | | Map<Object, DateTime> get objectDateTimeMap; |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> get crazyComplex; |
| | | Map<String, bool> get val; |
| | | bool get writeNotNull; |
| | | String get string; |
| | | SimpleObject get simpleObject; |
| | | StrictKeysObject get strictKeysObject; |
| | | int get validatedPropertyNo42; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{ |
| | | 'no-42': ctorValidatedNo42, |
| | | 'dateTime': dateTime.toIso8601String(), |
| | | 'iterable': iterable.toList(), |
| | | 'dynamicIterable': dynamicIterable.toList(), |
| | | 'objectIterable': objectIterable.toList(), |
| | | 'intIterable': intIterable.toList(), |
| | | 'set': set.toList(), |
| | | 'dynamicSet': dynamicSet.toList(), |
| | | 'objectSet': objectSet.toList(), |
| | | 'intSet': intSet.toList(), |
| | | 'dateTimeSet': dateTimeSet.map((e) => e.toIso8601String()).toList(), |
| | | 'datetime-iterable': |
| | | dateTimeIterable.map((e) => e.toIso8601String()).toList(), |
| | | 'list': list, |
| | | 'dynamicList': dynamicList, |
| | | 'objectList': objectList, |
| | | 'intList': intList, |
| | | 'dateTimeList': dateTimeList.map((e) => e.toIso8601String()).toList(), |
| | | 'map': map, |
| | | 'stringStringMap': stringStringMap, |
| | | 'dynamicIntMap': dynamicIntMap, |
| | | 'objectDateTimeMap': |
| | | objectDateTimeMap.map((k, e) => MapEntry(k, e.toIso8601String())), |
| | | 'crazyComplex': crazyComplex |
| | | .map((e) => e.map((k, e) => MapEntry( |
| | | k, |
| | | e.map((k, e) => MapEntry( |
| | | k, |
| | | e |
| | | .map((e) => e.map((e) => e.toIso8601String()).toList()) |
| | | .toList()))))) |
| | | .toList(), |
| | | 'val': val, |
| | | 'writeNotNull': writeNotNull, |
| | | r'$string': string, |
| | | 'simpleObject': simpleObject, |
| | | 'strictKeysObject': strictKeysObject, |
| | | 'validatedPropertyNo42': validatedPropertyNo42 |
| | | }; |
| | | } |
| | | |
| | | JsonConverterTestClass _$JsonConverterTestClassFromJson(Map json) { |
| | | return JsonConverterTestClass() |
| | | ..duration = durationConverter.fromJson(json['duration'] as int) |
| | | ..durationList = (json['durationList'] as List) |
| | | .map((e) => durationConverter.fromJson(e as int)) |
| | | .toList() |
| | | ..bigInt = const BigIntStringConverter().fromJson(json['bigInt'] as String) |
| | | ..bigIntMap = (json['bigIntMap'] as Map).map((k, e) => MapEntry( |
| | | k as String, const BigIntStringConverter().fromJson(e as String))) |
| | | ..numberSilly = |
| | | TrivialNumberConverter.instance.fromJson(json['numberSilly'] as int) |
| | | ..numberSillySet = (json['numberSillySet'] as List) |
| | | .map((e) => TrivialNumberConverter.instance.fromJson(e as int)) |
| | | .toSet() |
| | | ..dateTime = |
| | | const EpochDateTimeConverter().fromJson(json['dateTime'] as int); |
| | | } |
| | | |
| | | abstract class _$JsonConverterTestClassSerializerMixin { |
| | | Duration get duration; |
| | | List<Duration> get durationList; |
| | | BigInt get bigInt; |
| | | Map<String, BigInt> get bigIntMap; |
| | | TrivialNumber get numberSilly; |
| | | Set<TrivialNumber> get numberSillySet; |
| | | DateTime get dateTime; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{ |
| | | 'duration': durationConverter.toJson(duration), |
| | | 'durationList': durationList.map(durationConverter.toJson).toList(), |
| | | 'bigInt': const BigIntStringConverter().toJson(bigInt), |
| | | 'bigIntMap': bigIntMap.map( |
| | | (k, e) => MapEntry(k, const BigIntStringConverter().toJson(e))), |
| | | 'numberSilly': TrivialNumberConverter.instance.toJson(numberSilly), |
| | | 'numberSillySet': |
| | | numberSillySet.map(TrivialNumberConverter.instance.toJson).toList(), |
| | | 'dateTime': const EpochDateTimeConverter().toJson(dateTime) |
| | | }; |
| | | } |
| | | |
| | | JsonConverterGeneric<S, T, U> _$JsonConverterGenericFromJson<S, T, U>( |
| | | Map json) { |
| | | return JsonConverterGeneric<S, T, U>() |
| | | ..item = |
| | | GenericConverter<S>().fromJson(json['item'] as Map<String, dynamic>) |
| | | ..itemList = (json['itemList'] as List) |
| | | .map((e) => GenericConverter<T>().fromJson(e as Map<String, dynamic>)) |
| | | .toList() |
| | | ..itemMap = (json['itemMap'] as Map).map((k, e) => MapEntry(k as String, |
| | | GenericConverter<U>().fromJson(e as Map<String, dynamic>))); |
| | | } |
| | | |
| | | abstract class _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S get item; |
| | | List<T> get itemList; |
| | | Map<String, U> get itemMap; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{ |
| | | 'item': GenericConverter<S>().toJson(item), |
| | | 'itemList': itemList.map(GenericConverter<T>().toJson).toList(), |
| | | 'itemMap': |
| | | itemMap.map((k, e) => MapEntry(k, GenericConverter<U>().toJson(e))) |
| | | }; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _WrappedGenerator |
| | | // ************************************************************************** |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _NonNullableGenerator |
| | | // ************************************************************************** |
| | | |
| | | // ignore_for_file: annotate_overrides, hash_and_equals |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'json_converters.dart'; |
| | | import 'kitchen_sink_interface.dart' as k; |
| | | import 'simple_object.dart'; |
| | | import 'strict_keys_object.dart'; |
| | | |
| | | part 'kitchen_sink.non_nullable.wrapped.g.dart'; |
| | | |
| | | // NOTE: these methods are replaced in the `non_nullable` cases to return |
| | | // non-null values. |
| | | List<T> _defaultList<T>() => <T>[]; |
| | | Set<T> _defaultSet<T>() => Set<T>(); |
| | | Map<String, T> _defaultMap<T>() => <String, T>{}; |
| | | SimpleObject _defaultSimpleObject() => SimpleObject(42); |
| | | StrictKeysObject _defaultStrictKeysObject() => StrictKeysObject(10, 'cool'); |
| | | |
| | | k.KitchenSink testFactory( |
| | | {int ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) => |
| | | KitchenSink( |
| | | ctorValidatedNo42: ctorValidatedNo42, |
| | | iterable: iterable, |
| | | dynamicIterable: dynamicIterable, |
| | | objectIterable: objectIterable, |
| | | intIterable: intIterable, |
| | | dateTimeIterable: dateTimeIterable); |
| | | |
| | | k.KitchenSink testFromJson(Map json) => KitchenSink.fromJson(json); |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | nullable: false, |
| | | anyMap: true, |
| | | generateToJsonFunction: false) |
| | | class KitchenSink extends Object |
| | | with _$KitchenSinkSerializerMixin |
| | | implements k.KitchenSink { |
| | | // To ensure static members are not considered for serialization. |
| | | static const answer = 42; |
| | | static final reason = 42; |
| | | static int get understand => 42; |
| | | |
| | | // NOTE: exposing these as Iterable, but storing the values as List |
| | | // to make the equality test work trivially. |
| | | final Iterable _iterable; |
| | | final Iterable<dynamic> _dynamicIterable; |
| | | final Iterable<Object> _objectIterable; |
| | | final Iterable<int> _intIterable; |
| | | final Iterable<DateTime> _dateTimeIterable; |
| | | |
| | | @JsonKey(name: 'no-42') |
| | | final int ctorValidatedNo42; |
| | | |
| | | KitchenSink( |
| | | {this.ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) |
| | | : _iterable = iterable?.toList() ?? _defaultList(), |
| | | _dynamicIterable = dynamicIterable?.toList() ?? _defaultList(), |
| | | _objectIterable = objectIterable?.toList() ?? _defaultList(), |
| | | _intIterable = intIterable?.toList() ?? _defaultList(), |
| | | _dateTimeIterable = dateTimeIterable?.toList() ?? _defaultList() { |
| | | if (ctorValidatedNo42 == 42) { |
| | | throw ArgumentError.value( |
| | | 42, 'ctorValidatedNo42', 'The value `42` is not allowed.'); |
| | | } |
| | | } |
| | | |
| | | factory KitchenSink.fromJson(Map json) => _$KitchenSinkFromJson(json); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | DateTime dateTime = DateTime(1981, 6, 5); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | Iterable get iterable => _iterable; |
| | | Iterable<dynamic> get dynamicIterable => _dynamicIterable; |
| | | Iterable<Object> get objectIterable => _objectIterable; |
| | | Iterable<int> get intIterable => _intIterable; |
| | | |
| | | Set set = _defaultSet(); |
| | | Set<dynamic> dynamicSet = _defaultSet(); |
| | | Set<Object> objectSet = _defaultSet(); |
| | | Set<int> intSet = _defaultSet(); |
| | | Set<DateTime> dateTimeSet = _defaultSet(); |
| | | |
| | | // Added a one-off annotation on a property (not a field) |
| | | @JsonKey(name: 'datetime-iterable') |
| | | Iterable<DateTime> get dateTimeIterable => _dateTimeIterable; |
| | | |
| | | List list = _defaultList(); |
| | | List<dynamic> dynamicList = _defaultList(); |
| | | List<Object> objectList = _defaultList(); |
| | | List<int> intList = _defaultList(); |
| | | @JsonKey(includeIfNull: false) |
| | | List<DateTime> dateTimeList = _defaultList(); |
| | | |
| | | Map map = _defaultMap(); |
| | | Map<String, String> stringStringMap = _defaultMap(); |
| | | Map<dynamic, int> dynamicIntMap = _defaultMap(); |
| | | Map<Object, DateTime> objectDateTimeMap = _defaultMap(); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> crazyComplex = |
| | | _defaultList(); |
| | | |
| | | // Handle fields with names that collide with helper names |
| | | @JsonKey(includeIfNull: false) |
| | | Map<String, bool> val = _defaultMap(); |
| | | bool writeNotNull; |
| | | @JsonKey(name: r'$string') |
| | | String string; |
| | | |
| | | SimpleObject simpleObject = _defaultSimpleObject(); |
| | | |
| | | StrictKeysObject strictKeysObject = _defaultStrictKeysObject(); |
| | | |
| | | int _validatedPropertyNo42; |
| | | int get validatedPropertyNo42 => _validatedPropertyNo42; |
| | | |
| | | set validatedPropertyNo42(int value) { |
| | | if (value == 42) { |
| | | throw StateError('Cannot be 42!'); |
| | | } |
| | | _validatedPropertyNo42 = value; |
| | | } |
| | | |
| | | bool operator ==(Object other) => k.sinkEquals(this, other); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | nullable: false, |
| | | anyMap: true, |
| | | generateToJsonFunction: false) |
| | | // referencing a top-level field should work |
| | | @durationConverter |
| | | // referencing via a const constructor should work |
| | | @BigIntStringConverter() |
| | | @TrivialNumberConverter.instance |
| | | @EpochDateTimeConverter() |
| | | class JsonConverterTestClass extends Object |
| | | with _$JsonConverterTestClassSerializerMixin { |
| | | JsonConverterTestClass(); |
| | | |
| | | factory JsonConverterTestClass.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterTestClassFromJson(json); |
| | | |
| | | Duration duration; |
| | | List<Duration> durationList; |
| | | |
| | | BigInt bigInt; |
| | | Map<String, BigInt> bigIntMap; |
| | | |
| | | TrivialNumber numberSilly; |
| | | Set<TrivialNumber> numberSillySet; |
| | | |
| | | DateTime dateTime = DateTime(1981, 6, 5); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, |
| | | nullable: false, |
| | | anyMap: true, |
| | | generateToJsonFunction: false) |
| | | @GenericConverter() |
| | | class JsonConverterGeneric<S, T, U> extends Object |
| | | with _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S item; |
| | | List<T> itemList; |
| | | Map<String, U> itemMap; |
| | | |
| | | JsonConverterGeneric(); |
| | | |
| | | factory JsonConverterGeneric.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterGenericFromJson(json); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'kitchen_sink.non_nullable.wrapped.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | KitchenSink _$KitchenSinkFromJson(Map json) { |
| | | return KitchenSink( |
| | | ctorValidatedNo42: json['no-42'] as int, |
| | | iterable: json['iterable'] as List, |
| | | dynamicIterable: json['dynamicIterable'] as List, |
| | | objectIterable: json['objectIterable'] as List, |
| | | intIterable: (json['intIterable'] as List).map((e) => e as int), |
| | | dateTimeIterable: (json['datetime-iterable'] as List) |
| | | .map((e) => DateTime.parse(e as String))) |
| | | ..dateTime = DateTime.parse(json['dateTime'] as String) |
| | | ..set = (json['set'] as List).map((e) => e).toSet() |
| | | ..dynamicSet = (json['dynamicSet'] as List).map((e) => e).toSet() |
| | | ..objectSet = (json['objectSet'] as List).map((e) => e).toSet() |
| | | ..intSet = (json['intSet'] as List).map((e) => e as int).toSet() |
| | | ..dateTimeSet = (json['dateTimeSet'] as List) |
| | | .map((e) => DateTime.parse(e as String)) |
| | | .toSet() |
| | | ..list = json['list'] as List |
| | | ..dynamicList = json['dynamicList'] as List |
| | | ..objectList = json['objectList'] as List |
| | | ..intList = (json['intList'] as List).map((e) => e as int).toList() |
| | | ..dateTimeList = (json['dateTimeList'] as List) |
| | | .map((e) => DateTime.parse(e as String)) |
| | | .toList() |
| | | ..map = json['map'] as Map |
| | | ..stringStringMap = Map<String, String>.from(json['stringStringMap'] as Map) |
| | | ..dynamicIntMap = Map<String, int>.from(json['dynamicIntMap'] as Map) |
| | | ..objectDateTimeMap = (json['objectDateTimeMap'] as Map) |
| | | .map((k, e) => MapEntry(k, DateTime.parse(e as String))) |
| | | ..crazyComplex = (json['crazyComplex'] as List) |
| | | .map((e) => (e as Map).map((k, e) => MapEntry( |
| | | k as String, |
| | | (e as Map).map((k, e) => MapEntry( |
| | | k as String, |
| | | (e as List) |
| | | .map((e) => |
| | | (e as List).map((e) => DateTime.parse(e as String)).toList()) |
| | | .toList()))))) |
| | | .toList() |
| | | ..val = Map<String, bool>.from(json['val'] as Map) |
| | | ..writeNotNull = json['writeNotNull'] as bool |
| | | ..string = json[r'$string'] as String |
| | | ..simpleObject = SimpleObject.fromJson(json['simpleObject'] as Map) |
| | | ..strictKeysObject = StrictKeysObject.fromJson(json['strictKeysObject'] as Map) |
| | | ..validatedPropertyNo42 = json['validatedPropertyNo42'] as int; |
| | | } |
| | | |
| | | abstract class _$KitchenSinkSerializerMixin { |
| | | int get ctorValidatedNo42; |
| | | DateTime get dateTime; |
| | | Iterable<dynamic> get iterable; |
| | | Iterable<dynamic> get dynamicIterable; |
| | | Iterable<Object> get objectIterable; |
| | | Iterable<int> get intIterable; |
| | | Set<dynamic> get set; |
| | | Set<dynamic> get dynamicSet; |
| | | Set<Object> get objectSet; |
| | | Set<int> get intSet; |
| | | Set<DateTime> get dateTimeSet; |
| | | Iterable<DateTime> get dateTimeIterable; |
| | | List<dynamic> get list; |
| | | List<dynamic> get dynamicList; |
| | | List<Object> get objectList; |
| | | List<int> get intList; |
| | | List<DateTime> get dateTimeList; |
| | | Map<dynamic, dynamic> get map; |
| | | Map<String, String> get stringStringMap; |
| | | Map<dynamic, int> get dynamicIntMap; |
| | | Map<Object, DateTime> get objectDateTimeMap; |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> get crazyComplex; |
| | | Map<String, bool> get val; |
| | | bool get writeNotNull; |
| | | String get string; |
| | | SimpleObject get simpleObject; |
| | | StrictKeysObject get strictKeysObject; |
| | | int get validatedPropertyNo42; |
| | | Map<String, dynamic> toJson() => _$KitchenSinkJsonMapWrapper(this); |
| | | } |
| | | |
| | | class _$KitchenSinkJsonMapWrapper extends $JsonMapWrapper { |
| | | final _$KitchenSinkSerializerMixin _v; |
| | | _$KitchenSinkJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const [ |
| | | 'no-42', |
| | | 'dateTime', |
| | | 'iterable', |
| | | 'dynamicIterable', |
| | | 'objectIterable', |
| | | 'intIterable', |
| | | 'set', |
| | | 'dynamicSet', |
| | | 'objectSet', |
| | | 'intSet', |
| | | 'dateTimeSet', |
| | | 'datetime-iterable', |
| | | 'list', |
| | | 'dynamicList', |
| | | 'objectList', |
| | | 'intList', |
| | | 'dateTimeList', |
| | | 'map', |
| | | 'stringStringMap', |
| | | 'dynamicIntMap', |
| | | 'objectDateTimeMap', |
| | | 'crazyComplex', |
| | | 'val', |
| | | 'writeNotNull', |
| | | r'$string', |
| | | 'simpleObject', |
| | | 'strictKeysObject', |
| | | 'validatedPropertyNo42' |
| | | ]; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'no-42': |
| | | return _v.ctorValidatedNo42; |
| | | case 'dateTime': |
| | | return _v.dateTime.toIso8601String(); |
| | | case 'iterable': |
| | | return _v.iterable.toList(); |
| | | case 'dynamicIterable': |
| | | return _v.dynamicIterable.toList(); |
| | | case 'objectIterable': |
| | | return _v.objectIterable.toList(); |
| | | case 'intIterable': |
| | | return _v.intIterable.toList(); |
| | | case 'set': |
| | | return _v.set.toList(); |
| | | case 'dynamicSet': |
| | | return _v.dynamicSet.toList(); |
| | | case 'objectSet': |
| | | return _v.objectSet.toList(); |
| | | case 'intSet': |
| | | return _v.intSet.toList(); |
| | | case 'dateTimeSet': |
| | | return _v.dateTimeSet.map((e) => e.toIso8601String()).toList(); |
| | | case 'datetime-iterable': |
| | | return _v.dateTimeIterable.map((e) => e.toIso8601String()).toList(); |
| | | case 'list': |
| | | return _v.list; |
| | | case 'dynamicList': |
| | | return _v.dynamicList; |
| | | case 'objectList': |
| | | return _v.objectList; |
| | | case 'intList': |
| | | return _v.intList; |
| | | case 'dateTimeList': |
| | | return $wrapList<DateTime>( |
| | | _v.dateTimeList, (e) => e.toIso8601String()); |
| | | case 'map': |
| | | return _v.map; |
| | | case 'stringStringMap': |
| | | return _v.stringStringMap; |
| | | case 'dynamicIntMap': |
| | | return _v.dynamicIntMap; |
| | | case 'objectDateTimeMap': |
| | | return $wrapMap<Object, DateTime>( |
| | | _v.objectDateTimeMap, (e) => e.toIso8601String()); |
| | | case 'crazyComplex': |
| | | return $wrapList<Map<String, Map<String, List<List<DateTime>>>>>( |
| | | _v.crazyComplex, |
| | | (e) => $wrapMap<String, Map<String, List<List<DateTime>>>>( |
| | | e, |
| | | (e) => $wrapMap<String, List<List<DateTime>>>( |
| | | e, |
| | | (e) => $wrapList<List<DateTime>>( |
| | | e, |
| | | (e) => $wrapList<DateTime>( |
| | | e, (e) => e.toIso8601String()))))); |
| | | case 'val': |
| | | return _v.val; |
| | | case 'writeNotNull': |
| | | return _v.writeNotNull; |
| | | case r'$string': |
| | | return _v.string; |
| | | case 'simpleObject': |
| | | return _v.simpleObject; |
| | | case 'strictKeysObject': |
| | | return _v.strictKeysObject; |
| | | case 'validatedPropertyNo42': |
| | | return _v.validatedPropertyNo42; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | JsonConverterTestClass _$JsonConverterTestClassFromJson(Map json) { |
| | | return JsonConverterTestClass() |
| | | ..duration = durationConverter.fromJson(json['duration'] as int) |
| | | ..durationList = (json['durationList'] as List) |
| | | .map((e) => durationConverter.fromJson(e as int)) |
| | | .toList() |
| | | ..bigInt = const BigIntStringConverter().fromJson(json['bigInt'] as String) |
| | | ..bigIntMap = (json['bigIntMap'] as Map).map((k, e) => MapEntry( |
| | | k as String, const BigIntStringConverter().fromJson(e as String))) |
| | | ..numberSilly = |
| | | TrivialNumberConverter.instance.fromJson(json['numberSilly'] as int) |
| | | ..numberSillySet = (json['numberSillySet'] as List) |
| | | .map((e) => TrivialNumberConverter.instance.fromJson(e as int)) |
| | | .toSet() |
| | | ..dateTime = |
| | | const EpochDateTimeConverter().fromJson(json['dateTime'] as int); |
| | | } |
| | | |
| | | abstract class _$JsonConverterTestClassSerializerMixin { |
| | | Duration get duration; |
| | | List<Duration> get durationList; |
| | | BigInt get bigInt; |
| | | Map<String, BigInt> get bigIntMap; |
| | | TrivialNumber get numberSilly; |
| | | Set<TrivialNumber> get numberSillySet; |
| | | DateTime get dateTime; |
| | | Map<String, dynamic> toJson() => _$JsonConverterTestClassJsonMapWrapper(this); |
| | | } |
| | | |
| | | class _$JsonConverterTestClassJsonMapWrapper extends $JsonMapWrapper { |
| | | final _$JsonConverterTestClassSerializerMixin _v; |
| | | _$JsonConverterTestClassJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const [ |
| | | 'duration', |
| | | 'durationList', |
| | | 'bigInt', |
| | | 'bigIntMap', |
| | | 'numberSilly', |
| | | 'numberSillySet', |
| | | 'dateTime' |
| | | ]; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'duration': |
| | | return durationConverter.toJson(_v.duration); |
| | | case 'durationList': |
| | | return $wrapList<Duration>(_v.durationList, durationConverter.toJson); |
| | | case 'bigInt': |
| | | return const BigIntStringConverter().toJson(_v.bigInt); |
| | | case 'bigIntMap': |
| | | return $wrapMap<String, BigInt>( |
| | | _v.bigIntMap, const BigIntStringConverter().toJson); |
| | | case 'numberSilly': |
| | | return TrivialNumberConverter.instance.toJson(_v.numberSilly); |
| | | case 'numberSillySet': |
| | | return _v.numberSillySet |
| | | .map(TrivialNumberConverter.instance.toJson) |
| | | .toList(); |
| | | case 'dateTime': |
| | | return const EpochDateTimeConverter().toJson(_v.dateTime); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | JsonConverterGeneric<S, T, U> _$JsonConverterGenericFromJson<S, T, U>( |
| | | Map json) { |
| | | return JsonConverterGeneric<S, T, U>() |
| | | ..item = |
| | | GenericConverter<S>().fromJson(json['item'] as Map<String, dynamic>) |
| | | ..itemList = (json['itemList'] as List) |
| | | .map((e) => GenericConverter<T>().fromJson(e as Map<String, dynamic>)) |
| | | .toList() |
| | | ..itemMap = (json['itemMap'] as Map).map((k, e) => MapEntry(k as String, |
| | | GenericConverter<U>().fromJson(e as Map<String, dynamic>))); |
| | | } |
| | | |
| | | abstract class _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S get item; |
| | | List<T> get itemList; |
| | | Map<String, U> get itemMap; |
| | | Map<String, dynamic> toJson() => |
| | | _$JsonConverterGenericJsonMapWrapper<S, T, U>(this); |
| | | } |
| | | |
| | | class _$JsonConverterGenericJsonMapWrapper<S, T, U> extends $JsonMapWrapper { |
| | | final _$JsonConverterGenericSerializerMixin<S, T, U> _v; |
| | | _$JsonConverterGenericJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const ['item', 'itemList', 'itemMap']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'item': |
| | | return GenericConverter<S>().toJson(_v.item); |
| | | case 'itemList': |
| | | return $wrapList<T>(_v.itemList, GenericConverter<T>().toJson); |
| | | case 'itemMap': |
| | | return $wrapMap<String, U>(_v.itemMap, GenericConverter<U>().toJson); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | // ************************************************************************** |
| | | // _WrappedGenerator |
| | | // ************************************************************************** |
| | | |
| | | // ignore_for_file: annotate_overrides, hash_and_equals |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'json_converters.dart'; |
| | | import 'kitchen_sink_interface.dart' as k; |
| | | import 'simple_object.dart'; |
| | | import 'strict_keys_object.dart'; |
| | | |
| | | part 'kitchen_sink.wrapped.g.dart'; |
| | | |
| | | // NOTE: these methods are replaced in the `non_nullable` cases to return |
| | | // non-null values. |
| | | List<T> _defaultList<T>() => null; |
| | | Set<T> _defaultSet<T>() => null; |
| | | Map _defaultMap() => null; |
| | | SimpleObject _defaultSimpleObject() => null; |
| | | StrictKeysObject _defaultStrictKeysObject() => null; |
| | | |
| | | k.KitchenSink testFactory( |
| | | {int ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) => |
| | | KitchenSink( |
| | | ctorValidatedNo42: ctorValidatedNo42, |
| | | iterable: iterable, |
| | | dynamicIterable: dynamicIterable, |
| | | objectIterable: objectIterable, |
| | | intIterable: intIterable, |
| | | dateTimeIterable: dateTimeIterable); |
| | | |
| | | k.KitchenSink testFromJson(Map json) => KitchenSink.fromJson(json); |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, anyMap: true, generateToJsonFunction: false) |
| | | class KitchenSink extends Object |
| | | with _$KitchenSinkSerializerMixin |
| | | implements k.KitchenSink { |
| | | // To ensure static members are not considered for serialization. |
| | | static const answer = 42; |
| | | static final reason = 42; |
| | | static int get understand => 42; |
| | | |
| | | // NOTE: exposing these as Iterable, but storing the values as List |
| | | // to make the equality test work trivially. |
| | | final Iterable _iterable; |
| | | final Iterable<dynamic> _dynamicIterable; |
| | | final Iterable<Object> _objectIterable; |
| | | final Iterable<int> _intIterable; |
| | | final Iterable<DateTime> _dateTimeIterable; |
| | | |
| | | @JsonKey(name: 'no-42') |
| | | final int ctorValidatedNo42; |
| | | |
| | | KitchenSink( |
| | | {this.ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}) |
| | | : _iterable = iterable?.toList() ?? _defaultList(), |
| | | _dynamicIterable = dynamicIterable?.toList() ?? _defaultList(), |
| | | _objectIterable = objectIterable?.toList() ?? _defaultList(), |
| | | _intIterable = intIterable?.toList() ?? _defaultList(), |
| | | _dateTimeIterable = dateTimeIterable?.toList() ?? _defaultList() { |
| | | if (ctorValidatedNo42 == 42) { |
| | | throw ArgumentError.value( |
| | | 42, 'ctorValidatedNo42', 'The value `42` is not allowed.'); |
| | | } |
| | | } |
| | | |
| | | factory KitchenSink.fromJson(Map json) => _$KitchenSinkFromJson(json); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | DateTime dateTime; |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | Iterable get iterable => _iterable; |
| | | Iterable<dynamic> get dynamicIterable => _dynamicIterable; |
| | | Iterable<Object> get objectIterable => _objectIterable; |
| | | Iterable<int> get intIterable => _intIterable; |
| | | |
| | | Set set = _defaultSet(); |
| | | Set<dynamic> dynamicSet = _defaultSet(); |
| | | Set<Object> objectSet = _defaultSet(); |
| | | Set<int> intSet = _defaultSet(); |
| | | Set<DateTime> dateTimeSet = _defaultSet(); |
| | | |
| | | // Added a one-off annotation on a property (not a field) |
| | | @JsonKey(name: 'datetime-iterable') |
| | | Iterable<DateTime> get dateTimeIterable => _dateTimeIterable; |
| | | |
| | | List list = _defaultList(); |
| | | List<dynamic> dynamicList = _defaultList(); |
| | | List<Object> objectList = _defaultList(); |
| | | List<int> intList = _defaultList(); |
| | | @JsonKey(includeIfNull: false) |
| | | List<DateTime> dateTimeList = _defaultList(); |
| | | |
| | | Map map = _defaultMap(); |
| | | Map<String, String> stringStringMap = _defaultMap(); |
| | | Map<dynamic, int> dynamicIntMap = _defaultMap(); |
| | | Map<Object, DateTime> objectDateTimeMap = _defaultMap(); |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> crazyComplex = |
| | | _defaultList(); |
| | | |
| | | // Handle fields with names that collide with helper names |
| | | @JsonKey(includeIfNull: false) |
| | | Map<String, bool> val = _defaultMap(); |
| | | bool writeNotNull; |
| | | @JsonKey(name: r'$string') |
| | | String string; |
| | | |
| | | SimpleObject simpleObject = _defaultSimpleObject(); |
| | | |
| | | StrictKeysObject strictKeysObject = _defaultStrictKeysObject(); |
| | | |
| | | int _validatedPropertyNo42; |
| | | int get validatedPropertyNo42 => _validatedPropertyNo42; |
| | | |
| | | set validatedPropertyNo42(int value) { |
| | | if (value == 42) { |
| | | throw StateError('Cannot be 42!'); |
| | | } |
| | | _validatedPropertyNo42 = value; |
| | | } |
| | | |
| | | bool operator ==(Object other) => k.sinkEquals(this, other); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, anyMap: true, generateToJsonFunction: false) |
| | | // referencing a top-level field should work |
| | | @durationConverter |
| | | // referencing via a const constructor should work |
| | | @BigIntStringConverter() |
| | | @TrivialNumberConverter.instance |
| | | @EpochDateTimeConverter() |
| | | class JsonConverterTestClass extends Object |
| | | with _$JsonConverterTestClassSerializerMixin { |
| | | JsonConverterTestClass(); |
| | | |
| | | factory JsonConverterTestClass.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterTestClassFromJson(json); |
| | | |
| | | Duration duration; |
| | | List<Duration> durationList; |
| | | |
| | | BigInt bigInt; |
| | | Map<String, BigInt> bigIntMap; |
| | | |
| | | TrivialNumber numberSilly; |
| | | Set<TrivialNumber> numberSillySet; |
| | | |
| | | DateTime dateTime; |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | useWrappers: true, anyMap: true, generateToJsonFunction: false) |
| | | @GenericConverter() |
| | | class JsonConverterGeneric<S, T, U> extends Object |
| | | with _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S item; |
| | | List<T> itemList; |
| | | Map<String, U> itemMap; |
| | | |
| | | JsonConverterGeneric(); |
| | | |
| | | factory JsonConverterGeneric.fromJson(Map<String, dynamic> json) => |
| | | _$JsonConverterGenericFromJson(json); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'kitchen_sink.wrapped.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | KitchenSink _$KitchenSinkFromJson(Map json) { |
| | | return KitchenSink( |
| | | ctorValidatedNo42: json['no-42'] as int, |
| | | iterable: json['iterable'] as List, |
| | | dynamicIterable: json['dynamicIterable'] as List, |
| | | objectIterable: json['objectIterable'] as List, |
| | | intIterable: (json['intIterable'] as List)?.map((e) => e as int), |
| | | dateTimeIterable: (json['datetime-iterable'] as List) |
| | | ?.map((e) => e == null ? null : DateTime.parse(e as String))) |
| | | ..dateTime = json['dateTime'] == null |
| | | ? null |
| | | : DateTime.parse(json['dateTime'] as String) |
| | | ..set = (json['set'] as List)?.map((e) => e)?.toSet() |
| | | ..dynamicSet = (json['dynamicSet'] as List)?.map((e) => e)?.toSet() |
| | | ..objectSet = (json['objectSet'] as List)?.map((e) => e)?.toSet() |
| | | ..intSet = (json['intSet'] as List)?.map((e) => e as int)?.toSet() |
| | | ..dateTimeSet = (json['dateTimeSet'] as List) |
| | | ?.map((e) => e == null ? null : DateTime.parse(e as String)) |
| | | ?.toSet() |
| | | ..list = json['list'] as List |
| | | ..dynamicList = json['dynamicList'] as List |
| | | ..objectList = json['objectList'] as List |
| | | ..intList = (json['intList'] as List)?.map((e) => e as int)?.toList() |
| | | ..dateTimeList = (json['dateTimeList'] as List) |
| | | ?.map((e) => e == null ? null : DateTime.parse(e as String)) |
| | | ?.toList() |
| | | ..map = json['map'] as Map |
| | | ..stringStringMap = (json['stringStringMap'] as Map) |
| | | ?.map((k, e) => MapEntry(k as String, e as String)) |
| | | ..dynamicIntMap = |
| | | (json['dynamicIntMap'] as Map)?.map((k, e) => MapEntry(k, e as int)) |
| | | ..objectDateTimeMap = (json['objectDateTimeMap'] as Map)?.map( |
| | | (k, e) => MapEntry(k, e == null ? null : DateTime.parse(e as String))) |
| | | ..crazyComplex = (json['crazyComplex'] as List) |
| | | ?.map((e) => (e as Map)?.map((k, e) => MapEntry( |
| | | k as String, |
| | | (e as Map)?.map((k, e) => MapEntry(k as String, |
| | | (e as List)?.map((e) => (e as List)?.map((e) => e == null ? null : DateTime.parse(e as String))?.toList())?.toList()))))) |
| | | ?.toList() |
| | | ..val = (json['val'] as Map)?.map((k, e) => MapEntry(k as String, e as bool)) |
| | | ..writeNotNull = json['writeNotNull'] as bool |
| | | ..string = json[r'$string'] as String |
| | | ..simpleObject = json['simpleObject'] == null ? null : SimpleObject.fromJson(json['simpleObject'] as Map) |
| | | ..strictKeysObject = json['strictKeysObject'] == null ? null : StrictKeysObject.fromJson(json['strictKeysObject'] as Map) |
| | | ..validatedPropertyNo42 = json['validatedPropertyNo42'] as int; |
| | | } |
| | | |
| | | abstract class _$KitchenSinkSerializerMixin { |
| | | int get ctorValidatedNo42; |
| | | DateTime get dateTime; |
| | | Iterable<dynamic> get iterable; |
| | | Iterable<dynamic> get dynamicIterable; |
| | | Iterable<Object> get objectIterable; |
| | | Iterable<int> get intIterable; |
| | | Set<dynamic> get set; |
| | | Set<dynamic> get dynamicSet; |
| | | Set<Object> get objectSet; |
| | | Set<int> get intSet; |
| | | Set<DateTime> get dateTimeSet; |
| | | Iterable<DateTime> get dateTimeIterable; |
| | | List<dynamic> get list; |
| | | List<dynamic> get dynamicList; |
| | | List<Object> get objectList; |
| | | List<int> get intList; |
| | | List<DateTime> get dateTimeList; |
| | | Map<dynamic, dynamic> get map; |
| | | Map<String, String> get stringStringMap; |
| | | Map<dynamic, int> get dynamicIntMap; |
| | | Map<Object, DateTime> get objectDateTimeMap; |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> get crazyComplex; |
| | | Map<String, bool> get val; |
| | | bool get writeNotNull; |
| | | String get string; |
| | | SimpleObject get simpleObject; |
| | | StrictKeysObject get strictKeysObject; |
| | | int get validatedPropertyNo42; |
| | | Map<String, dynamic> toJson() => _$KitchenSinkJsonMapWrapper(this); |
| | | } |
| | | |
| | | class _$KitchenSinkJsonMapWrapper extends $JsonMapWrapper { |
| | | final _$KitchenSinkSerializerMixin _v; |
| | | _$KitchenSinkJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys sync* { |
| | | yield 'no-42'; |
| | | if (_v.dateTime != null) { |
| | | yield 'dateTime'; |
| | | } |
| | | if (_v.iterable != null) { |
| | | yield 'iterable'; |
| | | } |
| | | yield 'dynamicIterable'; |
| | | yield 'objectIterable'; |
| | | yield 'intIterable'; |
| | | yield 'set'; |
| | | yield 'dynamicSet'; |
| | | yield 'objectSet'; |
| | | yield 'intSet'; |
| | | yield 'dateTimeSet'; |
| | | yield 'datetime-iterable'; |
| | | yield 'list'; |
| | | yield 'dynamicList'; |
| | | yield 'objectList'; |
| | | yield 'intList'; |
| | | if (_v.dateTimeList != null) { |
| | | yield 'dateTimeList'; |
| | | } |
| | | yield 'map'; |
| | | yield 'stringStringMap'; |
| | | yield 'dynamicIntMap'; |
| | | yield 'objectDateTimeMap'; |
| | | if (_v.crazyComplex != null) { |
| | | yield 'crazyComplex'; |
| | | } |
| | | if (_v.val != null) { |
| | | yield 'val'; |
| | | } |
| | | yield 'writeNotNull'; |
| | | yield r'$string'; |
| | | yield 'simpleObject'; |
| | | yield 'strictKeysObject'; |
| | | yield 'validatedPropertyNo42'; |
| | | } |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'no-42': |
| | | return _v.ctorValidatedNo42; |
| | | case 'dateTime': |
| | | return _v.dateTime?.toIso8601String(); |
| | | case 'iterable': |
| | | return _v.iterable?.toList(); |
| | | case 'dynamicIterable': |
| | | return _v.dynamicIterable?.toList(); |
| | | case 'objectIterable': |
| | | return _v.objectIterable?.toList(); |
| | | case 'intIterable': |
| | | return _v.intIterable?.toList(); |
| | | case 'set': |
| | | return _v.set?.toList(); |
| | | case 'dynamicSet': |
| | | return _v.dynamicSet?.toList(); |
| | | case 'objectSet': |
| | | return _v.objectSet?.toList(); |
| | | case 'intSet': |
| | | return _v.intSet?.toList(); |
| | | case 'dateTimeSet': |
| | | return _v.dateTimeSet?.map((e) => e?.toIso8601String())?.toList(); |
| | | case 'datetime-iterable': |
| | | return _v.dateTimeIterable |
| | | ?.map((e) => e?.toIso8601String()) |
| | | ?.toList(); |
| | | case 'list': |
| | | return _v.list; |
| | | case 'dynamicList': |
| | | return _v.dynamicList; |
| | | case 'objectList': |
| | | return _v.objectList; |
| | | case 'intList': |
| | | return _v.intList; |
| | | case 'dateTimeList': |
| | | return $wrapListHandleNull<DateTime>( |
| | | _v.dateTimeList, (e) => e?.toIso8601String()); |
| | | case 'map': |
| | | return _v.map; |
| | | case 'stringStringMap': |
| | | return _v.stringStringMap; |
| | | case 'dynamicIntMap': |
| | | return _v.dynamicIntMap; |
| | | case 'objectDateTimeMap': |
| | | return $wrapMapHandleNull<Object, DateTime>( |
| | | _v.objectDateTimeMap, (e) => e?.toIso8601String()); |
| | | case 'crazyComplex': |
| | | return $wrapListHandleNull< |
| | | Map<String, Map<String, List<List<DateTime>>>>>( |
| | | _v.crazyComplex, |
| | | (e) => |
| | | $wrapMapHandleNull<String, Map<String, List<List<DateTime>>>>( |
| | | e, |
| | | (e) => $wrapMapHandleNull<String, List<List<DateTime>>>( |
| | | e, |
| | | (e) => $wrapListHandleNull<List<DateTime>>( |
| | | e, |
| | | (e) => $wrapListHandleNull<DateTime>( |
| | | e, (e) => e?.toIso8601String()))))); |
| | | case 'val': |
| | | return _v.val; |
| | | case 'writeNotNull': |
| | | return _v.writeNotNull; |
| | | case r'$string': |
| | | return _v.string; |
| | | case 'simpleObject': |
| | | return _v.simpleObject; |
| | | case 'strictKeysObject': |
| | | return _v.strictKeysObject; |
| | | case 'validatedPropertyNo42': |
| | | return _v.validatedPropertyNo42; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | JsonConverterTestClass _$JsonConverterTestClassFromJson(Map json) { |
| | | return JsonConverterTestClass() |
| | | ..duration = json['duration'] == null |
| | | ? null |
| | | : durationConverter.fromJson(json['duration'] as int) |
| | | ..durationList = (json['durationList'] as List) |
| | | ?.map((e) => e == null ? null : durationConverter.fromJson(e as int)) |
| | | ?.toList() |
| | | ..bigInt = json['bigInt'] == null |
| | | ? null |
| | | : const BigIntStringConverter().fromJson(json['bigInt'] as String) |
| | | ..bigIntMap = (json['bigIntMap'] as Map)?.map((k, e) => MapEntry( |
| | | k as String, |
| | | e == null ? null : const BigIntStringConverter().fromJson(e as String))) |
| | | ..numberSilly = json['numberSilly'] == null |
| | | ? null |
| | | : TrivialNumberConverter.instance.fromJson(json['numberSilly'] as int) |
| | | ..numberSillySet = (json['numberSillySet'] as List) |
| | | ?.map((e) => e == null |
| | | ? null |
| | | : TrivialNumberConverter.instance.fromJson(e as int)) |
| | | ?.toSet() |
| | | ..dateTime = json['dateTime'] == null |
| | | ? null |
| | | : const EpochDateTimeConverter().fromJson(json['dateTime'] as int); |
| | | } |
| | | |
| | | abstract class _$JsonConverterTestClassSerializerMixin { |
| | | Duration get duration; |
| | | List<Duration> get durationList; |
| | | BigInt get bigInt; |
| | | Map<String, BigInt> get bigIntMap; |
| | | TrivialNumber get numberSilly; |
| | | Set<TrivialNumber> get numberSillySet; |
| | | DateTime get dateTime; |
| | | Map<String, dynamic> toJson() => _$JsonConverterTestClassJsonMapWrapper(this); |
| | | } |
| | | |
| | | class _$JsonConverterTestClassJsonMapWrapper extends $JsonMapWrapper { |
| | | final _$JsonConverterTestClassSerializerMixin _v; |
| | | _$JsonConverterTestClassJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const [ |
| | | 'duration', |
| | | 'durationList', |
| | | 'bigInt', |
| | | 'bigIntMap', |
| | | 'numberSilly', |
| | | 'numberSillySet', |
| | | 'dateTime' |
| | | ]; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'duration': |
| | | return _v.duration == null |
| | | ? null |
| | | : durationConverter.toJson(_v.duration); |
| | | case 'durationList': |
| | | return $wrapListHandleNull<Duration>(_v.durationList, |
| | | (e) => e == null ? null : durationConverter.toJson(e)); |
| | | case 'bigInt': |
| | | return _v.bigInt == null |
| | | ? null |
| | | : const BigIntStringConverter().toJson(_v.bigInt); |
| | | case 'bigIntMap': |
| | | return $wrapMapHandleNull<String, BigInt>( |
| | | _v.bigIntMap, |
| | | (e) => |
| | | e == null ? null : const BigIntStringConverter().toJson(e)); |
| | | case 'numberSilly': |
| | | return _v.numberSilly == null |
| | | ? null |
| | | : TrivialNumberConverter.instance.toJson(_v.numberSilly); |
| | | case 'numberSillySet': |
| | | return _v.numberSillySet |
| | | ?.map((e) => |
| | | e == null ? null : TrivialNumberConverter.instance.toJson(e)) |
| | | ?.toList(); |
| | | case 'dateTime': |
| | | return _v.dateTime == null |
| | | ? null |
| | | : const EpochDateTimeConverter().toJson(_v.dateTime); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | JsonConverterGeneric<S, T, U> _$JsonConverterGenericFromJson<S, T, U>( |
| | | Map json) { |
| | | return JsonConverterGeneric<S, T, U>() |
| | | ..item = json['item'] == null |
| | | ? null |
| | | : GenericConverter<S>().fromJson(json['item'] as Map<String, dynamic>) |
| | | ..itemList = (json['itemList'] as List) |
| | | ?.map((e) => e == null |
| | | ? null |
| | | : GenericConverter<T>().fromJson(e as Map<String, dynamic>)) |
| | | ?.toList() |
| | | ..itemMap = (json['itemMap'] as Map)?.map((k, e) => MapEntry( |
| | | k as String, |
| | | e == null |
| | | ? null |
| | | : GenericConverter<U>().fromJson(e as Map<String, dynamic>))); |
| | | } |
| | | |
| | | abstract class _$JsonConverterGenericSerializerMixin<S, T, U> { |
| | | S get item; |
| | | List<T> get itemList; |
| | | Map<String, U> get itemMap; |
| | | Map<String, dynamic> toJson() => |
| | | _$JsonConverterGenericJsonMapWrapper<S, T, U>(this); |
| | | } |
| | | |
| | | class _$JsonConverterGenericJsonMapWrapper<S, T, U> extends $JsonMapWrapper { |
| | | final _$JsonConverterGenericSerializerMixin<S, T, U> _v; |
| | | _$JsonConverterGenericJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => const ['item', 'itemList', 'itemMap']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'item': |
| | | return _v.item == null ? null : GenericConverter<S>().toJson(_v.item); |
| | | case 'itemList': |
| | | return $wrapListHandleNull<T>(_v.itemList, |
| | | (e) => e == null ? null : GenericConverter<T>().toJson(e)); |
| | | case 'itemMap': |
| | | return $wrapMapHandleNull<String, U>(_v.itemMap, |
| | | (e) => e == null ? null : GenericConverter<U>().toJson(e)); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:collection/collection.dart'; |
| | | import 'simple_object.dart'; |
| | | |
| | | abstract class KitchenSink { |
| | | int get ctorValidatedNo42; |
| | | DateTime dateTime; |
| | | |
| | | Iterable get iterable; |
| | | Iterable<dynamic> get dynamicIterable; |
| | | Iterable<Object> get objectIterable; |
| | | Iterable<int> get intIterable; |
| | | |
| | | Iterable<DateTime> get dateTimeIterable; |
| | | |
| | | List list; |
| | | List<dynamic> dynamicList; |
| | | List<Object> objectList; |
| | | List<int> intList; |
| | | List<DateTime> dateTimeList; |
| | | |
| | | Set set; |
| | | Set<dynamic> dynamicSet; |
| | | Set<Object> objectSet; |
| | | Set<int> intSet; |
| | | Set<DateTime> dateTimeSet; |
| | | |
| | | Map map; |
| | | Map<String, String> stringStringMap; |
| | | Map<dynamic, int> dynamicIntMap; |
| | | Map<Object, DateTime> objectDateTimeMap; |
| | | |
| | | List<Map<String, Map<String, List<List<DateTime>>>>> crazyComplex; |
| | | |
| | | Map<String, bool> val; |
| | | bool writeNotNull; |
| | | String string; |
| | | |
| | | SimpleObject get simpleObject; |
| | | |
| | | int validatedPropertyNo42; |
| | | |
| | | Map<String, dynamic> toJson(); |
| | | } |
| | | |
| | | //TODO(kevmoo) - finish this... |
| | | bool sinkEquals(KitchenSink a, Object other) => |
| | | other is KitchenSink && |
| | | a.ctorValidatedNo42 == other.ctorValidatedNo42 && |
| | | a.dateTime == other.dateTime && |
| | | _deepEquals(a.iterable, other.iterable) && |
| | | _deepEquals(a.dynamicIterable, other.dynamicIterable) && |
| | | // objectIterable |
| | | // intIterable |
| | | _deepEquals(a.dateTimeIterable, other.dateTimeIterable) && |
| | | // list |
| | | // dynamicList |
| | | // objectList |
| | | // intList |
| | | _deepEquals(a.dateTimeList, other.dateTimeList) && |
| | | // map |
| | | // stringStringMap |
| | | // stringIntMap |
| | | _deepEquals(a.objectDateTimeMap, other.objectDateTimeMap) && |
| | | _deepEquals(a.crazyComplex, other.crazyComplex) && |
| | | // val |
| | | a.writeNotNull == other.writeNotNull && |
| | | a.string == other.string; |
| | | |
| | | bool _deepEquals(Object a, Object b) => |
| | | const DeepCollectionEquality().equals(a, b); |
| New file |
| | |
| | | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:test/test.dart'; |
| | | import 'package:yaml/yaml.dart'; |
| | | |
| | | import '../test_utils.dart'; |
| | | import 'kitchen_sink.dart' as nullable |
| | | show testFactory, testFromJson, JsonConverterTestClass; |
| | | import 'kitchen_sink.non_nullable.checked.dart' as checked |
| | | show testFactory, testFromJson; |
| | | import 'kitchen_sink.non_nullable.dart' as nn |
| | | show testFactory, testFromJson, JsonConverterTestClass; |
| | | import 'kitchen_sink.non_nullable.wrapped.dart' as nnwrapped |
| | | show testFactory, testFromJson; |
| | | import 'kitchen_sink.wrapped.dart' as wrapped show testFactory, testFromJson; |
| | | import 'kitchen_sink_interface.dart'; |
| | | import 'strict_keys_object.dart'; |
| | | |
| | | // copied and renamed as private from /lib/src/constants.dart |
| | | const _generatedLocalVarName = 'val'; |
| | | const _toJsonMapHelperName = 'writeNotNull'; |
| | | |
| | | final _isATypeError = const TypeMatcher<TypeError>(); |
| | | |
| | | Matcher _isAUnrecognizedKeysEexception(expectedMessage) => |
| | | const TypeMatcher<UnrecognizedKeysException>() |
| | | .having((e) => e.message, 'message', expectedMessage); |
| | | |
| | | Matcher _isMissingKeyException(expectedMessage) => |
| | | const TypeMatcher<MissingRequiredKeysException>() |
| | | .having((e) => e.message, 'message', expectedMessage); |
| | | |
| | | void main() { |
| | | test('valid values covers all keys', () { |
| | | expect(_invalidValueTypes.keys, orderedEquals(_validValues.keys)); |
| | | }); |
| | | |
| | | test('required keys', () { |
| | | expect( |
| | | () => StrictKeysObject.fromJson({}), |
| | | throwsA(_isMissingKeyException( |
| | | 'Required keys are missing: value, custom_field.'))); |
| | | }); |
| | | |
| | | group('nullable', () { |
| | | group('unwrapped', () { |
| | | _nullableTests(nullable.testFactory, nullable.testFromJson); |
| | | }); |
| | | |
| | | group('wrapped', () { |
| | | _nullableTests(wrapped.testFactory, wrapped.testFromJson); |
| | | }); |
| | | }); |
| | | |
| | | group('non-nullable', () { |
| | | group('checked', () { |
| | | _nonNullableTests(checked.testFactory, checked.testFromJson, |
| | | isChecked: true); |
| | | }); |
| | | |
| | | group('unwrapped', () { |
| | | _nonNullableTests(nn.testFactory, nn.testFromJson); |
| | | }); |
| | | |
| | | group('wrapped', () { |
| | | _nonNullableTests(nnwrapped.testFactory, nnwrapped.testFromJson); |
| | | }); |
| | | }); |
| | | |
| | | group('JsonConverterTestClass', () { |
| | | final validValues = { |
| | | 'duration': 5, |
| | | 'durationList': [5], |
| | | 'bigInt': '5', |
| | | 'bigIntMap': {'vaule': '5'}, |
| | | 'numberSilly': 5, |
| | | 'numberSillySet': [5], |
| | | 'dateTime': 5 |
| | | }; |
| | | |
| | | test('nullable values are allowed in the nullable version', () { |
| | | final instance = nullable.JsonConverterTestClass(); |
| | | final json = instance.toJson(); |
| | | expect(json.values, everyElement(isNull)); |
| | | expect(json.keys, unorderedEquals(validValues.keys)); |
| | | |
| | | final instance2 = nullable.JsonConverterTestClass.fromJson(json); |
| | | expect(instance2.toJson(), json); |
| | | }); |
| | | |
| | | test('nullable values are not allowed in non-nullable version', () { |
| | | var instance = nn.JsonConverterTestClass(); |
| | | expect(() => instance.toJson(), throwsNoSuchMethodError, |
| | | reason: 'Trying to call `map` on a null list'); |
| | | |
| | | instance = nn.JsonConverterTestClass.fromJson(validValues); |
| | | final json = instance.toJson(); |
| | | expect(json, validValues); |
| | | expect(json.values, everyElement(isNotNull)); |
| | | |
| | | final instance2 = nn.JsonConverterTestClass.fromJson(json); |
| | | expect(instance2.toJson(), json); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | typedef KitchenSink KitchenSinkCtor( |
| | | {int ctorValidatedNo42, |
| | | Iterable iterable, |
| | | Iterable<dynamic> dynamicIterable, |
| | | Iterable<Object> objectIterable, |
| | | Iterable<int> intIterable, |
| | | Iterable<DateTime> dateTimeIterable}); |
| | | |
| | | void _nonNullableTests(KitchenSinkCtor ctor, KitchenSink fromJson(Map json), |
| | | {bool isChecked = false}) { |
| | | test('with null values fails serialization', () { |
| | | expect(() => (ctor()..objectDateTimeMap = null).toJson(), |
| | | throwsNoSuchMethodError); |
| | | }); |
| | | |
| | | test('with empty json fails deserialization', () { |
| | | if (isChecked) { |
| | | expect(() => fromJson({}), throwsA(_checkedMatcher('intIterable'))); |
| | | } else { |
| | | expect(() => fromJson({}), throwsNoSuchMethodError); |
| | | } |
| | | }); |
| | | _sharedTests(ctor, fromJson, isChecked: isChecked); |
| | | } |
| | | |
| | | void _nullableTests(KitchenSinkCtor ctor, KitchenSink fromJson(Map json)) { |
| | | void roundTripItem(KitchenSink p) { |
| | | roundTripObject(p, (json) => fromJson(json)); |
| | | } |
| | | |
| | | test('Fields with `!includeIfNull` should not be included when null', () { |
| | | final item = ctor(); |
| | | |
| | | final expectedDefaultKeys = _validValues.keys.toSet() |
| | | ..removeAll(_excludeIfNullKeys); |
| | | |
| | | final encoded = item.toJson(); |
| | | |
| | | expect(encoded.keys, orderedEquals(expectedDefaultKeys)); |
| | | |
| | | for (final key in expectedDefaultKeys) { |
| | | expect(encoded, containsPair(key, isNull)); |
| | | } |
| | | }); |
| | | |
| | | test('list and map of DateTime', () { |
| | | final now = DateTime.now(); |
| | | final item = ctor(dateTimeIterable: <DateTime>[now]) |
| | | ..dateTimeList = <DateTime>[now, null] |
| | | ..objectDateTimeMap = <Object, DateTime>{'value': now, 'null': null}; |
| | | |
| | | roundTripItem(item); |
| | | }); |
| | | |
| | | test('complex nested type', () { |
| | | final item = ctor() |
| | | ..crazyComplex = [ |
| | | null, |
| | | {}, |
| | | { |
| | | 'null': null, |
| | | 'empty': {}, |
| | | 'items': { |
| | | 'null': null, |
| | | 'empty': [], |
| | | 'items': [ |
| | | null, |
| | | [], |
| | | [DateTime.now()] |
| | | ] |
| | | } |
| | | } |
| | | ]; |
| | | roundTripItem(item); |
| | | }); |
| | | |
| | | _sharedTests(ctor, fromJson); |
| | | } |
| | | |
| | | void _sharedTests(KitchenSinkCtor ctor, KitchenSink fromJson(Map json), |
| | | {bool isChecked = false}) { |
| | | void roundTripSink(KitchenSink p) { |
| | | roundTripObject(p, fromJson); |
| | | } |
| | | |
| | | test('empty', () { |
| | | final item = ctor(); |
| | | roundTripSink(item); |
| | | }); |
| | | |
| | | test('list and map of DateTime - not null', () { |
| | | final now = DateTime.now(); |
| | | final item = ctor(dateTimeIterable: <DateTime>[now]) |
| | | ..dateTimeList = <DateTime>[now, now] |
| | | ..objectDateTimeMap = <Object, DateTime>{'value': now}; |
| | | |
| | | roundTripSink(item); |
| | | }); |
| | | |
| | | test('complex nested type - not null', () { |
| | | final item = ctor() |
| | | ..crazyComplex = [ |
| | | {}, |
| | | { |
| | | 'empty': {}, |
| | | 'items': { |
| | | 'empty': [], |
| | | 'items': [ |
| | | [], |
| | | [DateTime.now()] |
| | | ] |
| | | } |
| | | } |
| | | ]; |
| | | roundTripSink(item); |
| | | }); |
| | | |
| | | test('JSON keys should be defined in field/property order', () { |
| | | /// Explicitly setting values from [_excludeIfNullKeys] to ensure |
| | | /// they exist for KitchenSink where they are excluded when null |
| | | final item = ctor(iterable: []) |
| | | ..dateTime = DateTime.now() |
| | | ..dateTimeList = [] |
| | | ..crazyComplex = [] |
| | | ..val = {}; |
| | | |
| | | final json = item.toJson(); |
| | | expect(json.keys, orderedEquals(_validValues.keys)); |
| | | }); |
| | | |
| | | test('valid values round-trip - json', () { |
| | | expect(loudEncode(_validValues), loudEncode(fromJson(_validValues))); |
| | | }); |
| | | |
| | | test('valid values round-trip - yaml', () { |
| | | final jsonEncoded = loudEncode(_validValues); |
| | | final yaml = loadYaml(jsonEncoded, sourceUrl: 'input.yaml'); |
| | | expect(jsonEncoded, loudEncode(fromJson(yaml as YamlMap))); |
| | | }); |
| | | |
| | | group('a bad value for', () { |
| | | for (final e in _invalidValueTypes.entries) { |
| | | _testBadValue(isChecked, e.key, e.value, fromJson, false); |
| | | } |
| | | for (final e in _invalidCheckedValues.entries) { |
| | | _testBadValue(isChecked, e.key, e.value, fromJson, true); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | void _testBadValue(bool isChecked, String key, Object badValue, |
| | | KitchenSink fromJson(Map json), bool checkedAssignment) { |
| | | final matcher = _getMatcher(isChecked, key, checkedAssignment); |
| | | |
| | | for (final isJson in [true, false]) { |
| | | test('`$key` fails with value `$badValue`- ${isJson ? 'json' : 'yaml'}', |
| | | () { |
| | | var copy = Map.from(_validValues); |
| | | copy[key] = badValue; |
| | | |
| | | if (!isJson) { |
| | | copy = loadYaml(loudEncode(copy)) as YamlMap; |
| | | } |
| | | |
| | | expect(() => fromJson(copy), matcher); |
| | | }); |
| | | } |
| | | } |
| | | |
| | | Matcher _checkedMatcher(String expectedKey) => |
| | | const TypeMatcher<CheckedFromJsonException>() |
| | | .having((e) => e.className, 'className', 'KitchenSink') |
| | | .having((e) => e.key, 'key', expectedKey); |
| | | |
| | | Matcher _getMatcher(bool checked, String expectedKey, bool checkedAssignment) { |
| | | Matcher innerMatcher; |
| | | |
| | | if (checked) { |
| | | if (checkedAssignment && |
| | | const ['intIterable', 'datetime-iterable'].contains(expectedKey)) { |
| | | expectedKey = null; |
| | | } |
| | | |
| | | innerMatcher = _checkedMatcher(expectedKey); |
| | | } else { |
| | | innerMatcher = anyOf( |
| | | isCastError, |
| | | _isATypeError, |
| | | _isAUnrecognizedKeysEexception( |
| | | 'Unrecognized keys: [invalid_key]; supported keys: [value, custom_field]')); |
| | | |
| | | if (checkedAssignment) { |
| | | switch (expectedKey) { |
| | | case 'validatedPropertyNo42': |
| | | innerMatcher = isStateError; |
| | | break; |
| | | case 'no-42': |
| | | innerMatcher = isArgumentError; |
| | | break; |
| | | case 'strictKeysObject': |
| | | innerMatcher = _isAUnrecognizedKeysEexception('bob'); |
| | | break; |
| | | case 'intIterable': |
| | | case 'datetime-iterable': |
| | | innerMatcher = isCastError; |
| | | break; |
| | | default: |
| | | throw StateError('Not expected! - $expectedKey'); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return throwsA(innerMatcher); |
| | | } |
| | | |
| | | final _validValues = const { |
| | | 'no-42': 0, |
| | | 'dateTime': '2018-05-10T14:20:58.927', |
| | | 'iterable': [], |
| | | 'dynamicIterable': [], |
| | | 'objectIterable': [], |
| | | 'intIterable': [], |
| | | 'set': [], |
| | | 'dynamicSet': [], |
| | | 'objectSet': [], |
| | | 'intSet': [], |
| | | 'dateTimeSet': [], |
| | | 'datetime-iterable': [], |
| | | 'list': [], |
| | | 'dynamicList': [], |
| | | 'objectList': [], |
| | | 'intList': [], |
| | | 'dateTimeList': [], |
| | | 'map': <String, dynamic>{}, |
| | | 'stringStringMap': {}, |
| | | 'dynamicIntMap': {}, |
| | | 'objectDateTimeMap': <String, dynamic>{}, |
| | | 'crazyComplex': [], |
| | | _generatedLocalVarName: {}, |
| | | _toJsonMapHelperName: null, |
| | | r'$string': null, |
| | | 'simpleObject': {'value': 42}, |
| | | 'strictKeysObject': {'value': 10, 'custom_field': 'cool'}, |
| | | 'validatedPropertyNo42': 0 |
| | | }; |
| | | |
| | | final _invalidValueTypes = const { |
| | | 'no-42': true, |
| | | 'dateTime': true, |
| | | 'iterable': true, |
| | | 'dynamicIterable': true, |
| | | 'objectIterable': true, |
| | | 'intIterable': true, |
| | | 'set': true, |
| | | 'dynamicSet': true, |
| | | 'objectSet': true, |
| | | 'intSet': true, |
| | | 'dateTimeSet': true, |
| | | 'datetime-iterable': true, |
| | | 'list': true, |
| | | 'dynamicList': true, |
| | | 'objectList': true, |
| | | 'intList': [true], |
| | | 'dateTimeList': [true], |
| | | 'map': true, |
| | | 'stringStringMap': {'key': 42}, |
| | | 'dynamicIntMap': {'key': 'value'}, |
| | | 'objectDateTimeMap': {'key': 42}, |
| | | 'crazyComplex': [true], |
| | | _generatedLocalVarName: {'key': 42}, |
| | | _toJsonMapHelperName: 42, |
| | | r'$string': true, |
| | | 'simpleObject': 42, |
| | | 'strictKeysObject': { |
| | | 'value': 10, |
| | | 'invalid_key': true, |
| | | }, |
| | | 'validatedPropertyNo42': true |
| | | }; |
| | | |
| | | /// Invalid values that are found after the property set or ctor call |
| | | final _invalidCheckedValues = const { |
| | | 'no-42': 42, |
| | | 'validatedPropertyNo42': 42, |
| | | 'intIterable': [true], |
| | | 'datetime-iterable': [true], |
| | | }; |
| | | |
| | | final _excludeIfNullKeys = const [ |
| | | 'dateTime', |
| | | 'iterable', |
| | | 'dateTimeList', |
| | | 'crazyComplex', |
| | | _generatedLocalVarName |
| | | ]; |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | part 'simple_object.g.dart'; |
| | | |
| | | @JsonSerializable(anyMap: true, generateToJsonFunction: false) |
| | | class SimpleObject extends Object with _$SimpleObjectSerializerMixin { |
| | | @override |
| | | final int value; |
| | | |
| | | SimpleObject(this.value); |
| | | |
| | | factory SimpleObject.fromJson(Map json) => _$SimpleObjectFromJson(json); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'simple_object.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | SimpleObject _$SimpleObjectFromJson(Map json) { |
| | | return SimpleObject(json['value'] as int); |
| | | } |
| | | |
| | | abstract class _$SimpleObjectSerializerMixin { |
| | | int get value; |
| | | Map<String, dynamic> toJson() => <String, dynamic>{'value': value}; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | part 'strict_keys_object.g.dart'; |
| | | |
| | | @JsonSerializable( |
| | | disallowUnrecognizedKeys: true, anyMap: true, generateToJsonFunction: false) |
| | | class StrictKeysObject extends Object with _$StrictKeysObjectSerializerMixin { |
| | | @override |
| | | @JsonKey(required: true) |
| | | final int value; |
| | | |
| | | @override |
| | | @JsonKey(name: 'custom_field', required: true) |
| | | final String customField; |
| | | |
| | | StrictKeysObject(this.value, this.customField); |
| | | |
| | | factory StrictKeysObject.fromJson(Map json) => |
| | | _$StrictKeysObjectFromJson(json); |
| | | } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'strict_keys_object.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | StrictKeysObject _$StrictKeysObjectFromJson(Map json) { |
| | | $checkKeys(json, |
| | | allowedKeys: const ['value', 'custom_field'], |
| | | requiredKeys: const ['value', 'custom_field']); |
| | | return StrictKeysObject(json['value'] as int, json['custom_field'] as String); |
| | | } |
| | | |
| | | abstract class _$StrictKeysObjectSerializerMixin { |
| | | int get value; |
| | | String get customField; |
| | | Map<String, dynamic> toJson() => |
| | | <String, dynamic>{'value': value, 'custom_field': customField}; |
| | | } |
| New file |
| | |
| | | [ |
| | | "", |
| | | "undefined", |
| | | "undef", |
| | | "null", |
| | | "NULL", |
| | | "(null)", |
| | | "nil", |
| | | "NIL", |
| | | "true", |
| | | "false", |
| | | "True", |
| | | "False", |
| | | "TRUE", |
| | | "FALSE", |
| | | "None", |
| | | "hasOwnProperty", |
| | | "\\", |
| | | "\\\\", |
| | | "0", |
| | | "1", |
| | | "1.00", |
| | | "$1.00", |
| | | "1/2", |
| | | "1E2", |
| | | "1E02", |
| | | "1E+02", |
| | | "-1", |
| | | "-1.00", |
| | | "-$1.00", |
| | | "-1/2", |
| | | "-1E2", |
| | | "-1E02", |
| | | "-1E+02", |
| | | "1/0", |
| | | "0/0", |
| | | "-2147483648/-1", |
| | | "-9223372036854775808/-1", |
| | | "-0", |
| | | "-0.0", |
| | | "+0", |
| | | "+0.0", |
| | | "0.00", |
| | | "0..0", |
| | | ".", |
| | | "0.0.0", |
| | | "0,00", |
| | | "0,,0", |
| | | ",", |
| | | "0,0,0", |
| | | "0.0/0", |
| | | "1.0/0.0", |
| | | "0.0/0.0", |
| | | "1,0/0,0", |
| | | "0,0/0,0", |
| | | "--1", |
| | | "-", |
| | | "-.", |
| | | "-,", |
| | | "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", |
| | | "NaN", |
| | | "Infinity", |
| | | "-Infinity", |
| | | "INF", |
| | | "1#INF", |
| | | "-1#IND", |
| | | "1#QNAN", |
| | | "1#SNAN", |
| | | "1#IND", |
| | | "0x0", |
| | | "0xffffffff", |
| | | "0xffffffffffffffff", |
| | | "0xabad1dea", |
| | | "123456789012345678901234567890123456789", |
| | | "1,000.00", |
| | | "1 000.00", |
| | | "1'000.00", |
| | | "1,000,000.00", |
| | | "1 000 000.00", |
| | | "1'000'000.00", |
| | | "1.000,00", |
| | | "1 000,00", |
| | | "1'000,00", |
| | | "1.000.000,00", |
| | | "1 000 000,00", |
| | | "1'000'000,00", |
| | | "01000", |
| | | "08", |
| | | "09", |
| | | "2.2250738585072011e-308", |
| | | ",./;'[]\\-=", |
| | | "<>?:\"{}|_+", |
| | | "!@#$%^&*()`~", |
| | | "\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f", |
| | | "", |
| | | "\t\u000b\f
", |
| | | "", |
| | | "", |
| | | "", |
| | | "Ω≈ç√∫˜µ≤≥÷", |
| | | "åß∂ƒ©˙∆˚¬…æ", |
| | | "œ∑´®†¥¨ˆøπ“‘", |
| | | "¡™£¢∞§¶•ªº–≠", |
| | | "¸˛Ç◊ı˜Â¯˘¿", |
| | | "ÅÍÎÏ˝ÓÔÒÚÆ☃", |
| | | "Œ„´‰ˇÁ¨ˆØ∏”’", |
| | | "`⁄€‹›fifl‡°·‚—±", |
| | | "⅛⅜⅝⅞", |
| | | "ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя", |
| | | "٠١٢٣٤٥٦٧٨٩", |
| | | "⁰⁴⁵", |
| | | "₀₁₂", |
| | | "⁰⁴⁵₀₁₂", |
| | | "ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็", |
| | | "'", |
| | | "\"", |
| | | "''", |
| | | "\"\"", |
| | | "'\"'", |
| | | "\"''''\"'\"", |
| | | "\"'\"'\"''''\"", |
| | | "<foo val=“bar” />", |
| | | "<foo val=“bar” />", |
| | | "<foo val=”bar“ />", |
| | | "<foo val=`bar' />", |
| | | "田中さんにあげて下さい", |
| | | "パーティーへ行かないか", |
| | | "和製漢語", |
| | | "部落格", |
| | | "사회과학원 어학연구소", |
| | | "찦차를 타고 온 펲시맨과 쑛다리 똠방각하", |
| | | "社會科學院語學研究所", |
| | | "울란바토르", |
| | | "𠜎𠜱𠝹𠱓𠱸𠲖𠳏", |
| | | "Ⱥ", |
| | | "Ⱦ", |
| | | "ヽ༼ຈل͜ຈ༽ノ ヽ༼ຈل͜ຈ༽ノ ", |
| | | "(。◕ ∀ ◕。)", |
| | | "`ィ(´∀`∩", |
| | | "__ロ(,_,*)", |
| | | "・( ̄∀ ̄)・:*:", |
| | | "゚・✿ヾ╲(。◕‿◕。)╱✿・゚", |
| | | ",。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’", |
| | | "(╯°□°)╯︵ ┻━┻)", |
| | | "(ノಥ益ಥ)ノ ┻━┻", |
| | | "┬─┬ノ( º _ ºノ)", |
| | | "( ͡° ͜ʖ ͡°)", |
| | | "😍", |
| | | "👩🏽", |
| | | "👾 🙇 💁 🙅 🙆 🙋 🙎 🙍", |
| | | "🐵 🙈 🙉 🙊", |
| | | "❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙", |
| | | "✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿", |
| | | "🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧", |
| | | "0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟", |
| | | "🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸", |
| | | "🇺🇸🇷🇺🇸🇦🇫🇦🇲", |
| | | "🇺🇸🇷🇺🇸🇦", |
| | | "123", |
| | | "١٢٣", |
| | | "ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو.", |
| | | "בְּרֵאשִׁית, בָּרָא אֱלֹהִים, אֵת הַשָּׁמַיִם, וְאֵת הָאָרֶץ", |
| | | "הָיְתָהtestالصفحات التّحول", |
| | | "﷽", |
| | | "ﷺ", |
| | | "مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ، ", |
| | | "", |
| | | " ", |
| | | "", |
| | | " ", |
| | | "", |
| | | "␣", |
| | | "␢", |
| | | "␡", |
| | | "test", |
| | | "test", |
| | | "
test
", |
| | | "testtest", |
| | | "test", |
| | | "Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣", |
| | | "̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰", |
| | | "̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟", |
| | | "̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕", |
| | | "Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮", |
| | | "˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥", |
| | | "00˙Ɩ$-", |
| | | "The quick brown fox jumps over the lazy dog", |
| | | "𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠", |
| | | "𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌", |
| | | "𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈", |
| | | "𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰", |
| | | "𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘", |
| | | "𝚃𝚑𝚎 𝚚𝚞𝚒𝚌𝚔 𝚋𝚛𝚘𝚠𝚗 𝚏𝚘𝚡 𝚓𝚞𝚖𝚙𝚜 𝚘𝚟𝚎𝚛 𝚝𝚑𝚎 𝚕𝚊𝚣𝚢 𝚍𝚘𝚐", |
| | | "⒯⒣⒠ ⒬⒰⒤⒞⒦ ⒝⒭⒪⒲⒩ ⒡⒪⒳ ⒥⒰⒨⒫⒮ ⒪⒱⒠⒭ ⒯⒣⒠ ⒧⒜⒵⒴ ⒟⒪⒢", |
| | | "<script>alert(123)</script>", |
| | | "<script>alert('123');</script>", |
| | | "<img src=x onerror=alert(123) />", |
| | | "<svg><script>123<1>alert(123)</script>", |
| | | "\"><script>alert(123)</script>", |
| | | "'><script>alert(123)</script>", |
| | | "><script>alert(123)</script>", |
| | | "</script><script>alert(123)</script>", |
| | | "< / script >< script >alert(123)< / script >", |
| | | " onfocus=JaVaSCript:alert(123) autofocus", |
| | | "\" onfocus=JaVaSCript:alert(123) autofocus", |
| | | "' onfocus=JaVaSCript:alert(123) autofocus", |
| | | "<script>alert(123)</script>", |
| | | "<sc<script>ript>alert(123)</sc</script>ript>", |
| | | "--><script>alert(123)</script>", |
| | | "\";alert(123);t=\"", |
| | | "';alert(123);t='", |
| | | "JavaSCript:alert(123)", |
| | | ";alert(123);", |
| | | "src=JaVaSCript:prompt(132)", |
| | | "\"><script>alert(123);</script x=\"", |
| | | "'><script>alert(123);</script x='", |
| | | "><script>alert(123);</script x=", |
| | | "\" autofocus onkeyup=\"javascript:alert(123)", |
| | | "' autofocus onkeyup='javascript:alert(123)", |
| | | "<script\\x20type=\"text/javascript\">javascript:alert(1);</script>", |
| | | "<script\\x3Etype=\"text/javascript\">javascript:alert(1);</script>", |
| | | "<script\\x0Dtype=\"text/javascript\">javascript:alert(1);</script>", |
| | | "<script\\x09type=\"text/javascript\">javascript:alert(1);</script>", |
| | | "<script\\x0Ctype=\"text/javascript\">javascript:alert(1);</script>", |
| | | "<script\\x2Ftype=\"text/javascript\">javascript:alert(1);</script>", |
| | | "<script\\x0Atype=\"text/javascript\">javascript:alert(1);</script>", |
| | | "'`\"><\\x3Cscript>javascript:alert(1)</script>", |
| | | "'`\"><\\x00script>javascript:alert(1)</script>", |
| | | "ABC<div style=\"x\\x3Aexpression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:expression\\x5C(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:expression\\x00(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:exp\\x00ression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:exp\\x5Cression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\x0Aexpression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\x09expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE3\\x80\\x80expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x84expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xC2\\xA0expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x80expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x8Aexpression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\x0Dexpression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\x0Cexpression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x87expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xEF\\xBB\\xBFexpression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\x20expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x88expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\x00expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x8Bexpression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x86expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x85expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x82expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\x0Bexpression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x81expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x83expression(javascript:alert(1)\">DEF", |
| | | "ABC<div style=\"x:\\xE2\\x80\\x89expression(javascript:alert(1)\">DEF", |
| | | "<a href=\"\\x0Bjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x0Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xC2\\xA0javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x05javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE1\\xA0\\x8Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x18javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x11javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x88javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x89javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x17javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x03javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x0Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x1Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x00javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x10javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x82javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x20javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x13javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x09javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x8Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x14javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x19javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\xAFjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x1Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x81javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x1Djavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x87javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x07javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE1\\x9A\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x83javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x04javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x01javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x08javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x84javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x86javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE3\\x80\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x12javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x0Djavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x0Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x0Cjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x15javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\xA8javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x16javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x02javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x1Bjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x06javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\xA9javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x80\\x85javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x1Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\xE2\\x81\\x9Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"\\x1Cjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"javascript\\x00:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"javascript\\x3A:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"javascript\\x09:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"javascript\\x0D:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "<a href=\"javascript\\x0A:javascript:alert(1)\" id=\"fuzzelement1\">test</a>", |
| | | "`\"'><img src=xxx:x \\x0Aonerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x22onerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x0Bonerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x0Donerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x2Fonerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x09onerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x0Conerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x00onerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x27onerror=javascript:alert(1)>", |
| | | "`\"'><img src=xxx:x \\x20onerror=javascript:alert(1)>", |
| | | "\"`'><script>\\x3Bjavascript:alert(1)</script>", |
| | | "\"`'><script>\\x0Djavascript:alert(1)</script>", |
| | | "\"`'><script>\\xEF\\xBB\\xBFjavascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x81javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x84javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE3\\x80\\x80javascript:alert(1)</script>", |
| | | "\"`'><script>\\x09javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x89javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x85javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x88javascript:alert(1)</script>", |
| | | "\"`'><script>\\x00javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\xA8javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x8Ajavascript:alert(1)</script>", |
| | | "\"`'><script>\\xE1\\x9A\\x80javascript:alert(1)</script>", |
| | | "\"`'><script>\\x0Cjavascript:alert(1)</script>", |
| | | "\"`'><script>\\x2Bjavascript:alert(1)</script>", |
| | | "\"`'><script>\\xF0\\x90\\x96\\x9Ajavascript:alert(1)</script>", |
| | | "\"`'><script>-javascript:alert(1)</script>", |
| | | "\"`'><script>\\x0Ajavascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\xAFjavascript:alert(1)</script>", |
| | | "\"`'><script>\\x7Ejavascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x87javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x81\\x9Fjavascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\xA9javascript:alert(1)</script>", |
| | | "\"`'><script>\\xC2\\x85javascript:alert(1)</script>", |
| | | "\"`'><script>\\xEF\\xBF\\xAEjavascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x83javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x8Bjavascript:alert(1)</script>", |
| | | "\"`'><script>\\xEF\\xBF\\xBEjavascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x80javascript:alert(1)</script>", |
| | | "\"`'><script>\\x21javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x82javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE2\\x80\\x86javascript:alert(1)</script>", |
| | | "\"`'><script>\\xE1\\xA0\\x8Ejavascript:alert(1)</script>", |
| | | "\"`'><script>\\x0Bjavascript:alert(1)</script>", |
| | | "\"`'><script>\\x20javascript:alert(1)</script>", |
| | | "\"`'><script>\\xC2\\xA0javascript:alert(1)</script>", |
| | | "<img \\x00src=x onerror=\"alert(1)\">", |
| | | "<img \\x47src=x onerror=\"javascript:alert(1)\">", |
| | | "<img \\x11src=x onerror=\"javascript:alert(1)\">", |
| | | "<img \\x12src=x onerror=\"javascript:alert(1)\">", |
| | | "<img\\x47src=x onerror=\"javascript:alert(1)\">", |
| | | "<img\\x10src=x onerror=\"javascript:alert(1)\">", |
| | | "<img\\x13src=x onerror=\"javascript:alert(1)\">", |
| | | "<img\\x32src=x onerror=\"javascript:alert(1)\">", |
| | | "<img\\x47src=x onerror=\"javascript:alert(1)\">", |
| | | "<img\\x11src=x onerror=\"javascript:alert(1)\">", |
| | | "<img \\x47src=x onerror=\"javascript:alert(1)\">", |
| | | "<img \\x34src=x onerror=\"javascript:alert(1)\">", |
| | | "<img \\x39src=x onerror=\"javascript:alert(1)\">", |
| | | "<img \\x00src=x onerror=\"javascript:alert(1)\">", |
| | | "<img src\\x09=x onerror=\"javascript:alert(1)\">", |
| | | "<img src\\x10=x onerror=\"javascript:alert(1)\">", |
| | | "<img src\\x13=x onerror=\"javascript:alert(1)\">", |
| | | "<img src\\x32=x onerror=\"javascript:alert(1)\">", |
| | | "<img src\\x12=x onerror=\"javascript:alert(1)\">", |
| | | "<img src\\x11=x onerror=\"javascript:alert(1)\">", |
| | | "<img src\\x00=x onerror=\"javascript:alert(1)\">", |
| | | "<img src\\x47=x onerror=\"javascript:alert(1)\">", |
| | | "<img src=x\\x09onerror=\"javascript:alert(1)\">", |
| | | "<img src=x\\x10onerror=\"javascript:alert(1)\">", |
| | | "<img src=x\\x11onerror=\"javascript:alert(1)\">", |
| | | "<img src=x\\x12onerror=\"javascript:alert(1)\">", |
| | | "<img src=x\\x13onerror=\"javascript:alert(1)\">", |
| | | "<img[a][b][c]src[d]=x[e]onerror=[f]\"alert(1)\">", |
| | | "<img src=x onerror=\\x09\"javascript:alert(1)\">", |
| | | "<img src=x onerror=\\x10\"javascript:alert(1)\">", |
| | | "<img src=x onerror=\\x11\"javascript:alert(1)\">", |
| | | "<img src=x onerror=\\x12\"javascript:alert(1)\">", |
| | | "<img src=x onerror=\\x32\"javascript:alert(1)\">", |
| | | "<img src=x onerror=\\x00\"javascript:alert(1)\">", |
| | | "<a href=javascript:javascript:alert(1)>XXX</a>", |
| | | "<img src=\"x` `<script>javascript:alert(1)</script>\"` `>", |
| | | "<img src onerror /\" '\"= alt=javascript:alert(1)//\">", |
| | | "<title onpropertychange=javascript:alert(1)></title><title title=>", |
| | | "<a href=http://foo.bar/#x=`y></a><img alt=\"`><img src=x:x onerror=javascript:alert(1)></a>\">", |
| | | "<!--[if]><script>javascript:alert(1)</script -->", |
| | | "<!--[if<img src=x onerror=javascript:alert(1)//]> -->", |
| | | "<script src=\"/\\%(jscript)s\"></script>", |
| | | "<script src=\"\\\\%(jscript)s\"></script>", |
| | | "<IMG \"\"\"><SCRIPT>alert(\"XSS\")</SCRIPT>\">", |
| | | "<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>", |
| | | "<IMG SRC=# onmouseover=\"alert('xxs')\">", |
| | | "<IMG SRC= onmouseover=\"alert('xxs')\">", |
| | | "<IMG onmouseover=\"alert('xxs')\">", |
| | | "<IMG SRC=javascript:alert('XSS')>", |
| | | "<IMG SRC=javascript:alert('XSS')>", |
| | | "<IMG SRC=javascript:alert('XSS')>", |
| | | "<IMG SRC=\"jav ascript:alert('XSS');\">", |
| | | "<IMG SRC=\"jav	ascript:alert('XSS');\">", |
| | | "<IMG SRC=\"jav
ascript:alert('XSS');\">", |
| | | "<IMG SRC=\"jav
ascript:alert('XSS');\">", |
| | | "perl -e 'print \"<IMG SRC=java\\0script:alert(\\\"XSS\\\")>\";' > out", |
| | | "<IMG SRC=\"  javascript:alert('XSS');\">", |
| | | "<SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>", |
| | | "<BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>", |
| | | "<SCRIPT/SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>", |
| | | "<<SCRIPT>alert(\"XSS\");//<</SCRIPT>", |
| | | "<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >", |
| | | "<SCRIPT SRC=//ha.ckers.org/.j>", |
| | | "<IMG SRC=\"javascript:alert('XSS')\"", |
| | | "<iframe src=http://ha.ckers.org/scriptlet.html <", |
| | | "\\\";alert('XSS');//", |
| | | "<u oncopy=alert()> Copy me</u>", |
| | | "<i onwheel=alert(1)> Scroll over me </i>", |
| | | "<plaintext>", |
| | | "http://a/%%30%30", |
| | | "</textarea><script>alert(123)</script>", |
| | | "1;DROP TABLE users", |
| | | "1'; DROP TABLE users-- 1", |
| | | "' OR 1=1 -- 1", |
| | | "' OR '1'='1", |
| | | " ", |
| | | "%", |
| | | "_", |
| | | "-", |
| | | "--", |
| | | "--version", |
| | | "--help", |
| | | "$USER", |
| | | "/dev/null; touch /tmp/blns.fail ; echo", |
| | | "`touch /tmp/blns.fail`", |
| | | "$(touch /tmp/blns.fail)", |
| | | "@{[system \"touch /tmp/blns.fail\"]}", |
| | | "eval(\"puts 'hello world'\")", |
| | | "System(\"ls -al /\")", |
| | | "`ls -al /`", |
| | | "Kernel.exec(\"ls -al /\")", |
| | | "Kernel.exit(1)", |
| | | "%x('ls -al /')", |
| | | "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]><foo>&xxe;</foo>", |
| | | "$HOME", |
| | | "$ENV{'HOME'}", |
| | | "%d", |
| | | "%s", |
| | | "{0}", |
| | | "%*.*s", |
| | | "File:///", |
| | | "../../../../../../../../../../../etc/passwd%00", |
| | | "../../../../../../../../../../../etc/hosts", |
| | | "() { 0; }; touch /tmp/blns.shellshock1.fail;", |
| | | "() { _; } >_[$($())] { touch /tmp/blns.shellshock2.fail; }", |
| | | "<<< %s(un='%s') = %u", |
| | | "+++ATH0", |
| | | "CON", |
| | | "PRN", |
| | | "AUX", |
| | | "CLOCK$", |
| | | "NUL", |
| | | "A:", |
| | | "ZZ:", |
| | | "COM1", |
| | | "LPT1", |
| | | "LPT2", |
| | | "LPT3", |
| | | "COM2", |
| | | "COM3", |
| | | "COM4", |
| | | "DCC SEND STARTKEYLOGGER 0 0 0", |
| | | "Scunthorpe General Hospital", |
| | | "Penistone Community Church", |
| | | "Lightwater Country Park", |
| | | "Jimmy Clitheroe", |
| | | "Horniman Museum", |
| | | "shitake mushrooms", |
| | | "RomansInSussex.co.uk", |
| | | "http://www.cum.qc.ca/", |
| | | "Craig Cockburn, Software Specialist", |
| | | "Linda Callahan", |
| | | "Dr. Herman I. Libshitz", |
| | | "magna cum laude", |
| | | "Super Bowl XXX", |
| | | "medieval erection of parapets", |
| | | "evaluate", |
| | | "mocha", |
| | | "expression", |
| | | "Arsenal canal", |
| | | "classic", |
| | | "Tyson Gay", |
| | | "Dick Van Dyke", |
| | | "basement", |
| | | "If you're reading this, you've been in a coma for almost 20 years now. We're trying a new technique. We don't know where this message will end up in your dream, but we hope it works. Please wake up, we miss you.", |
| | | "Roses are \u001b[0;31mred\u001b[0m, violets are \u001b[0;34mblue. Hope you enjoy terminal hue", |
| | | "But now...\u001b[20Cfor my greatest trick...\u001b[8m", |
| | | "The quic\b\b\b\b\b\bk brown fo\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007x... [Beeeep]", |
| | | "Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗" |
| | | ] |
| New file |
| | |
| | | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | part 'json_literal.g.dart'; |
| | | |
| | | @JsonLiteral('json_literal.json') |
| | | List get data => _$dataJsonLiteral; |
| | | |
| | | @JsonLiteral('json_literal.json', asConst: true) |
| | | List get asConst => _$asConstJsonLiteral; |
| | | |
| | | /// From https://github.com/minimaxir/big-list-of-naughty-strings |
| | | /// blns.json @ 96f50492b278aeb2bfa40c4acbdbf6311312bf30 |
| | | @JsonLiteral('big-list-of-naughty-strings.json', asConst: true) |
| | | List get naughtyStrings => _$naughtyStringsJsonLiteral; |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'json_literal.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonLiteralGenerator |
| | | // ************************************************************************** |
| | | |
| | | final _$dataJsonLiteral = [ |
| | | { |
| | | 'backspace': '\b', |
| | | 'tab': '\t', |
| | | 'new line': '\n', |
| | | 'vertical tab': '\v', |
| | | 'form feed': '\r', |
| | | 'carriage return': '\r', |
| | | 'delete': '\x7F' |
| | | }, |
| | | 'simple string', |
| | | "'string with single quotes'", |
| | | '"string with double quotes"', |
| | | '\'With singles and \"doubles\"\'', |
| | | r'dollar $igns', |
| | | r"'single quotes and dollor $ig$'", |
| | | r"${'nice!'}", |
| | | '""hello""', |
| | | r'""$double quotes and dollar signs""', |
| | | '\$scary with \'single quotes\' and triple-doubles \"\"\"oh no!', |
| | | 'Dollar signs: \$ vs \\\$ vs \\\\\$', |
| | | 'Slashes \\nice slash\\', |
| | | 'slashes \\ and dollars \$ with white \n space', |
| | | "'''triple quoted strings should be\nfine!'''", |
| | | '"""as with triple-double-quotes"""', |
| | | '\"\"\"as with triple-double-quotes even when \'mixed\'\"\"\"', |
| | | null, |
| | | true, |
| | | false, |
| | | 5, |
| | | 5.5351, |
| | | -5.5, |
| | | {}, |
| | | { |
| | | 'null': null, |
| | | 'int': 42, |
| | | 'double': 42.0, |
| | | 'string': 'string', |
| | | 'list': [], |
| | | 'bool': true |
| | | } |
| | | ]; |
| | | |
| | | const _$asConstJsonLiteral = [ |
| | | { |
| | | 'backspace': '\b', |
| | | 'tab': '\t', |
| | | 'new line': '\n', |
| | | 'vertical tab': '\v', |
| | | 'form feed': '\r', |
| | | 'carriage return': '\r', |
| | | 'delete': '\x7F' |
| | | }, |
| | | 'simple string', |
| | | "'string with single quotes'", |
| | | '"string with double quotes"', |
| | | '\'With singles and \"doubles\"\'', |
| | | r'dollar $igns', |
| | | r"'single quotes and dollor $ig$'", |
| | | r"${'nice!'}", |
| | | '""hello""', |
| | | r'""$double quotes and dollar signs""', |
| | | '\$scary with \'single quotes\' and triple-doubles \"\"\"oh no!', |
| | | 'Dollar signs: \$ vs \\\$ vs \\\\\$', |
| | | 'Slashes \\nice slash\\', |
| | | 'slashes \\ and dollars \$ with white \n space', |
| | | "'''triple quoted strings should be\nfine!'''", |
| | | '"""as with triple-double-quotes"""', |
| | | '\"\"\"as with triple-double-quotes even when \'mixed\'\"\"\"', |
| | | null, |
| | | true, |
| | | false, |
| | | 5, |
| | | 5.5351, |
| | | -5.5, |
| | | {}, |
| | | { |
| | | 'null': null, |
| | | 'int': 42, |
| | | 'double': 42.0, |
| | | 'string': 'string', |
| | | 'list': [], |
| | | 'bool': true |
| | | } |
| | | ]; |
| | | |
| | | const _$naughtyStringsJsonLiteral = [ |
| | | '', |
| | | 'undefined', |
| | | 'undef', |
| | | 'null', |
| | | 'NULL', |
| | | '(null)', |
| | | 'nil', |
| | | 'NIL', |
| | | 'true', |
| | | 'false', |
| | | 'True', |
| | | 'False', |
| | | 'TRUE', |
| | | 'FALSE', |
| | | 'None', |
| | | 'hasOwnProperty', |
| | | '\\', |
| | | '\\\\', |
| | | '0', |
| | | '1', |
| | | '1.00', |
| | | r'$1.00', |
| | | '1/2', |
| | | '1E2', |
| | | '1E02', |
| | | '1E+02', |
| | | '-1', |
| | | '-1.00', |
| | | r'-$1.00', |
| | | '-1/2', |
| | | '-1E2', |
| | | '-1E02', |
| | | '-1E+02', |
| | | '1/0', |
| | | '0/0', |
| | | '-2147483648/-1', |
| | | '-9223372036854775808/-1', |
| | | '-0', |
| | | '-0.0', |
| | | '+0', |
| | | '+0.0', |
| | | '0.00', |
| | | '0..0', |
| | | '.', |
| | | '0.0.0', |
| | | '0,00', |
| | | '0,,0', |
| | | ',', |
| | | '0,0,0', |
| | | '0.0/0', |
| | | '1.0/0.0', |
| | | '0.0/0.0', |
| | | '1,0/0,0', |
| | | '0,0/0,0', |
| | | '--1', |
| | | '-', |
| | | '-.', |
| | | '-,', |
| | | '999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999', |
| | | 'NaN', |
| | | 'Infinity', |
| | | '-Infinity', |
| | | 'INF', |
| | | '1#INF', |
| | | '-1#IND', |
| | | '1#QNAN', |
| | | '1#SNAN', |
| | | '1#IND', |
| | | '0x0', |
| | | '0xffffffff', |
| | | '0xffffffffffffffff', |
| | | '0xabad1dea', |
| | | '123456789012345678901234567890123456789', |
| | | '1,000.00', |
| | | '1 000.00', |
| | | "1'000.00", |
| | | '1,000,000.00', |
| | | '1 000 000.00', |
| | | "1'000'000.00", |
| | | '1.000,00', |
| | | '1 000,00', |
| | | "1'000,00", |
| | | '1.000.000,00', |
| | | '1 000 000,00', |
| | | "1'000'000,00", |
| | | '01000', |
| | | '08', |
| | | '09', |
| | | '2.2250738585072011e-308', |
| | | ",./;'[]\\-=", |
| | | '<>?:"{}|_+', |
| | | r'!@#$%^&*()`~', |
| | | '\x01\x02\x03\x04\x05\x06\x07\b\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F', |
| | | '', |
| | | '\t\v\f
', |
| | | '', |
| | | '', |
| | | '', |
| | | 'Ω≈ç√∫˜µ≤≥÷', |
| | | 'åß∂ƒ©˙∆˚¬…æ', |
| | | 'œ∑´®†¥¨ˆøπ“‘', |
| | | '¡™£¢∞§¶•ªº–≠', |
| | | '¸˛Ç◊ı˜Â¯˘¿', |
| | | 'ÅÍÎÏ˝ÓÔÒÚÆ☃', |
| | | 'Œ„´‰ˇÁ¨ˆØ∏”’', |
| | | '`⁄€‹›fifl‡°·‚—±', |
| | | '⅛⅜⅝⅞', |
| | | 'ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя', |
| | | '٠١٢٣٤٥٦٧٨٩', |
| | | '⁰⁴⁵', |
| | | '₀₁₂', |
| | | '⁰⁴⁵₀₁₂', |
| | | 'ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็', |
| | | "'", |
| | | '"', |
| | | "''", |
| | | '""', |
| | | '\'\"\'', |
| | | '\"\'\'\'\'\"\'\"', |
| | | '\"\'\"\'\"\'\'\'\'\"', |
| | | '<foo val=“bar” />', |
| | | '<foo val=“bar” />', |
| | | '<foo val=”bar“ />', |
| | | "<foo val=`bar' />", |
| | | '田中さんにあげて下さい', |
| | | 'パーティーへ行かないか', |
| | | '和製漢語', |
| | | '部落格', |
| | | '사회과학원 어학연구소', |
| | | '찦차를 타고 온 펲시맨과 쑛다리 똠방각하', |
| | | '社會科學院語學研究所', |
| | | '울란바토르', |
| | | '𠜎𠜱𠝹𠱓𠱸𠲖𠳏', |
| | | 'Ⱥ', |
| | | 'Ⱦ', |
| | | 'ヽ༼ຈل͜ຈ༽ノ ヽ༼ຈل͜ຈ༽ノ ', |
| | | '(。◕ ∀ ◕。)', |
| | | '`ィ(´∀`∩', |
| | | '__ロ(,_,*)', |
| | | '・( ̄∀ ̄)・:*:', |
| | | '゚・✿ヾ╲(。◕‿◕。)╱✿・゚', |
| | | ',。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’', |
| | | '(╯°□°)╯︵ ┻━┻)', |
| | | '(ノಥ益ಥ)ノ ┻━┻', |
| | | '┬─┬ノ( º _ ºノ)', |
| | | '( ͡° ͜ʖ ͡°)', |
| | | '😍', |
| | | '👩🏽', |
| | | '👾 🙇 💁 🙅 🙆 🙋 🙎 🙍', |
| | | '🐵 🙈 🙉 🙊', |
| | | '❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙', |
| | | '✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿', |
| | | '🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧', |
| | | '0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟', |
| | | '🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸', |
| | | '🇺🇸🇷🇺🇸🇦🇫🇦🇲', |
| | | '🇺🇸🇷🇺🇸🇦', |
| | | '123', |
| | | '١٢٣', |
| | | 'ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو.', |
| | | 'בְּרֵאשִׁית, בָּרָא אֱלֹהִים, אֵת הַשָּׁמַיִם, וְאֵת הָאָרֶץ', |
| | | 'הָיְתָהtestالصفحات التّحول', |
| | | '﷽', |
| | | 'ﷺ', |
| | | 'مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ، ', |
| | | '', |
| | | ' ', |
| | | '', |
| | | ' ', |
| | | '', |
| | | '␣', |
| | | '␢', |
| | | '␡', |
| | | 'test', |
| | | 'test', |
| | | '
test
', |
| | | 'testtest', |
| | | 'test', |
| | | 'Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣', |
| | | '̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰', |
| | | '̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟', |
| | | '̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕', |
| | | 'Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮', |
| | | "˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥", |
| | | r'00˙Ɩ$-', |
| | | 'The quick brown fox jumps over the lazy dog', |
| | | '𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠', |
| | | '𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌', |
| | | '𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈', |
| | | '𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰', |
| | | '𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘', |
| | | '𝚃𝚑𝚎 𝚚𝚞𝚒𝚌𝚔 𝚋𝚛𝚘𝚠𝚗 𝚏𝚘𝚡 𝚓𝚞𝚖𝚙𝚜 𝚘𝚟𝚎𝚛 𝚝𝚑𝚎 𝚕𝚊𝚣𝚢 𝚍𝚘𝚐', |
| | | '⒯⒣⒠ ⒬⒰⒤⒞⒦ ⒝⒭⒪⒲⒩ ⒡⒪⒳ ⒥⒰⒨⒫⒮ ⒪⒱⒠⒭ ⒯⒣⒠ ⒧⒜⒵⒴ ⒟⒪⒢', |
| | | '<script>alert(123)</script>', |
| | | '<script>alert('123');</script>', |
| | | '<img src=x onerror=alert(123) />', |
| | | '<svg><script>123<1>alert(123)</script>', |
| | | '"><script>alert(123)</script>', |
| | | "'><script>alert(123)</script>", |
| | | '><script>alert(123)</script>', |
| | | '</script><script>alert(123)</script>', |
| | | '< / script >< script >alert(123)< / script >', |
| | | ' onfocus=JaVaSCript:alert(123) autofocus', |
| | | '" onfocus=JaVaSCript:alert(123) autofocus', |
| | | "' onfocus=JaVaSCript:alert(123) autofocus", |
| | | '<script>alert(123)</script>', |
| | | '<sc<script>ript>alert(123)</sc</script>ript>', |
| | | '--><script>alert(123)</script>', |
| | | '";alert(123);t="', |
| | | "';alert(123);t='", |
| | | 'JavaSCript:alert(123)', |
| | | ';alert(123);', |
| | | 'src=JaVaSCript:prompt(132)', |
| | | '"><script>alert(123);</script x="', |
| | | "'><script>alert(123);</script x='", |
| | | '><script>alert(123);</script x=', |
| | | '" autofocus onkeyup="javascript:alert(123)', |
| | | "' autofocus onkeyup='javascript:alert(123)", |
| | | '<script\\x20type="text/javascript">javascript:alert(1);</script>', |
| | | '<script\\x3Etype="text/javascript">javascript:alert(1);</script>', |
| | | '<script\\x0Dtype="text/javascript">javascript:alert(1);</script>', |
| | | '<script\\x09type="text/javascript">javascript:alert(1);</script>', |
| | | '<script\\x0Ctype="text/javascript">javascript:alert(1);</script>', |
| | | '<script\\x2Ftype="text/javascript">javascript:alert(1);</script>', |
| | | '<script\\x0Atype="text/javascript">javascript:alert(1);</script>', |
| | | '\'`\"><\\x3Cscript>javascript:alert(1)</script>', |
| | | '\'`\"><\\x00script>javascript:alert(1)</script>', |
| | | 'ABC<div style="x\\x3Aexpression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:expression\\x5C(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:expression\\x00(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:exp\\x00ression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:exp\\x5Cression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\x0Aexpression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\x09expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE3\\x80\\x80expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x84expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xC2\\xA0expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x80expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x8Aexpression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\x0Dexpression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\x0Cexpression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x87expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xEF\\xBB\\xBFexpression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\x20expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x88expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\x00expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x8Bexpression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x86expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x85expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x82expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\x0Bexpression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x81expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x83expression(javascript:alert(1)">DEF', |
| | | 'ABC<div style="x:\\xE2\\x80\\x89expression(javascript:alert(1)">DEF', |
| | | '<a href="\\x0Bjavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x0Fjavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xC2\\xA0javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x05javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE1\\xA0\\x8Ejavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x18javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x11javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x88javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x89javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x80javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x17javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x03javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x0Ejavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x1Ajavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x00javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x10javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x82javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x20javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x13javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x09javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x8Ajavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x14javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x19javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\xAFjavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x1Fjavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x81javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x1Djavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x87javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x07javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE1\\x9A\\x80javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x83javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x04javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x01javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x08javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x84javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x86javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE3\\x80\\x80javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x12javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x0Djavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x0Ajavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x0Cjavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x15javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\xA8javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x16javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x02javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x1Bjavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x06javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\xA9javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x80\\x85javascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x1Ejavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\xE2\\x81\\x9Fjavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="\\x1Cjavascript:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="javascript\\x00:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="javascript\\x3A:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="javascript\\x09:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="javascript\\x0D:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '<a href="javascript\\x0A:javascript:alert(1)" id="fuzzelement1">test</a>', |
| | | '`\"\'><img src=xxx:x \\x0Aonerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x22onerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x0Bonerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x0Donerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x2Fonerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x09onerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x0Conerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x00onerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x27onerror=javascript:alert(1)>', |
| | | '`\"\'><img src=xxx:x \\x20onerror=javascript:alert(1)>', |
| | | '\"`\'><script>\\x3Bjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\x0Djavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xEF\\xBB\\xBFjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x81javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x84javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE3\\x80\\x80javascript:alert(1)</script>', |
| | | '\"`\'><script>\\x09javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x89javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x85javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x88javascript:alert(1)</script>', |
| | | '\"`\'><script>\\x00javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\xA8javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x8Ajavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE1\\x9A\\x80javascript:alert(1)</script>', |
| | | '\"`\'><script>\\x0Cjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\x2Bjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xF0\\x90\\x96\\x9Ajavascript:alert(1)</script>', |
| | | '\"`\'><script>-javascript:alert(1)</script>', |
| | | '\"`\'><script>\\x0Ajavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\xAFjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\x7Ejavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x87javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x81\\x9Fjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\xA9javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xC2\\x85javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xEF\\xBF\\xAEjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x83javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x8Bjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xEF\\xBF\\xBEjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x80javascript:alert(1)</script>', |
| | | '\"`\'><script>\\x21javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x82javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE2\\x80\\x86javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xE1\\xA0\\x8Ejavascript:alert(1)</script>', |
| | | '\"`\'><script>\\x0Bjavascript:alert(1)</script>', |
| | | '\"`\'><script>\\x20javascript:alert(1)</script>', |
| | | '\"`\'><script>\\xC2\\xA0javascript:alert(1)</script>', |
| | | '<img \\x00src=x onerror="alert(1)">', |
| | | '<img \\x47src=x onerror="javascript:alert(1)">', |
| | | '<img \\x11src=x onerror="javascript:alert(1)">', |
| | | '<img \\x12src=x onerror="javascript:alert(1)">', |
| | | '<img\\x47src=x onerror="javascript:alert(1)">', |
| | | '<img\\x10src=x onerror="javascript:alert(1)">', |
| | | '<img\\x13src=x onerror="javascript:alert(1)">', |
| | | '<img\\x32src=x onerror="javascript:alert(1)">', |
| | | '<img\\x47src=x onerror="javascript:alert(1)">', |
| | | '<img\\x11src=x onerror="javascript:alert(1)">', |
| | | '<img \\x47src=x onerror="javascript:alert(1)">', |
| | | '<img \\x34src=x onerror="javascript:alert(1)">', |
| | | '<img \\x39src=x onerror="javascript:alert(1)">', |
| | | '<img \\x00src=x onerror="javascript:alert(1)">', |
| | | '<img src\\x09=x onerror="javascript:alert(1)">', |
| | | '<img src\\x10=x onerror="javascript:alert(1)">', |
| | | '<img src\\x13=x onerror="javascript:alert(1)">', |
| | | '<img src\\x32=x onerror="javascript:alert(1)">', |
| | | '<img src\\x12=x onerror="javascript:alert(1)">', |
| | | '<img src\\x11=x onerror="javascript:alert(1)">', |
| | | '<img src\\x00=x onerror="javascript:alert(1)">', |
| | | '<img src\\x47=x onerror="javascript:alert(1)">', |
| | | '<img src=x\\x09onerror="javascript:alert(1)">', |
| | | '<img src=x\\x10onerror="javascript:alert(1)">', |
| | | '<img src=x\\x11onerror="javascript:alert(1)">', |
| | | '<img src=x\\x12onerror="javascript:alert(1)">', |
| | | '<img src=x\\x13onerror="javascript:alert(1)">', |
| | | '<img[a][b][c]src[d]=x[e]onerror=[f]"alert(1)">', |
| | | '<img src=x onerror=\\x09"javascript:alert(1)">', |
| | | '<img src=x onerror=\\x10"javascript:alert(1)">', |
| | | '<img src=x onerror=\\x11"javascript:alert(1)">', |
| | | '<img src=x onerror=\\x12"javascript:alert(1)">', |
| | | '<img src=x onerror=\\x32"javascript:alert(1)">', |
| | | '<img src=x onerror=\\x00"javascript:alert(1)">', |
| | | '<a href=javascript:javascript:alert(1)>XXX</a>', |
| | | '<img src="x` `<script>javascript:alert(1)</script>"` `>', |
| | | '<img src onerror /\" \'\"= alt=javascript:alert(1)//\">', |
| | | '<title onpropertychange=javascript:alert(1)></title><title title=>', |
| | | '<a href=http://foo.bar/#x=`y></a><img alt="`><img src=x:x onerror=javascript:alert(1)></a>">', |
| | | '<!--[if]><script>javascript:alert(1)</script -->', |
| | | '<!--[if<img src=x onerror=javascript:alert(1)//]> -->', |
| | | '<script src="/\\%(jscript)s"></script>', |
| | | '<script src="\\\\%(jscript)s"></script>', |
| | | '<IMG """><SCRIPT>alert("XSS")</SCRIPT>">', |
| | | '<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>', |
| | | '<IMG SRC=# onmouseover=\"alert(\'xxs\')\">', |
| | | '<IMG SRC= onmouseover=\"alert(\'xxs\')\">', |
| | | '<IMG onmouseover=\"alert(\'xxs\')\">', |
| | | '<IMG SRC=javascript:alert('XSS')>', |
| | | '<IMG SRC=javascript:alert('XSS')>', |
| | | '<IMG SRC=javascript:alert('XSS')>', |
| | | '<IMG SRC=\"jav ascript:alert(\'XSS\');\">', |
| | | '<IMG SRC=\"jav	ascript:alert(\'XSS\');\">', |
| | | '<IMG SRC=\"jav
ascript:alert(\'XSS\');\">', |
| | | '<IMG SRC=\"jav
ascript:alert(\'XSS\');\">', |
| | | 'perl -e \'print \"<IMG SRC=java\\0script:alert(\\\"XSS\\\")>\";\' > out', |
| | | '<IMG SRC=\"  javascript:alert(\'XSS\');\">', |
| | | '<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>', |
| | | '<BODY onload!#\$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>', |
| | | '<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>', |
| | | '<<SCRIPT>alert("XSS");//<</SCRIPT>', |
| | | '<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >', |
| | | '<SCRIPT SRC=//ha.ckers.org/.j>', |
| | | '<IMG SRC=\"javascript:alert(\'XSS\')\"', |
| | | '<iframe src=http://ha.ckers.org/scriptlet.html <', |
| | | '\\\";alert(\'XSS\');//', |
| | | '<u oncopy=alert()> Copy me</u>', |
| | | '<i onwheel=alert(1)> Scroll over me </i>', |
| | | '<plaintext>', |
| | | 'http://a/%%30%30', |
| | | '</textarea><script>alert(123)</script>', |
| | | '1;DROP TABLE users', |
| | | "1'; DROP TABLE users-- 1", |
| | | "' OR 1=1 -- 1", |
| | | "' OR '1'='1", |
| | | ' ', |
| | | '%', |
| | | '_', |
| | | '-', |
| | | '--', |
| | | '--version', |
| | | '--help', |
| | | r'$USER', |
| | | '/dev/null; touch /tmp/blns.fail ; echo', |
| | | '`touch /tmp/blns.fail`', |
| | | r'$(touch /tmp/blns.fail)', |
| | | '@{[system "touch /tmp/blns.fail"]}', |
| | | 'eval(\"puts \'hello world\'\")', |
| | | 'System("ls -al /")', |
| | | '`ls -al /`', |
| | | 'Kernel.exec("ls -al /")', |
| | | 'Kernel.exit(1)', |
| | | "%x('ls -al /')", |
| | | '<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>', |
| | | r'$HOME', |
| | | r"$ENV{'HOME'}", |
| | | '%d', |
| | | '%s', |
| | | '{0}', |
| | | '%*.*s', |
| | | 'File:///', |
| | | '../../../../../../../../../../../etc/passwd%00', |
| | | '../../../../../../../../../../../etc/hosts', |
| | | '() { 0; }; touch /tmp/blns.shellshock1.fail;', |
| | | r'() { _; } >_[$($())] { touch /tmp/blns.shellshock2.fail; }', |
| | | "<<< %s(un='%s') = %u", |
| | | '+++ATH0', |
| | | 'CON', |
| | | 'PRN', |
| | | 'AUX', |
| | | r'CLOCK$', |
| | | 'NUL', |
| | | 'A:', |
| | | 'ZZ:', |
| | | 'COM1', |
| | | 'LPT1', |
| | | 'LPT2', |
| | | 'LPT3', |
| | | 'COM2', |
| | | 'COM3', |
| | | 'COM4', |
| | | 'DCC SEND STARTKEYLOGGER 0 0 0', |
| | | 'Scunthorpe General Hospital', |
| | | 'Penistone Community Church', |
| | | 'Lightwater Country Park', |
| | | 'Jimmy Clitheroe', |
| | | 'Horniman Museum', |
| | | 'shitake mushrooms', |
| | | 'RomansInSussex.co.uk', |
| | | 'http://www.cum.qc.ca/', |
| | | 'Craig Cockburn, Software Specialist', |
| | | 'Linda Callahan', |
| | | 'Dr. Herman I. Libshitz', |
| | | 'magna cum laude', |
| | | 'Super Bowl XXX', |
| | | 'medieval erection of parapets', |
| | | 'evaluate', |
| | | 'mocha', |
| | | 'expression', |
| | | 'Arsenal canal', |
| | | 'classic', |
| | | 'Tyson Gay', |
| | | 'Dick Van Dyke', |
| | | 'basement', |
| | | "If you're reading this, you've been in a coma for almost 20 years now. We're trying a new technique. We don't know where this message will end up in your dream, but we hope it works. Please wake up, we miss you.", |
| | | 'Roses are \x1B[0;31mred\x1B[0m, violets are \x1B[0;34mblue. Hope you enjoy terminal hue', |
| | | 'But now...\x1B[20Cfor my greatest trick...\x1B[8m', |
| | | 'The quic\b\b\b\b\b\bk brown fo\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07x... [Beeeep]', |
| | | 'Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗' |
| | | ]; |
| New file |
| | |
| | | [ |
| | | { |
| | | "backspace": "\b", |
| | | "tab": "\t", |
| | | "new line": "\n", |
| | | "vertical tab": "\u000b", |
| | | "form feed": "\r", |
| | | "carriage return": "\r", |
| | | "delete": "\u007F" |
| | | }, |
| | | "simple string", |
| | | "'string with single quotes'", |
| | | "\"string with double quotes\"", |
| | | "'With singles and \"doubles\"'", |
| | | "dollar $igns", |
| | | "'single quotes and dollor $ig$'", |
| | | "${'nice!'}", |
| | | "\"\"hello\"\"", |
| | | "\"\"$double quotes and dollar signs\"\"", |
| | | "$scary with 'single quotes' and triple-doubles \"\"\"oh no!", |
| | | "Dollar signs: $ vs \\$ vs \\\\$", |
| | | "Slashes \\nice slash\\", |
| | | "slashes \\ and dollars $ with white \n space", |
| | | "'''triple quoted strings should be\nfine!'''", |
| | | "\"\"\"as with triple-double-quotes\"\"\"", |
| | | "\"\"\"as with triple-double-quotes even when 'mixed'\"\"\"", |
| | | null, |
| | | true, |
| | | false, |
| | | 5, |
| | | 5.5351, |
| | | -5.5, |
| | | {}, |
| | | { |
| | | "null": null, |
| | | "int": 42, |
| | | "double": 42.0, |
| | | "string": "string", |
| | | "list": [], |
| | | "bool": true |
| | | } |
| | | ] |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | @TestOn('vm') |
| | | |
| | | import 'dart:convert'; |
| | | import 'dart:io'; |
| | | |
| | | import 'package:test/test.dart'; |
| | | |
| | | import '../test_file_utils.dart'; |
| | | import '../test_utils.dart'; |
| | | import 'json_literal.dart'; |
| | | |
| | | void main() { |
| | | test('literal round-trip', () { |
| | | final dataFilePath = testFilePath('test', 'literal', 'json_literal.json'); |
| | | final dataFile = File(dataFilePath); |
| | | |
| | | final dataString = loudEncode(json.decode(dataFile.readAsStringSync())); |
| | | // FYI: nice to re-write the test data when it's changed to keep it pretty |
| | | // ... but not a good idea to ship this |
| | | // dataFile.writeAsStringSync(dataString.replaceAll('\u007F', '\\u007F')); |
| | | final dartString = loudEncode(data); |
| | | |
| | | expect(dartString, dataString); |
| | | }); |
| | | |
| | | test('naughty strings', () { |
| | | final dataFilePath = |
| | | testFilePath('test', 'literal', 'big-list-of-naughty-strings.json'); |
| | | final dataFile = File(dataFilePath); |
| | | |
| | | final dataString = loudEncode(json.decode(dataFile.readAsStringSync())); |
| | | final dartString = loudEncode(naughtyStrings); |
| | | |
| | | expect(dartString, dataString); |
| | | }); |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | @TestOn('vm') |
| | | |
| | | import 'dart:io'; |
| | | |
| | | import 'package:test/test.dart'; |
| | | import 'package:path/path.dart' as p; |
| | | |
| | | void main() { |
| | | test('README example', () { |
| | | final readmeContent = File('README.md').readAsStringSync(); |
| | | |
| | | final exampleContent = _getExampleContent('example.dart'); |
| | | expect(readmeContent, contains(exampleContent)); |
| | | |
| | | final exampleGeneratedContent = _getExampleContent('example.g.dart'); |
| | | expect(readmeContent, contains(exampleGeneratedContent)); |
| | | }); |
| | | } |
| | | |
| | | String _getExampleContent(String fileName) { |
| | | final lines = File(p.join('example', fileName)).readAsLinesSync(); |
| | | |
| | | var lastHadContent = false; |
| | | |
| | | // All lines with content, except those starting with `/`. |
| | | // Also exclude blank lines that follow other blank lines |
| | | final cleanedSource = lines.where((l) { |
| | | if (l.startsWith(r'/')) { |
| | | return false; |
| | | } |
| | | |
| | | if (l.trim().isNotEmpty) { |
| | | lastHadContent = true; |
| | | return true; |
| | | } |
| | | |
| | | if (lastHadContent) { |
| | | lastHadContent = false; |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | }).join('\n'); |
| | | |
| | | return ''' |
| | | ```dart |
| | | $cleanedSource |
| | | ```'''; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | final jsonSerializableFields = generatorConfigDefaultJson.keys.toList(); |
| | | |
| | | final generatorConfigDefaultJson = Map<String, dynamic>.unmodifiable( |
| | | const JsonSerializable().withDefaults().toJson()); |
| | | |
| | | final generatorConfigNonDefaultJson = |
| | | Map<String, dynamic>.unmodifiable(const JsonSerializable( |
| | | anyMap: true, |
| | | checked: true, |
| | | createFactory: false, |
| | | createToJson: false, |
| | | disallowUnrecognizedKeys: true, |
| | | explicitToJson: true, |
| | | fieldRename: FieldRename.kebab, |
| | | generateToJsonFunction: false, |
| | | includeIfNull: false, |
| | | nullable: false, |
| | | useWrappers: true, |
| | | ).toJson()); |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | //ignore_for_file: avoid_unused_constructor_parameters, prefer_initializing_formals |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | |
| | | import 'annotation.dart'; |
| | | |
| | | part 'checked_test_input.dart'; |
| | | part 'configuration_input.dart'; |
| | | part 'default_value_input.dart'; |
| | | part 'field_namer_input.dart'; |
| | | part 'generic_test_input.dart'; |
| | | part 'inheritance_test_input.dart'; |
| | | part 'json_converter_test_input.dart'; |
| | | part 'setter_test_input.dart'; |
| | | part 'to_from_json_test_input.dart'; |
| | | |
| | | @ShouldThrow('Generator cannot target `theAnswer`.', |
| | | 'Remove the JsonSerializable annotation from `theAnswer`.') |
| | | @JsonSerializable() |
| | | const theAnswer = 42; |
| | | |
| | | @ShouldThrow('Generator cannot target `annotatedMethod`.', |
| | | 'Remove the JsonSerializable annotation from `annotatedMethod`.') |
| | | @JsonSerializable() |
| | | void annotatedMethod() => null; |
| | | |
| | | @ShouldGenerate(r''' |
| | | Person _$PersonFromJson(Map<String, dynamic> json) { |
| | | return Person() |
| | | ..firstName = json['firstName'] as String |
| | | ..lastName = json['lastName'] as String |
| | | ..height = json['h'] as int |
| | | ..dateOfBirth = json['dateOfBirth'] == null |
| | | ? null |
| | | : DateTime.parse(json['dateOfBirth'] as String) |
| | | ..dynamicType = json['dynamicType'] |
| | | ..varType = json['varType'] |
| | | ..listOfInts = (json['listOfInts'] as List)?.map((e) => e as int)?.toList(); |
| | | } |
| | | |
| | | Map<String, dynamic> _$PersonToJson(Person instance) => <String, dynamic>{ |
| | | 'firstName': instance.firstName, |
| | | 'lastName': instance.lastName, |
| | | 'h': instance.height, |
| | | 'dateOfBirth': instance.dateOfBirth?.toIso8601String(), |
| | | 'dynamicType': instance.dynamicType, |
| | | 'varType': instance.varType, |
| | | 'listOfInts': instance.listOfInts |
| | | }; |
| | | ''') |
| | | @JsonSerializable() |
| | | class Person { |
| | | String firstName, lastName; |
| | | @JsonKey(name: 'h') |
| | | int height; |
| | | DateTime dateOfBirth; |
| | | dynamic dynamicType; |
| | | //ignore: prefer_typing_uninitialized_variables |
| | | var varType; |
| | | List<int> listOfInts; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Order _$OrderFromJson(Map<String, dynamic> json) { |
| | | return Order(json['height'] as int, json['firstName'] as String, |
| | | json['lastName'] as String) |
| | | ..dateOfBirth = json['dateOfBirth'] == null |
| | | ? null |
| | | : DateTime.parse(json['dateOfBirth'] as String); |
| | | } |
| | | |
| | | Map<String, dynamic> _$OrderToJson(Order instance) => <String, dynamic>{ |
| | | 'firstName': instance.firstName, |
| | | 'lastName': instance.lastName, |
| | | 'height': instance.height, |
| | | 'dateOfBirth': instance.dateOfBirth?.toIso8601String() |
| | | }; |
| | | ''') |
| | | @JsonSerializable() |
| | | class Order { |
| | | final String firstName, lastName; |
| | | int height; |
| | | DateTime dateOfBirth; |
| | | |
| | | Order(this.height, String firstName, [this.lastName]) : firstName = firstName; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | FinalFields _$FinalFieldsFromJson(Map<String, dynamic> json) { |
| | | return FinalFields(json['a'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$FinalFieldsToJson(FinalFields instance) => |
| | | <String, dynamic>{'a': instance.a}; |
| | | ''') |
| | | @JsonSerializable() |
| | | class FinalFields { |
| | | final int a; |
| | | int get b => 4; |
| | | |
| | | FinalFields(this.a); |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | FinalFieldsNotSetInCtor _$FinalFieldsNotSetInCtorFromJson( |
| | | Map<String, dynamic> json) { |
| | | return FinalFieldsNotSetInCtor(); |
| | | } |
| | | |
| | | Map<String, dynamic> _$FinalFieldsNotSetInCtorToJson( |
| | | FinalFieldsNotSetInCtor instance) => |
| | | <String, dynamic>{}; |
| | | ''') |
| | | @JsonSerializable() |
| | | class FinalFieldsNotSetInCtor { |
| | | final int a = 1; |
| | | |
| | | FinalFieldsNotSetInCtor(); |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | SetSupport _$SetSupportFromJson(Map<String, dynamic> json) { |
| | | return SetSupport((json['values'] as List)?.map((e) => e as int)?.toSet()); |
| | | } |
| | | |
| | | Map<String, dynamic> _$SetSupportToJson(SetSupport instance) => |
| | | <String, dynamic>{'values': instance.values?.toList()}; |
| | | ''') |
| | | @JsonSerializable() |
| | | class SetSupport { |
| | | final Set<int> values; |
| | | |
| | | SetSupport(this.values); |
| | | } |
| | | |
| | | @JsonSerializable(createToJson: false) |
| | | class FromJsonOptionalParameters { |
| | | final ChildWithFromJson child; |
| | | |
| | | FromJsonOptionalParameters(this.child); |
| | | } |
| | | |
| | | class ChildWithFromJson { |
| | | ChildWithFromJson.fromJson(json, {initValue = false}); |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class ParentObject { |
| | | int number; |
| | | String str; |
| | | ChildObject child; |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class ChildObject { |
| | | int number; |
| | | String str; |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class ParentObjectWithChildren { |
| | | int number; |
| | | String str; |
| | | List<ChildObject> children; |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class ParentObjectWithDynamicChildren { |
| | | int number; |
| | | String str; |
| | | List<dynamic> children; |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class UnknownCtorParamType { |
| | | int number; |
| | | |
| | | // ignore: undefined_class, field_initializer_not_assignable |
| | | UnknownCtorParamType(Bob number) : number = number; |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class UnknownFieldType { |
| | | // ignore: undefined_class |
| | | Bob number; |
| | | } |
| | | |
| | | @JsonSerializable(createFactory: false) |
| | | class UnknownFieldTypeToJsonOnly { |
| | | // ignore: undefined_class |
| | | Bob number; |
| | | } |
| | | |
| | | @JsonSerializable() |
| | | class UnknownFieldTypeWithConvert { |
| | | @JsonKey(fromJson: _everythingIs42, toJson: _everythingIs42) |
| | | // ignore: undefined_class |
| | | Bob number; |
| | | } |
| | | |
| | | dynamic _everythingIs42(Object input) => 42; |
| | | |
| | | @JsonSerializable(createFactory: false) |
| | | class NoSerializeFieldType { |
| | | Stopwatch watch; |
| | | } |
| | | |
| | | @JsonSerializable(createToJson: false) |
| | | class NoDeserializeFieldType { |
| | | Stopwatch watch; |
| | | } |
| | | |
| | | @JsonSerializable(createFactory: false) |
| | | class NoSerializeBadKey { |
| | | Map<int, DateTime> intDateTimeMap; |
| | | } |
| | | |
| | | @JsonSerializable(createToJson: false) |
| | | class NoDeserializeBadKey { |
| | | Map<int, DateTime> intDateTimeMap; |
| | | } |
| | | |
| | | @JsonSerializable(createFactory: false) |
| | | class IncludeIfNullAll { |
| | | @JsonKey(includeIfNull: true) |
| | | int number; |
| | | String str; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> _$IncludeIfNullOverrideToJson( |
| | | IncludeIfNullOverride instance) { |
| | | final val = <String, dynamic>{ |
| | | 'number': instance.number, |
| | | }; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('str', instance.str); |
| | | return val; |
| | | } |
| | | ''') |
| | | @JsonSerializable(createFactory: false, includeIfNull: false) |
| | | class IncludeIfNullOverride { |
| | | @JsonKey(includeIfNull: true) |
| | | int number; |
| | | String str; |
| | | } |
| | | |
| | | // https://github.com/dart-lang/json_serializable/issues/7 regression |
| | | @JsonSerializable() |
| | | class NoCtorClass { |
| | | final int member; |
| | | |
| | | factory NoCtorClass.fromJson(Map<String, dynamic> json) => null; |
| | | } |
| | | |
| | | @ShouldThrow('More than one field has the JSON key `str`.', |
| | | 'Check the `JsonKey` annotations on fields.') |
| | | @JsonSerializable(createFactory: false) |
| | | class KeyDupesField { |
| | | @JsonKey(name: 'str') |
| | | int number; |
| | | |
| | | String str; |
| | | } |
| | | |
| | | @ShouldThrow('More than one field has the JSON key `a`.', |
| | | 'Check the `JsonKey` annotations on fields.') |
| | | @JsonSerializable(createFactory: false) |
| | | class DupeKeys { |
| | | @JsonKey(name: 'a') |
| | | int number; |
| | | |
| | | @JsonKey(name: 'a') |
| | | String str; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> _$IgnoredFieldClassToJson(IgnoredFieldClass instance) => |
| | | <String, dynamic>{ |
| | | 'ignoredFalseField': instance.ignoredFalseField, |
| | | 'ignoredNullField': instance.ignoredNullField |
| | | }; |
| | | ''') |
| | | @JsonSerializable(createFactory: false) |
| | | class IgnoredFieldClass { |
| | | @JsonKey(ignore: true) |
| | | int ignoredTrueField; |
| | | |
| | | @JsonKey(ignore: false) |
| | | int ignoredFalseField; |
| | | |
| | | int ignoredNullField; |
| | | } |
| | | |
| | | @ShouldThrow('Cannot populate the required constructor argument: ' |
| | | 'ignoredTrueField. It is assigned to an ignored field.') |
| | | @JsonSerializable() |
| | | class IgnoredFieldCtorClass { |
| | | @JsonKey(ignore: true) |
| | | int ignoredTrueField; |
| | | IgnoredFieldCtorClass(this.ignoredTrueField); |
| | | } |
| | | |
| | | @ShouldThrow('Cannot populate the required constructor argument: ' |
| | | '_privateField. It is assigned to a private field.') |
| | | @JsonSerializable() |
| | | class PrivateFieldCtorClass { |
| | | // ignore: unused_field |
| | | int _privateField; |
| | | PrivateFieldCtorClass(this._privateField); |
| | | } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. ' |
| | | 'Cannot set both `disallowNullvalue` and `includeIfNull` to `true`. ' |
| | | 'This leads to incompatible `toJson` and `fromJson` behavior.') |
| | | @JsonSerializable() |
| | | class IncludeIfNullDisallowNullClass { |
| | | @JsonKey(includeIfNull: true, disallowNullValue: true) |
| | | int field; |
| | | } |
| | | |
| | | @JsonSerializable(createFactory: false) |
| | | class TrivialNestedNullable { |
| | | TrivialNestedNullable child; |
| | | int otherField; |
| | | } |
| | | |
| | | @JsonSerializable(createFactory: false, nullable: false) |
| | | class TrivialNestedNonNullable { |
| | | TrivialNestedNonNullable child; |
| | | int otherField; |
| | | } |
| | | |
| | | @ShouldThrow( |
| | | 'The `JsonValue` annotation on `BadEnum.value` does not have a value ' |
| | | 'of type String, int, or null.') |
| | | @JsonSerializable() |
| | | class JsonValueWithBool { |
| | | BadEnum field; |
| | | } |
| | | |
| | | enum BadEnum { |
| | | @JsonValue(true) |
| | | value |
| | | } |
| | | |
| | | @ShouldGenerate(r'''const _$GoodEnumEnumMap = <GoodEnum, dynamic>{ |
| | | GoodEnum.noAnnotation: 'noAnnotation', |
| | | GoodEnum.stringAnnotation: 'string annotation', |
| | | GoodEnum.stringAnnotationWeird: r"string annotation with $ funky 'values'", |
| | | GoodEnum.intValue: 42, |
| | | GoodEnum.nullValue: null |
| | | }; |
| | | ''', contains: true) |
| | | @JsonSerializable() |
| | | class JsonValueValid { |
| | | GoodEnum field; |
| | | } |
| | | |
| | | enum GoodEnum { |
| | | noAnnotation, |
| | | @JsonValue('string annotation') |
| | | stringAnnotation, |
| | | @JsonValue("string annotation with \$ funky 'values'") |
| | | stringAnnotationWeird, |
| | | @JsonValue(42) |
| | | intValue, |
| | | @JsonValue(null) |
| | | nullValue |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | class ShouldThrow { |
| | | final String errorMessage; |
| | | final String todo; |
| | | const ShouldThrow(this.errorMessage, [this.todo]); |
| | | } |
| | | |
| | | class ShouldGenerate { |
| | | final String expectedOutput; |
| | | final String expectedWrappedOutput; |
| | | final bool contains; |
| | | final List<String> expectedLogItems; |
| | | final bool checked; |
| | | const ShouldGenerate(this.expectedOutput, |
| | | {this.expectedWrappedOutput, |
| | | this.contains = false, |
| | | this.expectedLogItems = const [], |
| | | this.checked = false}); |
| | | } |
| New file |
| | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | @ShouldGenerate(r''' |
| | | WithANonCtorGetterChecked _$WithANonCtorGetterCheckedFromJson( |
| | | Map<String, dynamic> json) { |
| | | return $checkedNew('WithANonCtorGetterChecked', json, () { |
| | | $checkKeys(json, |
| | | allowedKeys: const ['items'], |
| | | requiredKeys: const ['items'], |
| | | disallowNullValues: const ['items']); |
| | | final val = WithANonCtorGetterChecked($checkedConvert( |
| | | json, 'items', (v) => (v as List)?.map((e) => e as String)?.toList())); |
| | | return val; |
| | | }); |
| | | } |
| | | ''', checked: true) |
| | | @JsonSerializable(disallowUnrecognizedKeys: true, createToJson: false) |
| | | class WithANonCtorGetterChecked { |
| | | @JsonKey(required: true, disallowNullValue: true) |
| | | final List<String> items; |
| | | int get legth => items.length; |
| | | |
| | | WithANonCtorGetterChecked(this.items); |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | WithANonCtorGetter _$WithANonCtorGetterFromJson(Map<String, dynamic> json) { |
| | | $checkKeys(json, |
| | | allowedKeys: const ['items'], |
| | | requiredKeys: const ['items'], |
| | | disallowNullValues: const ['items']); |
| | | return WithANonCtorGetter( |
| | | (json['items'] as List)?.map((e) => e as String)?.toList()); |
| | | } |
| | | ''') |
| | | @JsonSerializable(disallowUnrecognizedKeys: true, createToJson: false) |
| | | class WithANonCtorGetter { |
| | | @JsonKey(required: true, disallowNullValue: true) |
| | | final List<String> items; |
| | | int get legth => items.length; |
| | | |
| | | WithANonCtorGetter(this.items); |
| | | } |
| New file |
| | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | @JsonSerializable() |
| | | class ConfigurationImplicitDefaults { |
| | | int field; |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | anyMap: false, |
| | | checked: false, |
| | | createFactory: true, |
| | | createToJson: true, |
| | | disallowUnrecognizedKeys: false, |
| | | explicitToJson: false, |
| | | fieldRename: FieldRename.none, |
| | | generateToJsonFunction: true, |
| | | includeIfNull: true, |
| | | nullable: true, |
| | | useWrappers: false, |
| | | ) |
| | | class ConfigurationExplicitDefaults { |
| | | int field; |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | createToJson: true, |
| | | includeIfNull: true, |
| | | nullable: true, |
| | | disallowUnrecognizedKeys: true, |
| | | fieldRename: FieldRename.snake, |
| | | createFactory: true) |
| | | class ConfigurationAllDefaultsOpposite { |
| | | int field; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. ' |
| | | '`defaultValue` is `Symbol`, it must be a literal.') |
| | | @JsonSerializable() |
| | | class DefaultWithSymbol { |
| | | @JsonKey(defaultValue: #symbol) |
| | | Object field; |
| | | |
| | | DefaultWithSymbol(); |
| | | } |
| | | |
| | | int _function() => 42; |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. ' |
| | | '`defaultValue` is `Function`, it must be a literal.') |
| | | @JsonSerializable() |
| | | class DefaultWithFunction { |
| | | @JsonKey(defaultValue: _function) |
| | | Object field; |
| | | |
| | | DefaultWithFunction(); |
| | | } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. ' |
| | | '`defaultValue` is `Type`, it must be a literal.') |
| | | @JsonSerializable() |
| | | class DefaultWithType { |
| | | @JsonKey(defaultValue: Object) |
| | | Object field; |
| | | |
| | | DefaultWithType(); |
| | | } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. ' |
| | | '`defaultValue` is `Duration`, it must be a literal.') |
| | | @JsonSerializable() |
| | | class DefaultWithConstObject { |
| | | @JsonKey(defaultValue: Duration()) |
| | | Object field; |
| | | |
| | | DefaultWithConstObject(); |
| | | } |
| | | |
| | | enum Enum { value } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. ' |
| | | '`defaultValue` is `List > Enum`, it must be a literal.') |
| | | @JsonSerializable() |
| | | class DefaultWithNestedEnum { |
| | | @JsonKey(defaultValue: [Enum.value]) |
| | | Object field; |
| | | |
| | | DefaultWithNestedEnum(); |
| | | } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. ' |
| | | 'Cannot use `defaultValue` on a field with `nullable` false.') |
| | | @JsonSerializable() |
| | | class DefaultWithNonNullableField { |
| | | @JsonKey(defaultValue: 42, nullable: false) |
| | | Object field; |
| | | |
| | | DefaultWithNonNullableField(); |
| | | } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. ' |
| | | 'Cannot use `defaultValue` on a field with `nullable` false.') |
| | | @JsonSerializable(nullable: false) |
| | | class DefaultWithNonNullableClass { |
| | | @JsonKey(defaultValue: 42) |
| | | Object field; |
| | | |
| | | DefaultWithNonNullableClass(); |
| | | } |
| New file |
| | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> _$FieldNamerNoneToJson(FieldNamerNone instance) => |
| | | <String, dynamic>{ |
| | | 'theField': instance.theField, |
| | | 'NAME_OVERRIDE': instance.nameOverride |
| | | }; |
| | | ''') |
| | | @JsonSerializable(fieldRename: FieldRename.none, createFactory: false) |
| | | class FieldNamerNone { |
| | | String theField; |
| | | |
| | | @JsonKey(name: 'NAME_OVERRIDE') |
| | | String nameOverride; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> _$FieldNamerKebabToJson(FieldNamerKebab instance) => |
| | | <String, dynamic>{ |
| | | 'the-field': instance.theField, |
| | | 'NAME_OVERRIDE': instance.nameOverride |
| | | }; |
| | | ''') |
| | | @JsonSerializable(fieldRename: FieldRename.kebab, createFactory: false) |
| | | class FieldNamerKebab { |
| | | String theField; |
| | | |
| | | @JsonKey(name: 'NAME_OVERRIDE') |
| | | String nameOverride; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> _$FieldNamerSnakeToJson(FieldNamerSnake instance) => |
| | | <String, dynamic>{ |
| | | 'the_field': instance.theField, |
| | | 'NAME_OVERRIDE': instance.nameOverride |
| | | }; |
| | | ''') |
| | | @JsonSerializable(fieldRename: FieldRename.snake, createFactory: false) |
| | | class FieldNamerSnake { |
| | | String theField; |
| | | |
| | | @JsonKey(name: 'NAME_OVERRIDE') |
| | | String nameOverride; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | @ShouldGenerate(r''' |
| | | GenericClass<T, S> _$GenericClassFromJson<T extends num, S>( |
| | | Map<String, dynamic> json) { |
| | | return GenericClass<T, S>() |
| | | ..fieldObject = |
| | | json['fieldObject'] == null ? null : _dataFromJson(json['fieldObject']) |
| | | ..fieldDynamic = json['fieldDynamic'] == null |
| | | ? null |
| | | : _dataFromJson(json['fieldDynamic']) |
| | | ..fieldInt = |
| | | json['fieldInt'] == null ? null : _dataFromJson(json['fieldInt']) |
| | | ..fieldT = json['fieldT'] == null ? null : _dataFromJson(json['fieldT']) |
| | | ..fieldS = json['fieldS'] == null ? null : _dataFromJson(json['fieldS']); |
| | | } |
| | | |
| | | Map<String, dynamic> _$GenericClassToJson<T extends num, S>( |
| | | GenericClass<T, S> instance) => |
| | | <String, dynamic>{ |
| | | 'fieldObject': instance.fieldObject == null |
| | | ? null |
| | | : _dataToJson(instance.fieldObject), |
| | | 'fieldDynamic': instance.fieldDynamic == null |
| | | ? null |
| | | : _dataToJson(instance.fieldDynamic), |
| | | 'fieldInt': |
| | | instance.fieldInt == null ? null : _dataToJson(instance.fieldInt), |
| | | 'fieldT': instance.fieldT == null ? null : _dataToJson(instance.fieldT), |
| | | 'fieldS': instance.fieldS == null ? null : _dataToJson(instance.fieldS) |
| | | }; |
| | | ''', expectedWrappedOutput: r''' |
| | | GenericClass<T, S> _$GenericClassFromJson<T extends num, S>( |
| | | Map<String, dynamic> json) { |
| | | return GenericClass<T, S>() |
| | | ..fieldObject = |
| | | json['fieldObject'] == null ? null : _dataFromJson(json['fieldObject']) |
| | | ..fieldDynamic = json['fieldDynamic'] == null |
| | | ? null |
| | | : _dataFromJson(json['fieldDynamic']) |
| | | ..fieldInt = |
| | | json['fieldInt'] == null ? null : _dataFromJson(json['fieldInt']) |
| | | ..fieldT = json['fieldT'] == null ? null : _dataFromJson(json['fieldT']) |
| | | ..fieldS = json['fieldS'] == null ? null : _dataFromJson(json['fieldS']); |
| | | } |
| | | |
| | | Map<String, dynamic> _$GenericClassToJson<T extends num, S>( |
| | | GenericClass<T, S> instance) => |
| | | _$GenericClassJsonMapWrapper<T, S>(instance); |
| | | |
| | | class _$GenericClassJsonMapWrapper<T extends num, S> extends $JsonMapWrapper { |
| | | final GenericClass<T, S> _v; |
| | | _$GenericClassJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys => |
| | | const ['fieldObject', 'fieldDynamic', 'fieldInt', 'fieldT', 'fieldS']; |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'fieldObject': |
| | | return _v.fieldObject == null ? null : _dataToJson(_v.fieldObject); |
| | | case 'fieldDynamic': |
| | | return _v.fieldDynamic == null ? null : _dataToJson(_v.fieldDynamic); |
| | | case 'fieldInt': |
| | | return _v.fieldInt == null ? null : _dataToJson(_v.fieldInt); |
| | | case 'fieldT': |
| | | return _v.fieldT == null ? null : _dataToJson(_v.fieldT); |
| | | case 'fieldS': |
| | | return _v.fieldS == null ? null : _dataToJson(_v.fieldS); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | ''') |
| | | @JsonSerializable() |
| | | class GenericClass<T extends num, S> { |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | Object fieldObject; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | dynamic fieldDynamic; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | int fieldInt; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | T fieldT; |
| | | |
| | | @JsonKey(fromJson: _dataFromJson, toJson: _dataToJson) |
| | | S fieldS; |
| | | |
| | | GenericClass(); |
| | | } |
| | | |
| | | T _dataFromJson<T extends num>(Object input) => null; |
| | | Object _dataToJson<T extends num>(T input) => null; |
| New file |
| | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | @ShouldGenerate(r''' |
| | | SubType _$SubTypeFromJson(Map<String, dynamic> json) { |
| | | return SubType( |
| | | json['subTypeViaCtor'] as int, json['super-final-field'] as int) |
| | | ..superReadWriteField = json['superReadWriteField'] as int |
| | | ..subTypeReadWrite = json['subTypeReadWrite'] as int; |
| | | } |
| | | |
| | | Map<String, dynamic> _$SubTypeToJson(SubType instance) { |
| | | final val = <String, dynamic>{ |
| | | 'super-final-field': instance.superFinalField, |
| | | }; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('superReadWriteField', instance.superReadWriteField); |
| | | val['subTypeViaCtor'] = instance.subTypeViaCtor; |
| | | val['subTypeReadWrite'] = instance.subTypeReadWrite; |
| | | return val; |
| | | } |
| | | ''', expectedWrappedOutput: r''' |
| | | SubType _$SubTypeFromJson(Map<String, dynamic> json) { |
| | | return SubType( |
| | | json['subTypeViaCtor'] as int, json['super-final-field'] as int) |
| | | ..superReadWriteField = json['superReadWriteField'] as int |
| | | ..subTypeReadWrite = json['subTypeReadWrite'] as int; |
| | | } |
| | | |
| | | Map<String, dynamic> _$SubTypeToJson(SubType instance) => |
| | | _$SubTypeJsonMapWrapper(instance); |
| | | |
| | | class _$SubTypeJsonMapWrapper extends $JsonMapWrapper { |
| | | final SubType _v; |
| | | _$SubTypeJsonMapWrapper(this._v); |
| | | |
| | | @override |
| | | Iterable<String> get keys sync* { |
| | | yield 'super-final-field'; |
| | | if (_v.superReadWriteField != null) { |
| | | yield 'superReadWriteField'; |
| | | } |
| | | yield 'subTypeViaCtor'; |
| | | yield 'subTypeReadWrite'; |
| | | } |
| | | |
| | | @override |
| | | dynamic operator [](Object key) { |
| | | if (key is String) { |
| | | switch (key) { |
| | | case 'super-final-field': |
| | | return _v.superFinalField; |
| | | case 'superReadWriteField': |
| | | return _v.superReadWriteField; |
| | | case 'subTypeViaCtor': |
| | | return _v.subTypeViaCtor; |
| | | case 'subTypeReadWrite': |
| | | return _v.subTypeReadWrite; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | ''') |
| | | @JsonSerializable() |
| | | class SubType extends SuperType { |
| | | final int subTypeViaCtor; |
| | | int subTypeReadWrite; |
| | | |
| | | SubType(this.subTypeViaCtor, int superFinalField) : super(superFinalField); |
| | | } |
| | | |
| | | // NOTE: `SuperType` is intentionally after `SubType` in the source file to |
| | | // validate field ordering semantics. |
| | | class SuperType { |
| | | @JsonKey(name: 'super-final-field', nullable: false) |
| | | final int superFinalField; |
| | | |
| | | @JsonKey(includeIfNull: false) |
| | | int superReadWriteField; |
| | | |
| | | SuperType(this.superFinalField); |
| | | |
| | | /// Add a property to try to throw-off the generator |
| | | /// Since `priceHalf` is final and not in the constructor, it will be excluded |
| | | int get priceHalf => priceFraction(2); |
| | | |
| | | /// Add a method to try to throw-off the generator |
| | | int priceFraction(int other) => |
| | | superFinalField == null ? null : superFinalField ~/ other; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> _$SubTypeWithAnnotatedFieldOverrideExtendsToJson( |
| | | SubTypeWithAnnotatedFieldOverrideExtends instance) { |
| | | final val = <String, dynamic>{ |
| | | 'super-final-field': instance.superFinalField, |
| | | }; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('superReadWriteField', instance.superReadWriteField); |
| | | val['priceHalf'] = instance.priceHalf; |
| | | return val; |
| | | } |
| | | ''') |
| | | @JsonSerializable(createFactory: false) |
| | | class SubTypeWithAnnotatedFieldOverrideExtends extends SuperType { |
| | | SubTypeWithAnnotatedFieldOverrideExtends(int superTypeViaCtor) |
| | | : super(superTypeViaCtor); |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> |
| | | _$SubTypeWithAnnotatedFieldOverrideExtendsWithOverridesToJson( |
| | | SubTypeWithAnnotatedFieldOverrideExtendsWithOverrides instance) => |
| | | <String, dynamic>{ |
| | | 'priceHalf': instance.priceHalf, |
| | | 'superReadWriteField': instance.superReadWriteField, |
| | | 'super-final-field': instance.superFinalField |
| | | }; |
| | | ''') |
| | | @JsonSerializable(createFactory: false) |
| | | class SubTypeWithAnnotatedFieldOverrideExtendsWithOverrides extends SuperType { |
| | | SubTypeWithAnnotatedFieldOverrideExtendsWithOverrides(int superTypeViaCtor) |
| | | : super(superTypeViaCtor); |
| | | |
| | | /// The annotation applied here overrides the annotation in [SuperType]. |
| | | @JsonKey(includeIfNull: true) |
| | | @override |
| | | int get superReadWriteField => super.superReadWriteField; |
| | | |
| | | @override |
| | | set superReadWriteField(int value) { |
| | | super.superReadWriteField = value; |
| | | } |
| | | |
| | | /// The order is picked up by this override, but the annotation is still |
| | | /// applied from [SuperType]. |
| | | @override |
| | | int get superFinalField => super.superFinalField; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> _$SubTypeWithAnnotatedFieldOverrideImplementsToJson( |
| | | SubTypeWithAnnotatedFieldOverrideImplements instance) => |
| | | <String, dynamic>{ |
| | | 'superReadWriteField': instance.superReadWriteField, |
| | | 'superFinalField': instance.superFinalField |
| | | }; |
| | | ''') |
| | | @JsonSerializable(createFactory: false) |
| | | class SubTypeWithAnnotatedFieldOverrideImplements implements SuperType { |
| | | // Note the order of fields in the output is determined by this class |
| | | @override |
| | | int superReadWriteField; |
| | | |
| | | @JsonKey(ignore: true) |
| | | @override |
| | | int get priceHalf => 42; |
| | | |
| | | /// Since the relationship is `implements` no [JsonKey] values from |
| | | /// [SuperType] are honored. |
| | | @override |
| | | int get superFinalField => 42; |
| | | |
| | | @override |
| | | int priceFraction(int other) => other; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | @ShouldGenerate(r''' |
| | | JsonConverterNamedCtor<E> _$JsonConverterNamedCtorFromJson<E>( |
| | | Map<String, dynamic> json) { |
| | | return JsonConverterNamedCtor<E>() |
| | | ..value = json['value'] == null |
| | | ? null |
| | | : const _DurationMillisecondConverter.named() |
| | | .fromJson(json['value'] as int) |
| | | ..genericValue = json['genericValue'] == null |
| | | ? null |
| | | : _GenericConverter<E>.named().fromJson(json['genericValue'] as int) |
| | | ..keyAnnotationFirst = json['keyAnnotationFirst'] == null |
| | | ? null |
| | | : JsonConverterNamedCtor._fromJson(json['keyAnnotationFirst'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$JsonConverterNamedCtorToJson<E>( |
| | | JsonConverterNamedCtor<E> instance) => |
| | | <String, dynamic>{ |
| | | 'value': instance.value == null |
| | | ? null |
| | | : const _DurationMillisecondConverter.named().toJson(instance.value), |
| | | 'genericValue': instance.genericValue == null |
| | | ? null |
| | | : _GenericConverter<E>.named().toJson(instance.genericValue), |
| | | 'keyAnnotationFirst': instance.keyAnnotationFirst == null |
| | | ? null |
| | | : JsonConverterNamedCtor._toJson(instance.keyAnnotationFirst) |
| | | }; |
| | | ''') |
| | | @JsonSerializable() |
| | | @_DurationMillisecondConverter.named() |
| | | @_GenericConverter.named() |
| | | class JsonConverterNamedCtor<E> { |
| | | Duration value; |
| | | E genericValue; |
| | | |
| | | // Field annotations have precedence over class annotations |
| | | @JsonKey(fromJson: _fromJson, toJson: _toJson) |
| | | Duration keyAnnotationFirst; |
| | | |
| | | static Duration _fromJson(int value) => null; |
| | | static int _toJson(Duration object) => 42; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | JsonConvertOnField<E> _$JsonConvertOnFieldFromJson<E>( |
| | | Map<String, dynamic> json) { |
| | | return JsonConvertOnField<E>() |
| | | ..annotatedField = json['annotatedField'] == null |
| | | ? null |
| | | : const _DurationMillisecondConverter() |
| | | .fromJson(json['annotatedField'] as int) |
| | | ..annotatedWithNamedCtor = json['annotatedWithNamedCtor'] == null |
| | | ? null |
| | | : const _DurationMillisecondConverter.named() |
| | | .fromJson(json['annotatedWithNamedCtor'] as int) |
| | | ..classAnnotatedWithField = json['classAnnotatedWithField'] == null |
| | | ? null |
| | | : _durationConverter.fromJson(json['classAnnotatedWithField'] as int) |
| | | ..genericValue = json['genericValue'] == null |
| | | ? null |
| | | : _GenericConverter<E>().fromJson(json['genericValue'] as int); |
| | | } |
| | | |
| | | Map<String, dynamic> _$JsonConvertOnFieldToJson<E>( |
| | | JsonConvertOnField<E> instance) => |
| | | <String, dynamic>{ |
| | | 'annotatedField': instance.annotatedField == null |
| | | ? null |
| | | : const _DurationMillisecondConverter() |
| | | .toJson(instance.annotatedField), |
| | | 'annotatedWithNamedCtor': instance.annotatedWithNamedCtor == null |
| | | ? null |
| | | : const _DurationMillisecondConverter.named() |
| | | .toJson(instance.annotatedWithNamedCtor), |
| | | 'classAnnotatedWithField': instance.classAnnotatedWithField == null |
| | | ? null |
| | | : _durationConverter.toJson(instance.classAnnotatedWithField), |
| | | 'genericValue': instance.genericValue == null |
| | | ? null |
| | | : _GenericConverter<E>().toJson(instance.genericValue) |
| | | }; |
| | | ''') |
| | | @JsonSerializable() |
| | | @_durationConverter |
| | | class JsonConvertOnField<E> { |
| | | @_DurationMillisecondConverter() |
| | | Duration annotatedField; |
| | | |
| | | @_DurationMillisecondConverter.named() |
| | | Duration annotatedWithNamedCtor; |
| | | |
| | | Duration classAnnotatedWithField; |
| | | |
| | | @_GenericConverter() |
| | | E genericValue; |
| | | } |
| | | |
| | | class _GenericConverter<T> implements JsonConverter<T, int> { |
| | | const _GenericConverter(); |
| | | const _GenericConverter.named(); |
| | | |
| | | @override |
| | | T fromJson(int json) => null; |
| | | |
| | | @override |
| | | int toJson(T object) => 0; |
| | | } |
| | | |
| | | @ShouldThrow('`JsonConverter` implementations can have no more than one type ' |
| | | 'argument. `_BadConverter` has 2.') |
| | | @JsonSerializable() |
| | | @_BadConverter() |
| | | class JsonConverterWithBadTypeArg<T> { |
| | | T value; |
| | | } |
| | | |
| | | class _BadConverter<T, S> implements JsonConverter<S, int> { |
| | | const _BadConverter(); |
| | | |
| | | @override |
| | | S fromJson(int json) => null; |
| | | |
| | | @override |
| | | int toJson(S object) => 0; |
| | | } |
| | | |
| | | @ShouldThrow('Found more than one matching converter for `Duration`.') |
| | | @JsonSerializable() |
| | | @_durationConverter |
| | | @_DurationMillisecondConverter() |
| | | class JsonConverterDuplicateAnnotations { |
| | | Duration value; |
| | | } |
| | | |
| | | const _durationConverter = _DurationMillisecondConverter(); |
| | | |
| | | class _DurationMillisecondConverter implements JsonConverter<Duration, int> { |
| | | const _DurationMillisecondConverter(); |
| | | |
| | | const _DurationMillisecondConverter.named(); |
| | | |
| | | @override |
| | | Duration fromJson(int json) => |
| | | json == null ? null : Duration(milliseconds: json); |
| | | |
| | | @override |
| | | int toJson(Duration object) => object?.inMilliseconds; |
| | | } |
| | | |
| | | @ShouldThrow('Generators with constructor arguments are not supported.') |
| | | @JsonSerializable() |
| | | @_ConverterWithCtorParams(42) |
| | | class JsonConverterCtorParams { |
| | | Duration value; |
| | | } |
| | | |
| | | class _ConverterWithCtorParams implements JsonConverter<Duration, int> { |
| | | final int param; |
| | | const _ConverterWithCtorParams(this.param); |
| | | |
| | | @override |
| | | Duration fromJson(int json) => null; |
| | | |
| | | @override |
| | | int toJson(Duration object) => 0; |
| | | } |
| New file |
| | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | @ShouldGenerate(r''' |
| | | JustSetter _$JustSetterFromJson(Map<String, dynamic> json) { |
| | | return JustSetter(); |
| | | } |
| | | |
| | | Map<String, dynamic> _$JustSetterToJson(JustSetter instance) => |
| | | <String, dynamic>{}; |
| | | ''', expectedLogItems: ['Setters are ignored: JustSetter.someSetter']) |
| | | @JsonSerializable() |
| | | class JustSetter { |
| | | set someSetter(Object name) {} |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | JustSetterNoToJson _$JustSetterNoToJsonFromJson(Map<String, dynamic> json) { |
| | | return JustSetterNoToJson(); |
| | | } |
| | | ''', expectedLogItems: ['Setters are ignored: JustSetterNoToJson.someSetter']) |
| | | @JsonSerializable(createToJson: false) |
| | | class JustSetterNoToJson { |
| | | set someSetter(Object name) {} |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | Map<String, dynamic> _$JustSetterNoFromJsonToJson( |
| | | JustSetterNoFromJson instance) => |
| | | <String, dynamic>{}; |
| | | ''', expectedLogItems: ['Setters are ignored: JustSetterNoFromJson.someSetter']) |
| | | @JsonSerializable(createFactory: false) |
| | | class JustSetterNoFromJson { |
| | | set someSetter(Object name) {} |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | part of '_json_serializable_test_input.dart'; |
| | | |
| | | int _toInt(bool input) => 42; |
| | | int _twoArgFunction(int a, int b) => 42; |
| | | |
| | | dynamic _toDynamic(dynamic input) => null; |
| | | Object _toObject(Object input) => null; |
| | | |
| | | @ShouldThrow( |
| | | 'Error with `@JsonKey` on `field`. The `fromJson` function `_toInt` ' |
| | | 'return type `int` is not compatible with field type `String`.') |
| | | @JsonSerializable() |
| | | class BadFromFuncReturnType { |
| | | @JsonKey(fromJson: _toInt) |
| | | String field; |
| | | } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. The `fromJson` function ' |
| | | '`_twoArgFunction` must have one positional paramater.') |
| | | @JsonSerializable() |
| | | class InvalidFromFunc2Args { |
| | | @JsonKey(fromJson: _twoArgFunction) |
| | | String field; |
| | | } |
| | | |
| | | @ShouldGenerate(r''' |
| | | ValidToFromFuncClassStatic _$ValidToFromFuncClassStaticFromJson( |
| | | Map<String, dynamic> json) { |
| | | return ValidToFromFuncClassStatic() |
| | | ..field = json['field'] == null |
| | | ? null |
| | | : ValidToFromFuncClassStatic._staticFunc(json['field'] as String); |
| | | } |
| | | |
| | | Map<String, dynamic> _$ValidToFromFuncClassStaticToJson( |
| | | ValidToFromFuncClassStatic instance) => |
| | | <String, dynamic>{ |
| | | 'field': instance.field == null |
| | | ? null |
| | | : ValidToFromFuncClassStatic._staticFunc(instance.field) |
| | | }; |
| | | ''') |
| | | @JsonSerializable() |
| | | class ValidToFromFuncClassStatic { |
| | | static String _staticFunc(String param) => null; |
| | | |
| | | @JsonKey(fromJson: _staticFunc, toJson: _staticFunc) |
| | | String field; |
| | | } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. The `toJson` function `_toInt` ' |
| | | 'argument type `bool` is not compatible with field type `String`.') |
| | | @JsonSerializable() |
| | | class BadToFuncReturnType { |
| | | @JsonKey(toJson: _toInt) |
| | | String field; |
| | | } |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. The `toJson` function ' |
| | | '`_twoArgFunction` must have one positional paramater.') |
| | | @JsonSerializable() |
| | | class InvalidToFunc2Args { |
| | | @JsonKey(toJson: _twoArgFunction) |
| | | String field; |
| | | } |
| | | |
| | | @ShouldGenerate("_toObject(json['field'])", contains: true) |
| | | @JsonSerializable() |
| | | class ObjectConvertMethods { |
| | | @JsonKey(fromJson: _toObject, toJson: _toObject) |
| | | String field; |
| | | } |
| | | |
| | | @ShouldGenerate("_toDynamic(json['field'])", contains: true) |
| | | @JsonSerializable() |
| | | class DynamicConvertMethods { |
| | | @JsonKey(fromJson: _toDynamic, toJson: _toDynamic) |
| | | String field; |
| | | } |
| | | |
| | | String _toString(String input) => null; |
| | | |
| | | @ShouldGenerate("_toString(json['field'] as String)", contains: true) |
| | | @JsonSerializable() |
| | | class TypedConvertMethods { |
| | | @JsonKey(fromJson: _toString, toJson: _toString) |
| | | String field; |
| | | } |
| | | |
| | | String _fromDynamicMap(Map input) => null; |
| | | String _fromDynamicList(List input) => null; |
| | | String _fromDynamicIterable(Iterable input) => null; |
| | | |
| | | @ShouldGenerate(r''' |
| | | FromDynamicCollection _$FromDynamicCollectionFromJson( |
| | | Map<String, dynamic> json) { |
| | | return FromDynamicCollection() |
| | | ..mapField = json['mapField'] == null |
| | | ? null |
| | | : _fromDynamicMap(json['mapField'] as Map) |
| | | ..listField = json['listField'] == null |
| | | ? null |
| | | : _fromDynamicList(json['listField'] as List) |
| | | ..iterableField = json['iterableField'] == null |
| | | ? null |
| | | : _fromDynamicIterable(json['iterableField'] as List); |
| | | } |
| | | ''') |
| | | @JsonSerializable(createToJson: false) |
| | | class FromDynamicCollection { |
| | | @JsonKey(fromJson: _fromDynamicMap) |
| | | String mapField; |
| | | @JsonKey(fromJson: _fromDynamicList) |
| | | String listField; |
| | | @JsonKey(fromJson: _fromDynamicIterable) |
| | | String iterableField; |
| | | } |
| | | |
| | | String _noArgs() => null; |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. The `fromJson` function ' |
| | | '`_noArgs` must have one positional paramater.') |
| | | @JsonSerializable(createToJson: false) |
| | | class BadNoArgs { |
| | | @JsonKey(fromJson: _noArgs) |
| | | String field; |
| | | } |
| | | |
| | | String _twoArgs(a, b) => null; |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. The `fromJson` function ' |
| | | '`_twoArgs` must have one positional paramater.') |
| | | @JsonSerializable(createToJson: false) |
| | | class BadTwoRequiredPositional { |
| | | @JsonKey(fromJson: _twoArgs) |
| | | String field; |
| | | } |
| | | |
| | | String _oneNamed({a}) => null; |
| | | |
| | | @ShouldThrow('Error with `@JsonKey` on `field`. The `fromJson` function ' |
| | | '`_oneNamed` must have one positional paramater.') |
| | | @JsonSerializable(createToJson: false) |
| | | class BadOneNamed { |
| | | @JsonKey(fromJson: _oneNamed) |
| | | String field; |
| | | } |
| | | |
| | | String _oneNormalOnePositional(a, [b]) => null; |
| | | |
| | | @ShouldGenerate("_oneNormalOnePositional(json['field'])", contains: true) |
| | | @JsonSerializable(createToJson: false) |
| | | class OkayOneNormalOptionalPositional { |
| | | @JsonKey(fromJson: _oneNormalOnePositional) |
| | | String field; |
| | | } |
| | | |
| | | String _oneNormalOptionalNamed(a, {b}) => null; |
| | | |
| | | @ShouldGenerate("_oneNormalOptionalNamed(json['field'])", contains: true) |
| | | @JsonSerializable(createToJson: false) |
| | | class OkayOneNormalOptionalNamed { |
| | | @JsonKey(fromJson: _oneNormalOptionalNamed) |
| | | String field; |
| | | } |
| | | |
| | | String _onlyOptionalPositional([a, b]) => null; |
| | | |
| | | @ShouldGenerate("_onlyOptionalPositional(json['field'])", contains: true) |
| | | @JsonSerializable(createToJson: false) |
| | | class OkayOnlyOptionalPositional { |
| | | @JsonKey(fromJson: _onlyOptionalPositional) |
| | | String field; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'dart:mirrors'; |
| | | |
| | | import 'package:path/path.dart' as p; |
| | | |
| | | String testFilePath(String part1, [String part2, String part3]) => |
| | | p.join(_packagePath(), part1, part2, part3); |
| | | |
| | | String _packagePathCache; |
| | | |
| | | String _packagePath() { |
| | | if (_packagePathCache == null) { |
| | | // Getting the location of this file – via reflection |
| | | final currentFilePath = (reflect(_packagePath) as ClosureMirror) |
| | | .function |
| | | .location |
| | | .sourceUri |
| | | .path; |
| | | |
| | | _packagePathCache = p.normalize(p.join(p.dirname(currentFilePath), '..')); |
| | | } |
| | | return _packagePathCache; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'dart:convert'; |
| | | |
| | | import 'package:test/test.dart'; |
| | | |
| | | final isCastError = const TypeMatcher<CastError>(); |
| | | final throwsCastError = throwsA(isCastError); |
| | | |
| | | T roundTripObject<T>(T object, T factory(Map<String, dynamic> json)) { |
| | | final data = loudEncode(object); |
| | | |
| | | final object2 = factory(json.decode(data) as Map<String, dynamic>); |
| | | |
| | | expect(object2, equals(object)); |
| | | |
| | | final json2 = loudEncode(object2); |
| | | |
| | | expect(json2, equals(data)); |
| | | return object2; |
| | | } |
| | | |
| | | /// Prints out nested causes before throwing `JsonUnsupportedObjectError`. |
| | | String loudEncode(Object object) { |
| | | try { |
| | | return const JsonEncoder.withIndent(' ').convert(object); |
| | | } on JsonUnsupportedObjectError catch (e) { |
| | | var error = e; |
| | | do { |
| | | final cause = error.cause; |
| | | print(cause); |
| | | error = (cause is JsonUnsupportedObjectError) ? cause : null; |
| | | } while (error != null); |
| | | rethrow; |
| | | } |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | @TestOn('vm') |
| | | |
| | | import 'package:test/test.dart'; |
| | | |
| | | import 'package:json_serializable/src/utils.dart'; |
| | | |
| | | const _items = { |
| | | 'simple': 'simple', |
| | | 'twoWords': 'two-words', |
| | | 'FirstBig': 'first-big' |
| | | }; |
| | | |
| | | void main() { |
| | | group('kebab', () { |
| | | for (final entry in _items.entries) { |
| | | test('"${entry.key}"', () { |
| | | expect(kebabCase(entry.key), entry.value); |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | group('snake', () { |
| | | for (final entry in _items.entries) { |
| | | test('"${entry.key}"', () { |
| | | expect(snakeCase(entry.key), entry.value.replaceAll('-', '_')); |
| | | }); |
| | | } |
| | | }); |
| | | } |
| New file |
| | |
| | | weights: |
| | | all_packages: 42 |
| | | none: |
| | | root_package: null |
| | | builders: |
| | | scss_builder: |
| | | target: "scss_builder" |
| | | import: "package:angular_components/builder.dart" |
| | | builder_factories: ["scssBuilder"] |
| | | build_to: cache |
| | | build_extensions: |
| | | .scss: [".scss.css"] |
| | | .sass: [".scss.css"] |
| New file |
| | |
| | | builders: |
| | | angular: |
| | | import: "package:angular/builder.dart" |
| | | builder_factories: |
| | | - templatePlaceholder |
| | | - templateCompiler |
| | | - stylesheetCompiler |
| | | auto_apply: none |
| | | applies_builders: |
| | | - "angular|placeholder_cleanup" |
| | | - "angular|component_source_cleanup" |
| | | # See https://github.com/dart-lang/angular/issues/988. |
| | | is_optional: true |
| | | required_inputs: |
| | | - ".css" |
| | | build_extensions: |
| | | .css: |
| | | - ".css.dart" |
| | | - ".css.shim.dart" |
| | | .dart: |
| | | - ".template.dart" |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:meta/meta.dart'; |
| | | |
| | | part 'build_config.g.dart'; |
| | | |
| | | @JsonSerializable(checked: true, anyMap: true) |
| | | class Config { |
| | | @JsonKey(required: true) |
| | | final Map<String, Builder> builders; |
| | | |
| | | // Verifying enum keys in map |
| | | Map<AutoApply, int> weights; |
| | | |
| | | Config({@required this.builders}); |
| | | |
| | | factory Config.fromJson(Map map) => _$ConfigFromJson(map); |
| | | |
| | | Map<String, dynamic> toJson() => _$ConfigToJson(this); |
| | | } |
| | | |
| | | @JsonSerializable( |
| | | includeIfNull: false, |
| | | disallowUnrecognizedKeys: true, |
| | | checked: true, |
| | | anyMap: true) |
| | | class Builder { |
| | | @JsonKey(nullable: true) |
| | | final String target; |
| | | |
| | | final String import; |
| | | |
| | | @JsonKey(name: 'is_optional') |
| | | final bool isOptional; |
| | | |
| | | @JsonKey(disallowNullValue: true) |
| | | final Uri configLocation; |
| | | |
| | | @JsonKey(name: 'auto_apply', disallowNullValue: true) |
| | | final AutoApply autoApply; |
| | | |
| | | @JsonKey(name: 'build_to') |
| | | final BuildTo buildTo; |
| | | |
| | | final AutoApply defaultEnumTest; |
| | | |
| | | @JsonKey(name: 'builder_factories', nullable: false) |
| | | final List<String> builderFactories; |
| | | |
| | | @JsonKey(name: 'applies_builders') |
| | | final List<String> appliesBuilders; |
| | | |
| | | @JsonKey(name: 'required_inputs') |
| | | final List<String> requiredInputs; |
| | | |
| | | @JsonKey(name: 'build_extensions') |
| | | final Map<String, List<String>> buildExtentions; |
| | | |
| | | Builder( |
| | | {@required this.import, |
| | | this.target, |
| | | this.isOptional, |
| | | this.autoApply, |
| | | this.buildTo, |
| | | this.defaultEnumTest, |
| | | this.builderFactories, |
| | | this.appliesBuilders, |
| | | this.requiredInputs, |
| | | this.buildExtentions, |
| | | this.configLocation}) { |
| | | if (builderFactories.isEmpty) { |
| | | throw ArgumentError.value(builderFactories, 'builderFactories', |
| | | 'Must have at least one value.'); |
| | | } |
| | | } |
| | | |
| | | factory Builder.fromJson(Map map) => _$BuilderFromJson(map); |
| | | |
| | | Map<String, dynamic> toJson() => _$BuilderToJson(this); |
| | | } |
| | | |
| | | enum AutoApply { |
| | | none, |
| | | dependents, |
| | | @JsonValue('all_packages') |
| | | allPackages, |
| | | @JsonValue('root_package') |
| | | rootPackage |
| | | } |
| | | |
| | | enum BuildTo { cache, source } |
| New file |
| | |
| | | // GENERATED CODE - DO NOT MODIFY BY HAND |
| | | |
| | | part of 'build_config.dart'; |
| | | |
| | | // ************************************************************************** |
| | | // JsonSerializableGenerator |
| | | // ************************************************************************** |
| | | |
| | | Config _$ConfigFromJson(Map json) { |
| | | return $checkedNew('Config', json, () { |
| | | $checkKeys(json, requiredKeys: const ['builders']); |
| | | final val = Config( |
| | | builders: $checkedConvert( |
| | | json, |
| | | 'builders', |
| | | (v) => (v as Map)?.map((k, e) => MapEntry( |
| | | k as String, e == null ? null : Builder.fromJson(e as Map))))); |
| | | $checkedConvert( |
| | | json, |
| | | 'weights', |
| | | (v) => val.weights = (v as Map)?.map((k, e) => |
| | | MapEntry(_$enumDecodeNullable(_$AutoApplyEnumMap, k), e as int))); |
| | | return val; |
| | | }); |
| | | } |
| | | |
| | | Map<String, dynamic> _$ConfigToJson(Config instance) => <String, dynamic>{ |
| | | 'builders': instance.builders, |
| | | 'weights': |
| | | instance.weights?.map((k, e) => MapEntry(_$AutoApplyEnumMap[k], e)) |
| | | }; |
| | | |
| | | T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | throw ArgumentError('A value must be provided. Supported values: ' |
| | | '${enumValues.values.join(', ')}'); |
| | | } |
| | | return enumValues.entries |
| | | .singleWhere((e) => e.value == source, |
| | | orElse: () => throw ArgumentError( |
| | | '`$source` is not one of the supported values: ' |
| | | '${enumValues.values.join(', ')}')) |
| | | .key; |
| | | } |
| | | |
| | | T _$enumDecodeNullable<T>(Map<T, dynamic> enumValues, dynamic source) { |
| | | if (source == null) { |
| | | return null; |
| | | } |
| | | return _$enumDecode<T>(enumValues, source); |
| | | } |
| | | |
| | | const _$AutoApplyEnumMap = <AutoApply, dynamic>{ |
| | | AutoApply.none: 'none', |
| | | AutoApply.dependents: 'dependents', |
| | | AutoApply.allPackages: 'all_packages', |
| | | AutoApply.rootPackage: 'root_package' |
| | | }; |
| | | |
| | | Builder _$BuilderFromJson(Map json) { |
| | | return $checkedNew('Builder', json, () { |
| | | $checkKeys(json, allowedKeys: const [ |
| | | 'target', |
| | | 'import', |
| | | 'is_optional', |
| | | 'configLocation', |
| | | 'auto_apply', |
| | | 'build_to', |
| | | 'defaultEnumTest', |
| | | 'builder_factories', |
| | | 'applies_builders', |
| | | 'required_inputs', |
| | | 'build_extensions' |
| | | ], disallowNullValues: const [ |
| | | 'configLocation', |
| | | 'auto_apply' |
| | | ]); |
| | | final val = Builder( |
| | | import: $checkedConvert(json, 'import', (v) => v as String), |
| | | target: $checkedConvert(json, 'target', (v) => v as String), |
| | | isOptional: $checkedConvert(json, 'is_optional', (v) => v as bool), |
| | | autoApply: $checkedConvert(json, 'auto_apply', |
| | | (v) => _$enumDecodeNullable(_$AutoApplyEnumMap, v)), |
| | | buildTo: $checkedConvert( |
| | | json, 'build_to', (v) => _$enumDecodeNullable(_$BuildToEnumMap, v)), |
| | | defaultEnumTest: $checkedConvert(json, 'defaultEnumTest', |
| | | (v) => _$enumDecodeNullable(_$AutoApplyEnumMap, v)), |
| | | builderFactories: $checkedConvert(json, 'builder_factories', |
| | | (v) => (v as List).map((e) => e as String).toList()), |
| | | appliesBuilders: $checkedConvert(json, 'applies_builders', |
| | | (v) => (v as List)?.map((e) => e as String)?.toList()), |
| | | requiredInputs: $checkedConvert(json, 'required_inputs', |
| | | (v) => (v as List)?.map((e) => e as String)?.toList()), |
| | | buildExtentions: $checkedConvert( |
| | | json, |
| | | 'build_extensions', |
| | | (v) => (v as Map)?.map((k, e) => MapEntry( |
| | | k as String, (e as List)?.map((e) => e as String)?.toList()))), |
| | | configLocation: $checkedConvert(json, 'configLocation', |
| | | (v) => v == null ? null : Uri.parse(v as String))); |
| | | return val; |
| | | }, fieldKeyMap: const { |
| | | 'isOptional': 'is_optional', |
| | | 'autoApply': 'auto_apply', |
| | | 'buildTo': 'build_to', |
| | | 'builderFactories': 'builder_factories', |
| | | 'appliesBuilders': 'applies_builders', |
| | | 'requiredInputs': 'required_inputs', |
| | | 'buildExtentions': 'build_extensions' |
| | | }); |
| | | } |
| | | |
| | | Map<String, dynamic> _$BuilderToJson(Builder instance) { |
| | | final val = <String, dynamic>{}; |
| | | |
| | | void writeNotNull(String key, dynamic value) { |
| | | if (value != null) { |
| | | val[key] = value; |
| | | } |
| | | } |
| | | |
| | | writeNotNull('target', instance.target); |
| | | writeNotNull('import', instance.import); |
| | | writeNotNull('is_optional', instance.isOptional); |
| | | writeNotNull('configLocation', instance.configLocation?.toString()); |
| | | writeNotNull('auto_apply', _$AutoApplyEnumMap[instance.autoApply]); |
| | | writeNotNull('build_to', _$BuildToEnumMap[instance.buildTo]); |
| | | writeNotNull('defaultEnumTest', _$AutoApplyEnumMap[instance.defaultEnumTest]); |
| | | val['builder_factories'] = instance.builderFactories; |
| | | writeNotNull('applies_builders', instance.appliesBuilders); |
| | | writeNotNull('required_inputs', instance.requiredInputs); |
| | | writeNotNull('build_extensions', instance.buildExtentions); |
| | | return val; |
| | | } |
| | | |
| | | const _$BuildToEnumMap = <BuildTo, dynamic>{ |
| | | BuildTo.cache: 'cache', |
| | | BuildTo.source: 'source' |
| | | }; |
| New file |
| | |
| | | builders: |
| | | # The regular builder config, creates `.tar.gz` files. |
| | | regular_builder: |
| | | import: "package:my_package/builder.dart" |
| | | builder_factories: ["myBuilder"] |
| | | build_extensions: {".dart": [".tar.gz"]} |
| | | auto_apply: root_package |
| | | applies_builders: ["|archive_extract_builder"] |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | @TestOn('vm') |
| | | |
| | | import 'dart:io'; |
| | | |
| | | import 'package:json_annotation/json_annotation.dart'; |
| | | import 'package:path/path.dart' as p; |
| | | import 'package:test/test.dart'; |
| | | import 'package:yaml/yaml.dart'; |
| | | |
| | | import '../test_utils.dart'; |
| | | import 'build_config.dart'; |
| | | |
| | | final _root = p.join('test', 'yaml'); |
| | | |
| | | List<String> _getTests() => Directory(_root) |
| | | .listSync() |
| | | .where((fse) => fse is File && p.extension(fse.path) == '.yaml') |
| | | .map((fse) => fse.path) |
| | | .toList(); |
| | | |
| | | void main() { |
| | | group('valid configurations', () { |
| | | for (final filePath in _getTests()) { |
| | | test(p.basenameWithoutExtension(filePath), () { |
| | | final content = File(filePath).readAsStringSync(); |
| | | final yamlContent = loadYaml(content, sourceUrl: filePath) as YamlMap; |
| | | |
| | | try { |
| | | final config = Config.fromJson(yamlContent); |
| | | expect(config, isNotNull); |
| | | } on CheckedFromJsonException catch (e) { |
| | | print(_prettyPrintCheckedFromJsonException(e)); |
| | | rethrow; |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | group('bad configs', () { |
| | | var index = 0; |
| | | for (final entry in _badConfigs.entries) { |
| | | test('${index++}', () { |
| | | final yamlContent = |
| | | loadYaml(entry.key, sourceUrl: 'file.yaml') as YamlMap; |
| | | |
| | | expect(yamlContent, isNotNull); |
| | | printOnFailure(entry.key); |
| | | |
| | | try { |
| | | final config = Config.fromJson(yamlContent); |
| | | print(loudEncode(config)); |
| | | fail('parse should fail'); |
| | | } on CheckedFromJsonException catch (e) { |
| | | final prettyOutput = _prettyPrintCheckedFromJsonException(e); |
| | | printOnFailure(prettyOutput); |
| | | expect(prettyOutput, entry.value); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | final _badConfigs = const { |
| | | r''' |
| | | builders: |
| | | - a |
| | | - b |
| | | ''': r''' |
| | | line 2, column 1 of file.yaml: Could not create `Config`. Unsupported value for `builders`. |
| | | - a |
| | | ^^^^''', |
| | | r''' |
| | | builders: |
| | | sample: |
| | | defaultEnumTest: bob |
| | | ''': r''' |
| | | line 3, column 22 of file.yaml: Could not create `Builder`. Unsupported value for `defaultEnumTest`. `bob` is not one of the supported values: none, dependents, all_packages, root_package |
| | | defaultEnumTest: bob |
| | | ^^^''', |
| | | r''' |
| | | builders: |
| | | a: |
| | | target: 42 |
| | | ''': r''' |
| | | line 3, column 13 of file.yaml: Could not create `Builder`. Unsupported value for `target`. |
| | | target: 42 |
| | | ^^''', |
| | | r''' |
| | | builders: |
| | | a: |
| | | target: "a target" |
| | | auto_apply: unsupported |
| | | ''': r''' |
| | | line 4, column 17 of file.yaml: Could not create `Builder`. Unsupported value for `auto_apply`. `unsupported` is not one of the supported values: none, dependents, all_packages, root_package |
| | | auto_apply: unsupported |
| | | ^^^^^^^^^^^''', |
| | | r''' |
| | | builders: |
| | | a: |
| | | builder_factories: [] |
| | | ''': r''' |
| | | line 3, column 24 of file.yaml: Could not create `Builder`. Unsupported value for `builder_factories`. Must have at least one value. |
| | | builder_factories: [] |
| | | ^^''', |
| | | r''' |
| | | builders: |
| | | a: |
| | | foo: bar |
| | | baz: zap |
| | | ''': r''' |
| | | Could not create `Builder`. |
| | | Unrecognized keys: [baz, foo]; supported keys: [target, import, is_optional, configLocation, auto_apply, build_to, defaultEnumTest, builder_factories, applies_builders, required_inputs, build_extensions] |
| | | |
| | | line 4, column 5 of file.yaml: Invalid key "baz" |
| | | baz: zap |
| | | ^^^ |
| | | line 3, column 5 of file.yaml: Invalid key "foo" |
| | | foo: bar |
| | | ^^^''', |
| | | r''' |
| | | bob: cool |
| | | ''': ''' |
| | | Could not create `Config`. |
| | | line 1, column 3 of file.yaml: Required keys are missing: builders. |
| | | bob: cool |
| | | ^^^^^^^^^^''', |
| | | r''' |
| | | builders: |
| | | builder_name: |
| | | auto_apply:''': '''Could not create `Builder`. |
| | | line 3, column 5 of file.yaml: These keys had `null` values, which is not allowed: [auto_apply] |
| | | auto_apply: |
| | | ^^^^^^^^^^^''', |
| | | r''' |
| | | builders: |
| | | builder_name: |
| | | builder_factories: ["scssBuilder"] |
| | | configLocation: "user@host:invalid/uri"''': |
| | | '''line 4, column 21 of file.yaml: Could not create `Builder`. Unsupported value for `configLocation`. Illegal scheme character at offset 4. |
| | | configLocation: "user@host:invalid/uri" |
| | | ^^^^^^^^^^^^^^^^^^^^^^^''' |
| | | }; |
| | | |
| | | String _prettyPrintCheckedFromJsonException(CheckedFromJsonException err) { |
| | | final yamlMap = err.map as YamlMap; |
| | | |
| | | YamlScalar _getYamlKey(String key) { |
| | | return yamlMap.nodes.keys.singleWhere((k) => (k as YamlScalar).value == key, |
| | | orElse: () => null) as YamlScalar; |
| | | } |
| | | |
| | | final innerError = err.innerError; |
| | | |
| | | var message = 'Could not create `${err.className}`.'; |
| | | if (innerError is BadKeyException) { |
| | | expect(err.message, innerError.message); |
| | | |
| | | if (innerError is UnrecognizedKeysException) { |
| | | message += '\n${innerError.message}\n'; |
| | | for (final key in innerError.unrecognizedKeys) { |
| | | final yamlKey = _getYamlKey(key); |
| | | assert(yamlKey != null); |
| | | message += '\n${yamlKey.span.message('Invalid key "$key"')}'; |
| | | } |
| | | } else if (innerError is MissingRequiredKeysException) { |
| | | expect(err.key, innerError.missingKeys.first); |
| | | message += '\n${yamlMap.span.message(innerError.message)}'; |
| | | } else if (innerError is DisallowedNullValueException) { |
| | | expect(err.key, innerError.keysWithNullValues.first); |
| | | message += '\n${yamlMap.span.message(innerError.message)}'; |
| | | } else { |
| | | throw UnsupportedError('${innerError.runtimeType} is not supported.'); |
| | | } |
| | | } else { |
| | | final yamlValue = yamlMap.nodes[err.key]; |
| | | |
| | | if (yamlValue == null) { |
| | | assert(err.key == null); |
| | | message = '${yamlMap.span.message(message)} ${err.innerError}'; |
| | | } else { |
| | | message = '$message Unsupported value for `${err.key}`.'; |
| | | if (err.message != null) { |
| | | message = '$message ${err.message}'; |
| | | } |
| | | message = yamlValue.span.message(message); |
| | | } |
| | | } |
| | | |
| | | return message; |
| | | } |
| New file |
| | |
| | | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | |
| | | import 'dart:async'; |
| | | |
| | | import 'package:build/build.dart'; |
| | | import 'package:path/path.dart' as p; |
| | | import 'package:source_gen/source_gen.dart'; |
| | | |
| | | final _copyrightContent = |
| | | '''// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| | | // for details. All rights reserved. Use of this source code is governed by a |
| | | // BSD-style license that can be found in the LICENSE file. |
| | | '''; |
| | | |
| | | final copyrightHeader = '$_copyrightContent\n$defaultFileHeader'; |
| | | |
| | | Builder nonNull([_]) => LibraryBuilder(_NonNullableGenerator(), |
| | | generatedExtension: '.non_nullable.dart', header: copyrightHeader); |
| | | |
| | | Builder wrapped([_]) => LibraryBuilder(_WrappedGenerator(), |
| | | generatedExtension: '.wrapped.dart', header: copyrightHeader); |
| | | |
| | | Builder checked([_]) => LibraryBuilder(_CheckedGenerator(), |
| | | generatedExtension: '.checked.dart', header: copyrightHeader); |
| | | |
| | | class _NonNullableGenerator extends Generator { |
| | | @override |
| | | FutureOr<String> generate(LibraryReader library, BuildStep buildStep) async { |
| | | final path = buildStep.inputId.path; |
| | | final baseName = p.basenameWithoutExtension(path); |
| | | |
| | | final content = await buildStep.readAsString(buildStep.inputId); |
| | | final replacements = [ |
| | | _Replacement(_copyrightContent, ''), |
| | | _Replacement( |
| | | "part '$baseName.g.dart", |
| | | "part '$baseName.non_nullable.g.dart", |
| | | ), |
| | | _Replacement('@JsonSerializable(', '@JsonSerializable(nullable: false,'), |
| | | ]; |
| | | |
| | | if (baseName == 'kitchen_sink') { |
| | | replacements.addAll([ |
| | | _Replacement('List<T> _defaultList<T>() => null;', |
| | | 'List<T> _defaultList<T>() => <T>[];'), |
| | | _Replacement('Set<T> _defaultSet<T>() => null;', |
| | | 'Set<T> _defaultSet<T>() => Set<T>();'), |
| | | _Replacement('Map _defaultMap() => null;', |
| | | 'Map<String, T> _defaultMap<T>() => <String, T>{};'), |
| | | _Replacement('SimpleObject _defaultSimpleObject() => null;', |
| | | 'SimpleObject _defaultSimpleObject() => SimpleObject(42);'), |
| | | _Replacement( |
| | | 'StrictKeysObject _defaultStrictKeysObject() => null;', |
| | | 'StrictKeysObject _defaultStrictKeysObject() => ' |
| | | "StrictKeysObject(10, 'cool');"), |
| | | _Replacement( |
| | | 'DateTime dateTime;', 'DateTime dateTime = DateTime(1981, 6, 5);') |
| | | ]); |
| | | } |
| | | |
| | | return _Replacement.generate(content, replacements); |
| | | } |
| | | } |
| | | |
| | | class _CheckedGenerator extends Generator { |
| | | @override |
| | | FutureOr<String> generate(LibraryReader library, BuildStep buildStep) async { |
| | | final path = buildStep.inputId.path; |
| | | final baseName = p.basenameWithoutExtension(path); |
| | | |
| | | final content = await buildStep.readAsString(buildStep.inputId); |
| | | final replacements = [ |
| | | _Replacement('@JsonSerializable(', '@JsonSerializable(checked: true,'), |
| | | _Replacement(_copyrightContent, ''), |
| | | _Replacement( |
| | | "part '$baseName.g.dart", |
| | | "part '$baseName.checked.g.dart", |
| | | ), |
| | | ]; |
| | | |
| | | if (baseName == 'default_value') { |
| | | replacements.add( |
| | | _Replacement('@JsonSerializable(', '@JsonSerializable(anyMap: true,'), |
| | | ); |
| | | } |
| | | |
| | | return _Replacement.generate(content, replacements); |
| | | } |
| | | } |
| | | |
| | | class _WrappedGenerator extends Generator { |
| | | @override |
| | | FutureOr<String> generate(LibraryReader library, BuildStep buildStep) async { |
| | | final path = buildStep.inputId.path; |
| | | final baseName = p.basenameWithoutExtension(path); |
| | | |
| | | final content = await buildStep.readAsString(buildStep.inputId); |
| | | final replacements = [ |
| | | _Replacement(_copyrightContent, ''), |
| | | _Replacement( |
| | | "part '$baseName.g.dart", |
| | | "part '$baseName.wrapped.g.dart", |
| | | ), |
| | | _Replacement( |
| | | '@JsonSerializable(', '@JsonSerializable(useWrappers: true,'), |
| | | ]; |
| | | |
| | | return _Replacement.generate(content, replacements); |
| | | } |
| | | } |
| | | |
| | | class _Replacement { |
| | | final Pattern existing; |
| | | final String replacement; |
| | | |
| | | _Replacement(this.existing, this.replacement); |
| | | |
| | | static String generate( |
| | | String inputContent, Iterable<_Replacement> replacements) { |
| | | var outputContent = inputContent; |
| | | |
| | | for (final r in replacements) { |
| | | if (!outputContent.contains(r.existing)) { |
| | | throw StateError( |
| | | 'Input string did not contain `${r.existing}` as expected.'); |
| | | } |
| | | outputContent = outputContent.replaceAll(r.existing, r.replacement); |
| | | } |
| | | |
| | | return outputContent; |
| | | } |
| | | } |