JET Logo

JSON Extension Type (JET)

A Dart CLI tool that automatically generates extension types for JSON to Dart typedef records and classes conversion.

pub package License: MIT Dart


Features

  • โœ… Typedef records: Support for Dart typedef records
  • ๐Ÿงช Classes: Support for Dart classes with constructors (โš ๏ธ Experimental)
  • โœ… Primitive types: String, int, double, bool
  • โœ… Nullable types: Support for nullable fields (?)
  • โœ… Lists: List
  • โœ… Enums: Automatic string to enum conversion
  • โœ… Custom types: Nested record types and classes
  • โœ… Custom annotations: Customize JSON keys and default values

Installation

Global activation

dart pub global activate json_extension_type

Usage

Basic Command

jet generate [path]

Examples

# Generate extensions for lib/ directory
jet generate

# Generate for a specific directory
jet generate lib/models

# Show help
jet help

# Show version
jet --version

How It Works

1. Define Your Model

Create a *_model.dart file with typedef records or classes:

// lib/models/user_model.dart
enum UserStatus {
  active,
  inactive,
  banned,
}

// Option 1: Using typedef records
typedef User = ({
  String id,
  String name,
  String email,
  int age,
  UserStatus status,
  Address? address,
  List<String> tags,
});

// Option 2: Using classes (โš ๏ธ Experimental - May change in future releases)
class Person {
  final String id;
  final String name;
  final int age;
  final UserStatus status;
  
  Person({
    required this.id,
    required this.name,
    required this.age,
    required this.status,
  });
}

typedef Address = ({
  String street,
  String city,
  String country,
});

2. Generate Extensions

Run the generator:

jet generate lib/models

3. Generated Code

The tool automatically adds extension types to your model file with clear comments:

// ==========================================
// Generated by JSON Extension Type (JET)
// Do not modify manually
// Run "jet generate" to update
// ==========================================
extension type UserJson(dynamic data) {
  User toModel() {
    return (
      id: data['id'] as String? ?? '',
      name: data['name'] as String? ?? '',
      email: data['email'] as String? ?? '',
      age: data['age'] as int? ?? 0,
      status: UserStatus.values.byName(data['status'] as String? ?? 'active'),
      address: data['address'] != null ? AddressJson(data['address'] as Map<String, Object?>?).toModel() : null,
      tags: (data['tags'] as List?)?.cast<String>() ?? [],
    );
  }

  List<User> toList() {
    final data = this.data as List;
    return data.map((e) => UserJson(e).toModel()).toList();
  }
}

extension type AddressJson(dynamic data) {
  Address toModel() {
    return (
      street: data['street'] as String? ?? '',
      city: data['city'] as String? ?? '',
      country: data['country'] as String? ?? '',
    );
  }

  List<Address> toList() {
    final data = this.data as List;
    return data.map((e) => AddressJson(e).toModel()).toList();
  }
}

4. Use in Your Code

import 'package:yourapp/models/user_model.dart';

void main() {
  final jsonData = {
    'id': 'user-123',
    'name': 'John Doe',
    'email': 'john@example.com',
    'age': 30,
    'status': 'active',
    'address': {
      'street': '123 Main St',
      'city': 'New York',
      'country': 'USA',
    },
    'tags': ['developer', 'flutter'],
  };

  // Convert JSON to model
  final user = UserJson(jsonData).toModel();
  print(user.name); // John Doe
  print(user.status); // UserStatus.active

  // Convert JSON array
  final jsonList = [jsonData, /* ... */];
  final users = UserJson(jsonList).toList();
}

Custom Annotations

#key: Custom JSON Key

Map a different JSON key to a field:

typedef User = ({
  //#key:user_id
  String id,
  String name,
});

Generated code:

id: data['user_id'] as String? ?? '',

#default: Custom Default Value

Set a custom default value:

typedef Config = ({
  //#default:10
  int timeout,
  //#default:true
  bool enabled,
});

Generated code:

timeout: data['timeout'] as int? ?? 10,
enabled: data['enabled'] as bool? ?? true,

Combined Annotations

typedef Product = ({
  //#key:product_id #default:unknown
  String id,
  //#key:product_price #default:0.0
  double price,
});

Type Support

Primitive Types

  • String โ†’ default: ''
  • int โ†’ default: 0
  • double โ†’ default: 0.0
  • bool โ†’ default: false

Nullable Types

typedef User = ({
  String? nickname,  // Can be null
  int? age,         // Can be null
});

Lists

typedef User = ({
  List<String> tags,           // List of primitives
  List<Product> products,      // List of custom types
});

Enums

enum Status { active, inactive, pending }

typedef User = ({
  Status status,    // Non-nullable enum
  Status? role,     // Nullable enum
});

Custom Types

typedef Order = ({
  User customer,      // Non-nullable custom type
  Address? billing,   // Nullable custom type
});

Project Structure

your_project/
โ”œโ”€โ”€ lib/
โ”‚   โ””โ”€โ”€ models/
โ”‚       โ”œโ”€โ”€ user_model.dart        # Your models + generated extensions
โ”‚       โ””โ”€โ”€ product_model.dart     # Your models + generated extensions

CLI Options

Commands

  • generate [path] - Generate extensions for models
  • help - Show help message

Flags

  • -h, --help - Show help
  • -v, --version - Show version

Development

Run from source

cd json_extension_type
dart run bin/jet.dart generate path/to/models

Run tests

dart test

Contributing

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

License

MIT License - see LICENSE file for details

Examples

The /example directory contains complete, runnable examples:

  • basic_example.dart - Simple typedef records and basic conversions
  • nested_types_example.dart - Complex nested structures (products, categories, reviews)
  • custom_annotations_example.dart - Using #key and #default annotations
  • api_simulation_example.dart - Real-world API integration patterns

Run any example:

dart run example/basic_example.dart

See example/README.md for detailed documentation.

Libraries

code_generator
generator
json_extension_type
JSON Extension Type Generator
models
parser