json_extension_type 1.2.0 copy "json_extension_type: ^1.2.0" to clipboard
json_extension_type: ^1.2.0 copied to clipboard

JSON Extension Type Generator - Automatically generates extension types for JSON to Dart typedef records and classes conversion.

example/example.md

JSON Extension Type Generator - Examples #

Quick Start Example #

1. Create a Model File #

// lib/models/user_model.dart
enum UserRole {
  admin,
  user,
  guest,
}

typedef User = ({
  String id,
  String name,
  String email,
  int age,
  UserRole role,
  List<String> permissions,
});

2. Generate Extensions #

jet generate lib/models

3. Generated Extension #

The tool adds this to your user_model.dart:

// ==========================================
// 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,
      role: UserRole.values.byName(data['role'] as String? ?? 'admin'),
      permissions: (data['permissions'] as List?)?.cast<String>() ?? [],
    );
  }

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

4. Use It #

void main() {
  final json = {
    'id': '123',
    'name': 'John Doe',
    'email': 'john@example.com',
    'age': 30,
    'role': 'admin',
    'permissions': ['read', 'write', 'delete'],
  };

  final user = UserJson(json).toModel();
  print('Name: ${user.name}');
  print('Role: ${user.role}');
  print('Can write: ${user.permissions.contains('write')}');
}

Advanced Examples #

Example 1: Nested Types #

// product_model.dart
typedef Product = ({
  String id,
  String name,
  double price,
  Category category,
  List<Review> reviews,
});

typedef Category = ({
  String id,
  String name,
});

typedef Review = ({
  String author,
  int rating,
  String comment,
});

Usage:

final json = {
  'id': 'p1',
  'name': 'Laptop',
  'price': 999.99,
  'category': {
    'id': 'c1',
    'name': 'Electronics',
  },
  'reviews': [
    {'author': 'Alice', 'rating': 5, 'comment': 'Great!'},
    {'author': 'Bob', 'rating': 4, 'comment': 'Good'},
  ],
};

final product = ProductJson(json).toModel();
print('${product.name}: \$${product.price}');
print('Category: ${product.category.name}');
print('Reviews: ${product.reviews.length}');

Example 2: Custom Annotations #

// order_model.dart
typedef Order = ({
  //#key:order_id
  String id,
  //#key:customer_name
  String customerName,
  //#key:total_amount #default:0.0
  double total,
  //#key:order_status
  OrderStatus status,
});

enum OrderStatus {
  pending,
  processing,
  shipped,
  delivered,
}

This maps JSON keys differently:

final json = {
  'order_id': 'ORD-123',           // → id
  'customer_name': 'Jane Smith',    // → customerName
  'total_amount': 299.99,           // → total
  'order_status': 'processing',     // → status
};

final order = OrderJson(json).toModel();

Example 3: Nullable Fields #

typedef Profile = ({
  String username,
  String? bio,              // Optional
  String? avatarUrl,        // Optional
  Address? mailingAddress,  // Optional custom type
  List<String> badges,      // Required list
});

typedef Address = ({
  String street,
  String city,
  String? postalCode,      // Optional
});

Usage:

final json1 = {
  'username': 'johndoe',
  'badges': ['verified', 'premium'],
};

final profile1 = ProfileJson(json1).toModel();
print(profile1.bio); // null
print(profile1.mailingAddress); // null

final json2 = {
  'username': 'janedoe',
  'bio': 'Software developer',
  'avatarUrl': 'https://example.com/avatar.jpg',
  'mailingAddress': {
    'street': '123 Main St',
    'city': 'New York',
  },
  'badges': [],
};

final profile2 = ProfileJson(json2).toModel();
print(profile2.bio); // 'Software developer'
print(profile2.mailingAddress?.city); // 'New York'

Example 4: API Integration #

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:yourapp/models/user_model.dart';

Future<List<User>> fetchUsers() async {
  final response = await http.get(
    Uri.parse('https://api.example.com/users'),
  );

  if (response.statusCode == 200) {
    final jsonData = jsonDecode(response.body);
    return UserJson(jsonData).toList();
  } else {
    throw Exception('Failed to load users');
  }
}

Future<User> fetchUser(String id) async {
  final response = await http.get(
    Uri.parse('https://api.example.com/users/$id'),
  );

  if (response.statusCode == 200) {
    final jsonData = jsonDecode(response.body);
    return UserJson(jsonData).toModel();
  } else {
    throw Exception('Failed to load user');
  }
}

Example 5: Local JSON Files #

import 'dart:convert';
import 'dart:io';
import 'package:yourapp/models/config_model.dart';

Future<Config> loadConfig() async {
  final file = File('config.json');
  final contents = await file.readAsString();
  final jsonData = jsonDecode(contents);
  return ConfigJson(jsonData).toModel();
}

Workflow #

Development Workflow #

  1. Create Model

    # Create model file
    touch lib/models/product_model.dart
    
  2. Define Types

    typedef Product = ({
      String id,
      String name,
      double price,
    });
    
  3. Generate

    jet generate lib/models
    
  4. Use

    final product = ProductJson(json).toModel();
    
  5. Update

    • Modify typedef
    • Run jet generate again
    • Extensions are automatically updated

Best Practices #

  1. Organize Models

    • Keep all models in lib/models/
    • One model per file
    • Use descriptive names ending with _model.dart
  2. Use Annotations Wisely

    • Only use #key when JSON keys don't match
    • Use #default for non-standard defaults
    • Document custom annotations
  3. Regenerate Regularly

    • After each model change
    • Before committing code
    • Part of build process
  4. Type Safety

    • Always use proper types
    • Prefer non-nullable when possible
    • Use enums for fixed sets of values
  5. Testing

    • Test with real JSON data
    • Verify default values
    • Check nullable behavior

Tips & Tricks #

Tip 1: Quick Regeneration #

Add to pubspec.yaml:

scripts:
  generate: jet generate lib/models

Then run:

dart run generate

Tip 2: Multiple Directories #

Generate for multiple directories:

jet generate lib/models
jet generate lib/data/types
jet generate lib/api/responses

Tip 3: CI/CD Integration #

# .github/workflows/ci.yml
- name: Generate extensions
  run: jet generate lib/models
  
- name: Verify no changes
  run: |
    if ! git diff --quiet; then
      echo "Extensions are out of sync!"
      exit 1
    fi

Tip 4: Editor Integration #

Add VS Code task (.vscode/tasks.json):

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Generate Extensions",
      "type": "shell",
      "command": "jet generate lib/models",
      "group": "build"
    }
  ]
}

Run with: Cmd+Shift+B → Select "Generate Extensions"

0
likes
140
points
8
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

JSON Extension Type Generator - Automatically generates extension types for JSON to Dart typedef records and classes conversion.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

args, path

More

Packages that depend on json_extension_type