dataforge 1.0.0-dev.0 copy "dataforge: ^1.0.0-dev.0" to clipboard
dataforge: ^1.0.0-dev.0 copied to clipboard

Build runner generator for deeply immutable Dataforge v1 value models.

Dataforge Generator #

The build_runner adapter for Dataforge v1 deeply immutable value models.

1.0.0-dev.0 is a preview, not the 1.0 GA release. APIs, diagnostics and generated output may still change in later preview versions.

Installation #

dependencies:
  dataforge_annotation: ^1.0.0-dev.0

dev_dependencies:
  build_runner: ^2.4.13
  dataforge: ^1.0.0-dev.0

All Dataforge packages in an application must resolve to the same preview version. Dart 3.9 or later is required.

Model declaration #

import 'package:dataforge_annotation/dataforge_annotation.dart';

part 'user.data.dart';

@Dataforge()
abstract final class User with _$User {
  const User._();

  factory User({
    required String name,
    @DataforgeDefault(<String>[]) List<String> tags,
    @JsonKey(name: 'display_name') String? displayName,
  }) = _User;

  factory User.fromJson(Map<String, Object?> json) = _User.fromJson;
}

The declaration contract is strict:

  • the public model is abstract final;
  • value properties come from one unnamed redirecting factory;
  • the generated target is _User and the generated mixin is _$User;
  • const User._(); provides the base constructor for the final implementation;
  • the part URI must end in .data.dart and match the source file;
  • JSON input is Map<String, Object?>;
  • a fromJson factory, when enabled, redirects to _User.fromJson.

Invalid declarations fail generation with a source-located DF diagnostic. The generator never rewrites the model source.

Generate #

dart run build_runner build

For continuous generation:

dart run build_runner watch

The published builder always emits .data.dart part files. The output suffix is not configurable in this preview.

Value semantics #

Generated implementations are final. Constructor, copyWith, default and decode boundaries recursively freeze the complete declared type tree:

  • List, Set and Map inputs are copied and exposed through unmodifiable collections;
  • nested collections and records are traversed recursively;
  • equality and hash use the same leaf witnesses as freeze;
  • copyWith may safely share values already frozen under compatible witness semantics.

Mutating caller-owned collections after construction cannot change a model. Set elements and Map keys that collapse under witness equality are rejected instead of being silently discarded.

Annotations #

@Dataforge #

@Dataforge(
  name: '',
  includeFromJson: true,
  includeToJson: true,
)

name changes the private implementation base name. JSON directions can be disabled independently.

@DataforgeDefault #

Dart does not allow a default directly on a redirecting factory parameter. Use compile-time metadata instead:

factory Page({
  @DataforgeDefault(1) int number,
  @DataforgeDefault(<String>[]) List<String> labels,
}) = _Page;

The resolved frontend validates that the constant is assignable and can be rendered without losing meaning.

@JsonKey #

factory User({
  @JsonKey(
    name: 'user_name',
    alternateNames: ['username'],
    includeIfNull: false,
  )
  String? name,
}) = _User;

ignore: true excludes a field from both JSON directions. An ignored required field must still have a construction default.

Strict JSON #

Generated codecs do not coerce unrelated runtime types. They validate required fields, nullability, unknown keys, aliases, duplicate decoded keys and custom witness output. Failures use DataforgeDecodeException or DataforgeEncodeException with a stable DFJ code and JSONPath.

DateTime is encoded as normalized UTC ISO-8601 text. Record values have recursive non-JSON value semantics, but a Record subtree used by JSON requires an exact DataforgeType<RecordShape> witness; otherwise generation reports DF1006.

Generic and custom values #

Any behavior that depends on a type parameter or unsupported custom leaf needs an explicit DataforgeType<T> witness:

@Dataforge()
abstract final class Box<T> with _$Box<T> {
  const Box._();

  factory Box({
    required DataforgeType<T> type,
    required T value,
  }) = _Box<T>;

  factory Box.fromJson(
    Map<String, Object?> json, {
    required DataforgeType<T> type,
  }) = _Box<T>.fromJson;
}

A custom witness is part of the value contract. Its identity tree and its freeze/equality/hash/codec behavior must remain immutable for its entire lifetime. freeze must isolate mutable input; equality and hash must agree.

Standalone CLI #

The dataforge_cli package provides a standalone resolved adapter:

dataforge generate .
dataforge check .

Both adapters use the same resolved facade and renderer. Representative fixtures assert byte parity, but the full GA type/platform parity matrix is not complete yet.

Troubleshooting #

  1. Run dart pub get in the nearest package root.
  2. Check the exact part, _$Model, _Model and private base constructor names.
  3. Use @DataforgeDefault rather than a redirecting-factory default.
  4. Provide one compatible witness for every type-dependent semantic subtree.
  5. Follow the first source-located DF diagnostic; later errors are often consequences of the same declaration mismatch.

See the 1.0 RFC and support matrix for the preview boundary.

1
likes
145
points
234
downloads

Documentation

Documentation
API reference

Publisher

verified publisherpub.lwjlol.com

Weekly Downloads

Build runner generator for deeply immutable Dataforge v1 value models.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

analyzer, build, dataforge_annotation, dataforge_base, source_gen

More

Packages that depend on dataforge