dart_json_annotations 2.2.0 copy "dart_json_annotations: ^2.2.0" to clipboard
dart_json_annotations: ^2.2.0 copied to clipboard

High-performance code generation for Dart/Flutter: JSON, copyWith, equatable, and union/sealed class support. Rust-powered CLI with parallel processing.

dart_json_annotations v2.2.0 #

⚠️ EXPERIMENTAL - This package is under active development. APIs may change without notice.

A high-performance Dart code generator powered by Rust. Generates JSON serializers, copyWith, Equatable, and toString methods with optimized output size for large codebases.

Why v2.0? #

  • 70% smaller output - Optimized for 200+ models (< 10k lines)
  • Parallel processing - Uses Rust's rayon for multi-core builds
  • Single @Model annotation - Replaces 4+ separate annotations
  • Sealed class support - when/map methods like Freezed
  • Preset patterns - One-liner for common use cases

Features #

  • πŸ¦€ Rust-powered - Fast parallel code generation
  • πŸ“¦ Zero runtime dependency - Generated pure Dart code
  • πŸ”„ JSON serialization - toJson(), fromJson(), toJsonString()
  • πŸ“‹ copyWith - Immutable state updates
  • βš–οΈ Equatable - Value equality
  • 🎯 Sealed/Union classes - when, map, maybeWhen, maybeMap
  • βœ… Checksum caching - Skip unchanged files

Installation #

dependencies:
  dart_json_annotations: ^2.0.1

Requirements #

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Clone and setup
git clone https://github.com/djsmk123/dart_json_annotations.git
cd dart_json_annotations

# Active local
dart pub global activate -s path .
# Build the Rust binary (first time only)
dart_json_gen --build

# Generate code
dart_json_gen -i lib/models

Local Installation #

Quick Start #

Basic Usage #

All features are now specified using explicit parameters on the @Model annotation:

@Model(
  fromJson: true,    // Generate fromJson
  toJson: true,      // Generate toJson
  copyWith: true,    // Generate copyWith
  equatable: true,   // Generate == and hashCode
  stringify: true,   // Generate toString
)

Example: JSON-only (minimal) #

import 'package:dart_json_annotations/dart_json_annotations.dart';

part 'user.t.dart';

@Model(fromJson: true, toJson: true)  // JSON only - smallest output
class User {
  final int id;
  final String name;
  final String? email;
  
  User({required this.id, required this.name, this.email});
  
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

Example: Data class (common pattern) #

part 'user_profile.t.dart';

@Model(
  fromJson: true,
  toJson: true,
  copyWith: true,
  equatable: true,
  namingConvention: NamingConvention.snakeCase,
)
class UserProfile {
  @JsonKey(name: 'user_id')
  final int userId;
  
  final String firstName;
  final String lastName;
  
  @Ignore(equality: true)  // Exclude from == comparison
  final DateTime updatedAt;
  
  UserProfile({
    required this.userId,
    required this.firstName,
    required this.lastName,
    required this.updatedAt,
  });
  
  factory UserProfile.fromJson(Map<String, dynamic> json) => _$UserProfileFromJson(json);
}

Example: Bloc state (no JSON) #

part 'counter_state.t.dart';

@Model(copyWith: true, equatable: true)  // copyWith + equatable, NO json
class CounterState {
  final int count;
  final bool isLoading;
  final String? error;
  
  CounterState({required this.count, required this.isLoading, this.error});
}

// Generated usage:
final newState = state.copyWith(count: state.count + 1);
if (state1 == state2) { ... }  // Uses generated == operator

Example: Sealed/Union class #

Union classes support all parameter styles:

  • No parameters: factory Event.reset() = EventReset;
  • Positional: factory Event.setValue(int value) = EventSetValue;
  • Named: factory Event.load({required String id}) = EventLoad;
  • Mixed: factory Event.update(int id, {String? reason}) = EventUpdate;
part 'result.t.dart';

@Model(fromJson: true, toJson: true, equatable: true)
sealed class Result {
  const Result._();
  
  factory Result.fromJson(Map<String, dynamic> json) => _$ResultFromJson(json);
  
