toon_serializable

pub package

The official code generator for Token-Oriented Object Notation (TOON) models in Dart. Automatically generates TOON serialization code using build_runner.

Features

  • 🚀 Automatic Code Generation: Generate toToon() and fromToon() methods with a single annotation
  • 🔄 Field Renaming: Support for multiple field renaming strategies (snake_case, kebab-case, PascalCase, camelCase)
  • 🎯 Custom Keys: Override field names with @ToonKey annotation
  • 📦 Type Safety: Full support for nullable types and generic lists
  • Zero Runtime Overhead: All serialization logic is generated at compile time
  • 🔧 Easy Integration: Works seamlessly with build_runner and existing Dart projects

Installation

Add the following to your pubspec.yaml:

dependencies:
  toon_annotation: ^1.0.0
  toon_dart: ^1.0.0

dev_dependencies:
  toon_serializable: ^1.0.1
  build_runner: ^2.10.3

Then run:

dart pub get

Configuration

The package is automatically configured via build.yaml. No manual configuration is required for most use cases.

Usage

Basic Example

  1. Define your model class with the @ToonSerializable annotation:
import 'package:toon_annotation/toon_annotation.dart';
import 'package:toon_dart/toon_dart.dart';

part 'user_model.toon_serializable.g.part'; // Generated file

@ToonSerializable()
class User {
  final String name;
  final int age;
  
  User({required this.name, required this.age});
  
  // These methods will be generated
  factory User.fromToon(String toon) => _$UserFromToon(toon);
  String toToon() => _$UserToToon(this);
}
  1. Run the code generator:
dart run build_runner build
  1. Use the generated code:
final user = User(name: 'Alice', age: 30);
final toonString = user.toToon(); // Serialize to TOON
final decodedUser = User.fromToon(toonString); // Deserialize from TOON

Field Renaming

Use fieldRename to automatically convert field names:

@ToonSerializable(fieldRename: FieldRename.snake)
class User {
  final String firstName; // Serializes as 'first_name'
  final int userAge;      // Serializes as 'user_age'
  
  User({required this.firstName, required this.userAge});
  
  factory User.fromToon(String toon) => _$UserFromToon(toon);
  String toToon() => _$UserToToon(this);
}

Custom Field Keys

Override specific field names with @ToonKey:

@ToonSerializable(fieldRename: FieldRename.snake)
class User {
  final String firstName; // Serializes as 'first_name'
  
  @ToonKey(name: 'user_age')
  final int age; // Serializes as 'user_age' (not 'age')
  
  User({required this.firstName, required this.age});
  
  factory User.fromToon(String toon) => _$UserFromToon(toon);
  String toToon() => _$UserToToon(this);
}

Advanced Options

@ToonSerializable(
  fieldRename: FieldRename.snake,
  useTabularArrays: false, // Set to true for tabular array format
  strictKeys: true,        // Enable strict key validation
)
class User {
  // ... your fields
}

Running the Generator

One-time Generation

dart run build_runner build

Watch Mode (Auto-regenerate on file changes)

dart run build_runner watch

Clean Build (Delete conflicting outputs)

dart run build_runner build --delete-conflicting-outputs

Important Notes

⚠️ Known Issue: Part Declaration

The generated .part file requires manual addition of the part of declaration.

After running build_runner, you must manually add the following line at the top of each generated .part file:

part of 'your_file_name.dart';

For example, if your file is user_model.dart and the generated file is user_model.toon_serializable.g.part, add:

part of 'user_model.dart';

// ... rest of generated code

Why is this needed? The SharedPartBuilder from source_gen should automatically add this declaration, but due to current limitations, it must be added manually. This is a known issue that will be addressed in a future release.

Workaround: You can create a simple script or use your IDE's find-and-replace to add this line after each code generation.

Field Renaming Strategies

Strategy Example Input Example Output
FieldRename.snake firstName first_name
FieldRename.kebab firstName first-name
FieldRename.pascal firstName FirstName
FieldRename.camel FirstName firstName
None (default) firstName firstName

Supported Types

  • Primitives: String, int, double, bool
  • Nullable types: String?, int?, etc.
  • Lists: List<String>, List<int>, etc.
  • Nested objects: Any class annotated with @ToonSerializable
  • Maps: Map<String, dynamic> (via toon_dart)

Examples

See the /example directory for complete working examples.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Issues

If you encounter any issues or have feature requests, please file them on the issue tracker.

License

This package is licensed under the MIT License. See the LICENSE file for details.

Libraries

builder
toon_serializable
Support for doing something awesome.