https://github.com/wilinz/json5_model
A one-line command to convert a JSON file into a Dart model class.
https://github.com/wilinz/json5_model
dart flutter json json2dart json5
Last synced: 4 months ago
JSON representation
A one-line command to convert a JSON file into a Dart model class.
- Host: GitHub
- URL: https://github.com/wilinz/json5_model
- Owner: wilinz
- License: mit
- Created: 2023-03-08T10:56:23.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2025-04-30T17:02:22.000Z (about 1 year ago)
- Last Synced: 2025-11-11T16:33:10.418Z (7 months ago)
- Topics: dart, flutter, json, json2dart, json5
- Language: Dart
- Homepage: https://pub.dev/packages/json5_model
- Size: 229 KB
- Stars: 11
- Watchers: 1
- Forks: 1
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
Language: [English](README.md) | [简体中文](README-ZH.md)
# json5_model
Convert JSON files to Dart model classes with a single command
An improved version of json_model that supports nested JSON parsing, JSON5 files, and fixes several
bugs. Note: The original @meta functionality from json_model is not supported.
## Installation
Unix bash:
```shell
dart pub add \
json_annotation copy_with_extension equatable equatable_annotations \
dev:json5_model dev:json_serializable dev:copy_with_extension_gen dev:equatable_gen dev:build_runner
```
Windows Powershell:
```shell
dart pub add |
json_annotation copy_with_extension equatable equatable_annotations |
dev:json5_model dev:json_serializable dev:copy_with_extension_gen dev:equatable_gen dev:build_runner
```
---
## Version 5.0.0 and above: Use `equatable_gen` by default to replace
`autoequal`, migration method as follows:
There is a quick way to migrate the old code to `equatable_gen`.
Use the `--dist` parameter to specify the directory for the Dart model source code. Before
migrating, a backup will be automatically created. You can specify the backup directory using the
`--migr-autoequal-back ` parameter. If not specified, the default backup directory is
`./migr_autoequal_back`.
```shell
dart pub run json5_model --dist=lib/data/model --migr-autoequal
```
You can also migrate manually by replacing the following:
1. `@Autoequal()` => `@generateProps`
2. `@autoequal` => `@generateProps`
3. `@IgnoreAutoequal()` => `@ignore`
4. `@IncludeAutoequal()` => `@include`
5. replace import:
```dart
import 'package:autoequal/autoequal.dart';
```
=>
```dart
import 'package:equatable_annotations/equatable_annotations.dart';
```
---
## Usage
1. Create a directory named "json" in your project root
2. Create or copy JSON files into the "json" directory
3. Examples:
```shell
# Custom paths
flutter pub run json5_model --src=lib/data/json --dist=lib/data/model
# Use RegExp to extract class name prefix from filenames (e.g. remove "_response" suffix)
flutter pub run json5_model --src=lib/data/json --dist=lib/test/json --prefix-regexp "(.+?)_response$"
# Keep source files
flutter pub run json5_model --src=lib/data/json --dist=lib/data/model --keepsource
# Restore files
flutter pub run json5_model --src=lib/data/json --restore
```
## New Features
### File Restoration Command
Use the `--restore` parameter to restore all renamed JSON files:
```shell
flutter pub run json5_model --restore
```
### Keep Source Files
Add the `--keepsource` parameter to prevent automatic renaming of JSON files:
```shell
flutter pub run json5_model --keepsource
```
## Global Command Parameters
| Parameter | Description | Default Value |
|-------------------------|---------------------------------------------------------------------------------------------------------------|-----------------------|
| `--src` | Specify JSON source directory | ./jsons |
| `--dist` | Specify output directory | lib/models |
| `--nocopywith` | Disable copyWith method generation | false |
| `--noautoequal` | Disable equality comparison generation | false |
| `--keepsource` | Keep original JSON files (don't add _ prefix) after generation | false |
| `--restore` | Restore all renamed JSON files | false |
| `--clean` | Clean generated files | false |
| `--no-file-prefix` | Disable auto-adding class name prefixes (may cause name conflicts) | false |
| `--prefix-regexp` | Apply RegExp to filename to extract class name prefix | (.+?) |
| `--migr-autoequal` | Enable migration for the old version of autoequal. | false |
| `--migr-autoequal-back` | Specify the backup directory when migrating the old version of autoequal. Default is "./migr_autoequal_back". | ./migr_autoequal_back |
## How It Works
1. **Smart Type Inference**
Automatically detects and merges these type characteristics:
- Numeric type promotion (int → double)
- Handles nested objects and lists
- Automatic null safety handling
- Merges fields from multiple JSON structures
2. **File Management**
- By default adds "_" prefix to source JSON files after generation (can be disabled with
`--keepsource`)
- Use `--restore` to batch restore renamed files
3. **Advanced Features**
```dart
// Auto-generated extension methods
List githubListFormJson(List json) => ...
// Empty object construction
factory Github.emptyInstance() => Github(...);
// Deep copy support
Github newObj = oldObj.copyWith(id: 123);
```
## Example JSON → Dart Conversion
Input JSON:
```json5
{
"scores": [
90,
85.5,
null
],
"users": [
{
"name": "Alice",
"age": 25
},
{
"name": "Bob",
"height": 175.5
}
]
}
```
Generated Dart snippet:
```dart
// Automatic numeric type and nullable handling
List scores;
// Merges Map fields from different structures
class UsersItem {
String? name;
int? age;
double? height;
factory UsersItem.fromJson(Map json) =>
...
}
```
## Best Practices
1. **Version Control**
Recommend including original JSON files in version control (with proper data sanitization)
2. **CI Integration**
Add generation command to your CI pipeline:
```yaml
# GitHub Actions example
- name: Generate models
run: flutter pub run json5_model
```
3. **Mixed Type Handling**
When encountering incompatible types:
```dart
// Automatically falls back to dynamic type
List complexList;
```
4. **Custom Configuration**
Combine parameters for customized generation:
```shell
# Disable autoequal and copywith generation
flutter pub run json5_model --noautoequal --nocopywith
```
## Example:
```shell
flutter pub run json5_model --src=lib/data/json
```
json:
```json5
{
"id": 1296269,
"node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5",
"owner": {
"login": "octocat",
},
"private": false,
"topics": [
"octocat",
"atom",
"electron",
"api"
],
"permissions": {
"admin": false,
"push": false,
"pull": true
},
"security_and_analysis": {
"advanced_security": {
"status": "enabled"
},
"secret_scanning": {
"status": "enabled"
},
"secret_scanning_push_protection": {
"status": "disabled"
}
}
}
```
Dart:
```dart
import 'package:json_annotation/json_annotation.dart';
import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:equatable/equatable.dart';
import 'package:autoequal/autoequal.dart';
part 'github.g.dart';
@CopyWith()
@Autoequal()
@JsonSerializable(explicitToJson: true)
class Github
with EquatableMixin {
Github({required this.id,
required this.nodeId,
required this.owner,
required this.private,
required this.topics,
required this.permissions,
required this.securityAndAnalysis});
@JsonKey(name: "id", defaultValue: 0)
final int id;
@JsonKey(name: "node_id", defaultValue: "")
final String nodeId;
@JsonKey(name: "owner", defaultValue: Owner.emptyInstance)
final Owner owner;
@JsonKey(name: "private", defaultValue: false)
final bool private;
@JsonKey(name: "topics", defaultValue: [])
final List topics;
@JsonKey(name: "permissions", defaultValue: Permissions.emptyInstance)
final Permissions permissions;
@JsonKey(name: "security_and_analysis", defaultValue: SecurityAndAnalysis.emptyInstance)
final SecurityAndAnalysis securityAndAnalysis;
factory Github.fromJson(Map json) => _$GithubFromJson(json);
Map toJson() => _$GithubToJson(this);
factory Github.emptyInstance() =>
Github(id: 0,
nodeId: "",
owner: Owner.emptyInstance(),
private: false,
topics: [],
permissions: Permissions.emptyInstance(),
securityAndAnalysis: SecurityAndAnalysis.emptyInstance());
@override
List get props => _$props;
}
@CopyWith()
@Autoequal()
@JsonSerializable(explicitToJson: true)
class Owner
with EquatableMixin {
Owner({required this.login});
@JsonKey(name: "login", defaultValue: "")
final String login;
factory Owner.fromJson(Map json) => _$OwnerFromJson(json);
Map toJson() => _$OwnerToJson(this);
factory Owner.emptyInstance() => Owner(login: "");
@override
List get props => _$props;
}
@CopyWith()
@Autoequal()
@JsonSerializable(explicitToJson: true)
class Permissions
with EquatableMixin {
Permissions({required this.admin,
required this.push,
required this.pull});
@JsonKey(name: "admin", defaultValue: false)
final bool admin;
@JsonKey(name: "push", defaultValue: false)
final bool push;
@JsonKey(name: "pull", defaultValue: false)
final bool pull;
factory Permissions.fromJson(Map json) => _$PermissionsFromJson(json);
Map toJson() => _$PermissionsToJson(this);
factory Permissions.emptyInstance() => Permissions(admin: false, push: false, pull: false);
@override
List get props => _$props;
}
@CopyWith()
@Autoequal()
@JsonSerializable(explicitToJson: true)
class AdvancedSecurity
with EquatableMixin {
AdvancedSecurity({required this.status});
@JsonKey(name: "status", defaultValue: "")
final String status;
factory AdvancedSecurity.fromJson(Map json) => _$AdvancedSecurityFromJson(json);
Map toJson() => _$AdvancedSecurityToJson(this);
factory AdvancedSecurity.emptyInstance() => AdvancedSecurity(status: "");
@override
List get props => _$props;
}
@CopyWith()
@Autoequal()
@JsonSerializable(explicitToJson: true)
class SecretScanning
with EquatableMixin {
SecretScanning({required this.status});
@JsonKey(name: "status", defaultValue: "")
final String status;
factory SecretScanning.fromJson(Map json) => _$SecretScanningFromJson(json);
Map toJson() => _$SecretScanningToJson(this);
factory SecretScanning.emptyInstance() => SecretScanning(status: "");
@override
List get props => _$props;
}
@CopyWith()
@Autoequal()
@JsonSerializable(explicitToJson: true)
class SecretScanningPushProtection
with EquatableMixin {
SecretScanningPushProtection({required this.status});
@JsonKey(name: "status", defaultValue: "")
final String status;
factory SecretScanningPushProtection.fromJson(Map json) =>
_$SecretScanningPushProtectionFromJson(json);
Map toJson() => _$SecretScanningPushProtectionToJson(this);
factory SecretScanningPushProtection.emptyInstance() => SecretScanningPushProtection(status: "");
@override
List get props => _$props;
}
@CopyWith()
@Autoequal()
@JsonSerializable(explicitToJson: true)
class SecurityAndAnalysis
with EquatableMixin {
SecurityAndAnalysis({required this.advancedSecurity,
required this.secretScanning,
required this.secretScanningPushProtection});
@JsonKey(name: "advanced_security", defaultValue: AdvancedSecurity.emptyInstance)
final AdvancedSecurity advancedSecurity;
@JsonKey(name: "secret_scanning", defaultValue: SecretScanning.emptyInstance)
final SecretScanning secretScanning;
@JsonKey(name: "secret_scanning_push_protection",
defaultValue: SecretScanningPushProtection.emptyInstance)
final SecretScanningPushProtection secretScanningPushProtection;
factory SecurityAndAnalysis.fromJson(Map json) =>
_$SecurityAndAnalysisFromJson(json);
Map toJson() => _$SecurityAndAnalysisToJson(this);
factory SecurityAndAnalysis.emptyInstance() =>
SecurityAndAnalysis(advancedSecurity: AdvancedSecurity.emptyInstance(),
secretScanning: SecretScanning.emptyInstance(),
secretScanningPushProtection: SecretScanningPushProtection.emptyInstance());
@override
List get props => _$props;
}
```