  // Different parameter styles all supported
  const factory Result.success(String data) = ResultSuccess;
  const factory Result.failure(String error, int code) = ResultFailure;
  const factory Result.loading() = ResultLoading;
  const factory Result.retry({required int attempt}) = ResultRetry;
}

// Generated usage:
final message = result.when(
  success: (data) => 'Got: $data',
  failure: (error, code) => 'Error $code: $error',
  loading: () => 'Loading...',
  retry: (attempt) => 'Retry #$attempt',
);

// Optional handling
result.maybeWhen(
  success: (data) => print(data),
  orElse: () => print('Not success'),
);

// Type checks
if (result.isSuccess) {
  final data = result.asSuccess!.data;
}

Annotations Reference #

@Model Options #

@Model(
  fromJson: false,     // Generate fromJson (default: false)
  toJson: false,       // Generate toJson (default: false)
  copyWith: false,     // Generate copyWith (default: false)
  copyWithNull: false, // Generate copyWithNull (default: false)
  equatable: false,    // Generate == and hashCode (default: false)
  stringify: false,    // Generate toString (default: false)
  mutable: false,      // Generate mutable class (default: false)
  namingConvention: NamingConvention.camelCase,  // Naming convention
  discriminator: 'type',  // Discriminator field for union classes
)

Field Annotations #

Annotation Description
@JsonKey(name: 'custom') Custom JSON key
@JsonKey(ignore: true) Skip in JSON
@JsonKey(defaultValue: '0') Default value
@Ignore() Ignore from ALL features
@Ignore(json: true) Ignore from JSON only
@Ignore(equality: true) Ignore from == comparison
@Ignore(copyWith: true) Ignore from copyWith
@Ignore(stringify: true) Ignore from toString

CLI Usage #

dart_json_gen [OPTIONS]

OPTIONS:
  -i, --input <PATH>    Input directory or file
  --build               Build Rust binary only
  --rebuild             Force rebuild before generation
  --clean               Delete generated files (use with -i to specify path)
  --threads <N>         Parallel threads (0 = auto)
  -v, --verbose         Detailed output (shows parsing, generation steps)
  -h, --help            Show help

EXAMPLES:
  dart_json_gen --build                    # Build binary
  dart_json_gen -i lib/models              # Generate code
  dart_json_gen -i lib/models --verbose    # Generate with detailed logs
  dart_json_gen --clean -i lib/models      # Clean generated files in lib/models
  dart_json_gen --clean -i lib/user.dart   # Clean specific file's generated code
  dart_json_gen -i lib --threads 4         # Use 4 threads

Configuration File #

Create a dart_json_gen.yaml (or dart_json_gen.yml) file in your project root to customize the generator:

# Custom extension for generated files
# Default: .t.dart
# Examples: .gen.dart, .g.dart, .generated.dart
generated_extension: ".t.dart"

Example configurations:

# Use .g.dart extension (like json_serializable)
generated_extension: ".g.dart"
# Use .t.dart extension
generated_extension: ".t.dart"
# Use .generated.dart extension
generated_extension: ".generated.dart"

Note: After changing the extension in the config file:

  1. Clean old generated files: dart_json_gen --clean -i lib/models
  2. Regenerate with new extension: dart_json_gen -i lib/models

Verbose Mode #

Use --verbose or -v to see detailed logging during code generation:

dart_json_gen -i lib/models --verbose

Output includes:

  • Files being parsed
  • Classes found in each file
  • Variant names for union/sealed classes
  • Files being generated or skipped
  • Detailed generation progress

Example verbose output:

[VERBOSE] Parsing 10 Dart files...
[VERBOSE] Found 3 class(es) in lib/models/user.dart
[VERBOSE]   Source: lib/models/user.dart
[VERBOSE] Processing: lib/models/user.dart
[VERBOSE] Generating code for 3 class(es) in user.gen.dart
[VERBOSE] Written: lib/models/user.gen.dart

Output Size Comparison #

For 200 models:

Configuration Lines/Model Total
JSON only (fromJson, toJson) 25 5,000 βœ…
Data class (fromJson, toJson, copyWith, equatable) 50 10,000
Bloc state (copyWith, equatable) 35 7,000 βœ…
Full features (all enabled) 70 14,000

Tip: Start with JSON-only features, add copyWith and equatable only when needed.

Migration from v1.x #

// v1.x (deprecated - used separate annotations)
@Json()
@CopyWith()
@Equatable()
class User { ... }

// v2.0+ (current - use explicit parameters)
@Model(
  fromJson: true,
  toJson: true,
  copyWith: true,
  equatable: true,
)
class User { ... }

Note: Preset constructors like @Model.json(), @Model.data(), etc. have been removed in favor of explicit parameters for better clarity and flexibility.

Project Structure #

dart_json_annotations/
β”œβ”€β”€ bin/dart_json_gen.dart     # Dart CLI
β”œβ”€β”€ codegen/                   # Rust source
β”‚   β”œβ”€β”€ Cargo.toml
β”‚   └── src/
β”‚       β”œβ”€β”€ main.rs
β”‚       β”œβ”€β”€ parser/mod.rs
β”‚       └── models/mod.rs
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ dart_json_annotations.dart
β”‚   └── src/annotations.dart
└── examples/

Roadmap #

  • βœ… JSON serialization
  • βœ… copyWith / copyWithNull
  • βœ… Equatable
  • βœ… Naming conventions
  • βœ… Checksum caching
  • βœ… Parallel processing (rayon)
  • βœ… @Model presets
  • βœ… Sealed/Union class support
  • βœ… Enum support
  • ❌ Watch mode || Do we really need this? because it is already instant generation
  • ❌ Config file

License #

MIT

0
likes
150
points
134
downloads

Publisher

unverified uploader

Weekly Downloads

High-performance code generation for Dart/Flutter: JSON, copyWith, equatable, and union/sealed class support. Rust-powered CLI with parallel processing.

Repository (GitHub)
View/report issues

Topics

#json #serialization #code-generation #equatable #copywith

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

path

More

Packages that depend on dart_json_annotations