Skip to content

Support using Freezed on normal Dart classes#1157

Merged
rrousselGit merged 4 commits intomasterfrom
manual
Feb 23, 2025
Merged

Support using Freezed on normal Dart classes#1157
rrousselGit merged 4 commits intomasterfrom
manual

Conversation

@rrousselGit
Copy link
Copy Markdown
Owner

@rrousselGit rrousselGit commented Feb 23, 2025

We can now do:

@freezed
class Foo with _$Foo {
  Foo(this.value);

  final int value;
}

void main() {
  var foo = Foo(42);
  print(foo.copyWith(value: 21));
}

Summary by CodeRabbit

  • New Features

    • Introduced new type-safe classes and enhanced copy functionality to improve immutability.
    • Expanded support for flexible parameter processing and default handling.
    • Added a new sealed class Response<T> with factory constructors for data and error handling.
    • Enhanced the FromJson class with additional checks for constructor presence.
  • Refactor

    • Updated the build configuration to process a broader range of files while excluding specific cases.
    • Streamlined property management and constructor validation for clearer, more reliable data class generation.
    • Enhanced the logic for handling properties and constructors in the Freezed library.
    • Modified the Abstract class to improve property handling and mixin generation.
  • Tests

    • Revised test suites and added new examples to validate the extended functionality, including tests for the Response class.
    • Cleaned up code comments and annotations for improved clarity.
    • Updated tests to reflect changes in property accessors and constructor validations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 23, 2025

Walkthrough

The pull request updates several aspects of the Freezed package. In the build configuration, the file inclusion/exclusion lists were modified for test files. In the AST file, the documentation getter now returns a nullable string with an added conditional check. The Freezed generator has been refactored to remove the intermediary properties class, and models were extended with new extension methods and property adaptations. Templates now accept additional parameters (such as globalData) and include significant refactorings (including new sealed classes and enum definitions) along with adjusted method signatures. Several tests were updated with minor comment removals and added override annotations.

Changes

File(s) Summary
packages/freezed/build.yaml Updated generate_for to exclude a specific file (test/source_gen_src.dart) and include all files in test directories.
packages/freezed/lib/src/ast.dart Changed documentation getter return type from String to String? and added a check to return null when no documentation exists.
packages/freezed/lib/src/freezed_generator.dart Removed CommonProperties and its associated method; refactored property handling to use data.properties directly.
packages/freezed/lib/src/models.dart Added an extension on FormalParameter for type annotation; updated constructor validation and error messages; introduced CopyWithTarget and escapedName getter; changed property structure in ConstructorDetails.
packages/freezed/lib/src/templates/abstract_template.dart Added a new required parameter globalData and adjusted the logic in toString and mixin generation.
packages/freezed/lib/src/templates/concrete_template.dart Introduced new sealed classes (Foo, Bar, Baz), added an enum Source, and updated multiple method signatures for JSON, debug, and equality methods.
packages/freezed/lib/src/templates/copy_with.dart Replaced abstractCopyWithGetter with copyWithGetter requiring a needsCast parameter and updated conditional casting logic.
packages/freezed/lib/src/templates/from_json_template.dart Added a conditional check to return an empty string when no constructors are present.
packages/freezed/lib/src/templates/parameter_template.dart Changed parameter type from FormalParameterList to Iterable<FormalParameter> and ensured the doc field defaults to an empty string.
packages/freezed/lib/src/templates/properties.dart Added a required isSynthetic parameter and corresponding field; updated factory and copyWith methods to consistently handle this attribute.
packages/freezed/test/* (concrete_test, decorator_test, deep_copy_test) Removed several outdated or TODO comments.
packages/freezed/test/integration/* (deep_copy, multiple_constructors, single_class_constructor, extend) Added @override annotations to fields and properties; introduced a new file defining a Base and a Subclass using Freezed.
packages/freezed/test/manual_test.dart Introduced new data classes for manual testing of immutable data structures and JSON serialization.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant CopyWith
    Client->>CopyWith: call copyWithGetter(needsCast: true/false)
    CopyWith->>CopyWith: Evaluate needsCast parameter
    alt needsCast true
        CopyWith-->>Client: Return copyWith with cast applied
    else
        CopyWith-->>Client: Return copyWith without cast
    end
Loading
sequenceDiagram
    participant FromJson
    participant ClassData
    FromJson->>ClassData: Check for presence of constructors
    alt No constructors found
        ClassData-->>FromJson: Indicate absence
        FromJson-->>Client: Return empty JSON conversion string
    else
        ClassData-->>FromJson: Provide constructors details
        FromJson-->>Client: Process and return JSON conversion logic
    end
Loading

Possibly related PRs

  • Remove patterns #1152: Modifies the ConstructorDetails logic and property handling by introducing a new required parameter (isExternal), which closely aligns with the refactoring changes in this PR.

Poem

Hop, skip, code in line,
Changes flutter, oh so fine.
From null docs to stricter casts,
Properties now built to last.
With overrides and sealed delight,
I bunny-hop through code tonight!
🐇✨ Happy coding, day and night!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6952218 and 02a6235.

📒 Files selected for processing (2)
  • packages/freezed/test/single_class_constructor_test.dart (1 hunks)
  • packages/freezed/test/source_gen_src.dart (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/freezed/test/source_gen_src.dart
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: freezed (packages/freezed_lint, master, get)
  • GitHub Check: freezed (packages/freezed_annotation, master, get)
  • GitHub Check: freezed (packages/freezed, master, get)
🔇 Additional comments (1)
packages/freezed/test/single_class_constructor_test.dart (1)

236-253: LGTM! Improved test accuracy by excluding standard Object methods.

The test now correctly excludes both 'copyWith' (Freezed-specific) and 'hashCode' (standard Object method) from the documentation test, making it more focused on user-defined properties.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
packages/freezed/lib/src/templates/properties.dart (1)

125-156: ⚠️ Potential issue

Fix potential null reference in copyWith method.

The isSynthetic parameter is missing in the method signature but is used directly in the constructor call. This could lead to unexpected behavior.

Apply this diff to fix the issue:

  Property copyWith({
    String? type,
    String? name,
    bool? isNullable,
    bool? isDartList,
    bool? isDartMap,
    bool? isDartSet,
    bool? isFinal,
+   bool? isSynthetic,
    List<String>? decorators,
    String? defaultValueSource,
    bool? hasJsonKey,
    String? doc,
    bool? isPossiblyDartCollection,
    ParameterElement? parameterElement,
  }) {
    return Property(
      type: type ?? this.type,
      name: name ?? this.name,
-     isSynthetic: isSynthetic,
+     isSynthetic: isSynthetic ?? this.isSynthetic,
      isNullable: isNullable ?? this.isNullable,
      // ... rest of the parameters
    );
  }
🧹 Nitpick comments (2)
packages/freezed/lib/src/templates/concrete_template.dart (2)

14-18: Initial sealed class hierarchy.
Classes Foo, Bar, and Baz illustrate a sealed hierarchy. If these are just placeholders, consider relocating them to test or sample code to avoid confusion in production.


107-108: Potential out-of-bounds error.
.where(...).first can throw if p.name is not found. Consider using .firstWhereOrNull or a null safety check to avoid potential runtime exceptions.

- final correspondingProperty = constructor.properties
-     .where((element) => element.name == p.name)
-     .first;
+ final correspondingProperty = constructor.properties
+     .firstWhereOrNull((element) => element.name == p.name);
+ if (correspondingProperty == null) {
+   // Handle missing property scenario
+ }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a58c4f6 and 6d33f8f.

📒 Files selected for processing (18)
  • packages/freezed/build.yaml (1 hunks)
  • packages/freezed/lib/src/ast.dart (2 hunks)
  • packages/freezed/lib/src/freezed_generator.dart (3 hunks)
  • packages/freezed/lib/src/models.dart (15 hunks)
  • packages/freezed/lib/src/templates/abstract_template.dart (2 hunks)
  • packages/freezed/lib/src/templates/concrete_template.dart (6 hunks)
  • packages/freezed/lib/src/templates/copy_with.dart (1 hunks)
  • packages/freezed/lib/src/templates/from_json_template.dart (1 hunks)
  • packages/freezed/lib/src/templates/parameter_template.dart (3 hunks)
  • packages/freezed/lib/src/templates/properties.dart (5 hunks)
  • packages/freezed/test/concrete_test.dart (0 hunks)
  • packages/freezed/test/decorator_test.dart (0 hunks)
  • packages/freezed/test/deep_copy_test.dart (0 hunks)
  • packages/freezed/test/integration/deep_copy.dart (1 hunks)
  • packages/freezed/test/integration/extend.dart (1 hunks)
  • packages/freezed/test/integration/multiple_constructors.dart (3 hunks)
  • packages/freezed/test/integration/single_class_constructor.dart (4 hunks)
  • packages/freezed/test/manual_test.dart (1 hunks)
💤 Files with no reviewable changes (3)
  • packages/freezed/test/decorator_test.dart
  • packages/freezed/test/deep_copy_test.dart
  • packages/freezed/test/concrete_test.dart
✅ Files skipped from review due to trivial changes (2)
  • packages/freezed/test/integration/deep_copy.dart
  • packages/freezed/test/integration/multiple_constructors.dart
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: freezed (packages/freezed_lint, master, get)
  • GitHub Check: freezed (packages/freezed_annotation, master, get)
  • GitHub Check: freezed (packages/freezed, master, get)
🔇 Additional comments (44)
packages/freezed/lib/src/templates/from_json_template.dart (1)

15-17: Well-structured change that improves flexibility!

The addition of the early return for classes without constructors, along with the clear documentation, is an excellent approach to supporting manual Dart classes. This change:

  • Prevents unwanted JSON serialization code generation for manual classes
  • Respects the original class structure
  • Avoids potential compilation issues from adding annotations in parts
  • Maintains existing behavior for classes that need JSON serialization
packages/freezed/test/integration/extend.dart (2)

1-3: LGTM!

The import and part statement are correctly set up for using Freezed annotations.


5-8: LGTM!

The base class is well-designed with:

  • Immutable implementation using const constructor
  • Final field for value
  • Clear and concise named constructor
packages/freezed/lib/src/templates/abstract_template.dart (4)

4-4: New import looks consistent.
The import of concrete_template.dart is justified, as this file now references the methods(...) function from that module.


13-19: Added globalData in constructor and field.
Injecting a Library globalData provides broader contextual data to template generation. Ensure all call sites supply this new parameter consistently to avoid runtime errors.


23-32: Conditional property generation strategy.
Using needsAbstractGetters to always generate abstract getters if toJson, ==, toString, or copyWith is enabled, otherwise only for synthetic fields, aligns with Freezed’s design goals. This logic appears correct and maintains backward compatibility.


44-52: Passing globalData into methods(...).
Including globalData expands the context for method generation, and calling copyWithGetter(needsCast: true) in mixin scenarios is a neat solution for ensuring correct type casts. All changes here look good.

packages/freezed/lib/src/templates/concrete_template.dart (11)

39-39: Union key property check.
constructor.properties.every((e) => e.name != data.options.annotation.unionKey) ensures no naming collisions on the unionKey. This is a good safeguard.


53-67: Expanded constructor output and copyWith usage.
Displaying _properties, generating copyWithGetter(needsCast: false), and passing source: Source.syntheticClass into methods(...) align with the new approach for synthetic classes. Also exposing copyWith?.interface and copyWith?.concreteImpl(...) is consistent.


233-234: Filtering synthetic properties.
Narrowing constructor.properties to only those marked isSynthetic is consistent with the new design, ensuring that the “real” fields remain unaffected.


312-312: Closing brace formatting.
This trailing brace marks the end of _concreteFromJsonConstructor. Everything is syntactically consistent.


314-317: New enum Source.
Defining Source.mixin and Source.syntheticClass clarifies where particular template code is generated. This is a sensible enum extension.


319-344: Aggregated method generator.
The methods(...) function centralizes the generation of toJson, debugFillProperties, operator==, hashCode, and toString. It's a clean approach, reducing duplication across templates.


346-386: toJson template logic.
Supporting different behaviors for Source.mixin vs. Source.syntheticClass covers manual vs. generated classes. Omitting toJson for manual classes is consistent with the constraints of part files.


388-410: debugFillProperties for diagnostics.
Conditionally generating diagnostic properties if globalData.hasDiagnostics is a helpful approach, ensuring minimal overhead when not needed.


412-435: toStringMethod with optional diagnostic parameter.
Providing a parameter for controlling DiagnosticLevel is a thoughtful addition. This helps unify debugging experiences for classes implementing DiagnosticableTreeMixin.


437-474: operator== with deep collection equality.
This method gracefully handles dart:core collections, employing DeepCollectionEquality to compare nested elements.


476-521: hashCodeMethod handles large property sets.
Falling back to Object.hashAll for >= 20 fields is a robust strategy, avoiding overly large hash calls. The approach is well structured and maintains consistency with the rest of Freezed.

packages/freezed/lib/src/models.dart (12)

148-162: Formal parameter type extraction.
The typeAnnotation() extension on FormalParameter covers different AST parameter variants. This improves reliability when analyzing parameter types.


191-193: Tracking redirected factory constructors.
Defining freezedCtors as those with factoryKeyword and a redirectedConstructor ensures we only handle relevant union constructors.


195-199: Single non-factory constructor rule.
Strengthening the error message enforces that only one non-factory constructor is allowed for a @freezed-annotated class. This clarifies usage and prevents accidental misuse.


290-292: Synthesizing properties from formal parameters.
Call to Property.fromFormalParameter ensures consistent property definitions for each constructor’s parameters, factoring in synthetic vs. real fields.


338-338: Parameter forwarding.
Forwarding constructor.parameters.parameters to ParametersTemplate is essential for uniform generation of parameter-based code.


470-480: ConstructorInvocation refactor.
Renaming and repurposing the old super invocation logic into ConstructorInvocation clarifies how super calls or named constructors are invoked.


481-485: Introducing CopyWithTarget.
Encapsulating the name and parameters for copyWith logic is a neat abstraction that simplifies passing around relevant details.


493-493: Note on line 493.
No ~ was shown for this line in the snippet; skipping comment.


593-614: _computeCloneableProperties logic for single vs. multiple constructors.
Generating cloneable properties either from shared constructor parameters or from a dedicated copyWithTarget covers both union and single-constructor scenarios. Good coverage.


618-690: _computeReadableProperties merges fields and constructor parameters.
By collecting definitions from both actual fields and constructor parameters, this ensures a complete view of properties for the user-facing API. Thoughtful approach.


931-942: Escaping class names in escapedName.
Replacing $ in the class name and applying generics transforms avoids collisions or syntax errors.


944-950: Separate PropertyList for readability vs. cloneability.
Decoupling which fields appear in the abstract interface vs. copyWith calls clarifies usage, keeping the code base tidy.

packages/freezed/lib/src/ast.dart (1)

5-17: LGTM! Improved null-safety handling for documentation.

The change to return null instead of an empty string when no documentation exists is a good practice. It makes the API more explicit about the absence of documentation.

packages/freezed/test/manual_test.dart (2)

7-18: Add tests for JSON serialization.

The JsonManual class implements fromJson and toJson methods, but there are no tests verifying this functionality.

Would you like me to generate test cases for JSON serialization?


75-135: LGTM! Comprehensive test coverage for core functionality.

The test cases thoroughly verify:

  • copyWith functionality
  • equality comparisons
  • toString implementation
  • constructor behaviors
packages/freezed/lib/src/freezed_generator.dart (1)

50-68: LGTM! Simplified property handling.

The removal of the CommonProperties class and direct usage of data.properties reduces complexity while maintaining functionality. This is a good example of the KISS principle.

Also applies to: 105-119

packages/freezed/lib/src/templates/copy_with.dart (2)

64-78: LGTM! The new copyWithGetter method improves type safety.

The method now handles type casting more explicitly through the needsCast parameter, ensuring proper type safety when generating the copyWith getter.


83-124: LGTM! Enhanced pattern matching for copyWithTarget.

The changes improve the handling of copyWithTarget by:

  1. Adding a condition to check for copyWithTarget
  2. Using pattern matching to determine the return type
  3. Maintaining the existing functionality for cases without a target
packages/freezed/test/integration/single_class_constructor.dart (4)

380-382: LGTM! Explicit override annotation added.

The @override annotation clarifies that container is overriding a member from a superclass or mixin.


401-404: LGTM! Explicit override annotations added.

The @override annotations clarify that both b and c are overriding members from a superclass or mixin.


412-414: LGTM! Explicit override annotation added.

The @override annotation clarifies that first is overriding a member from a superclass or mixin.


421-428: LGTM! Explicit override annotation added and improved readability.

The @override annotation clarifies that odd is overriding a member from a superclass or mixin. The implementation is clear and readable.

packages/freezed/lib/src/templates/parameter_template.dart (3)

66-67: LGTM! Enhanced parameter type flexibility.

Changed parameter type from FormalParameterList to Iterable<FormalParameter> to accept a wider range of inputs.


84-85: LGTM! Improved documentation handling.

Added null coalescing operator to ensure doc field is never null by defaulting to an empty string.


95-104: LGTM! Streamlined parameter processing.

Direct use of the parameters iterable simplifies the code by removing the need to access a nested parameters property.

packages/freezed/build.yaml (1)

9-12: LGTM! Improved test file handling.

The changes enhance test coverage by:

  1. Excluding only specific test files that shouldn't be processed
  2. Including a broader range of test files through updated patterns

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
packages/freezed/test/integration/multiple_constructors.dart (1)

8-15: Consider documenting the purpose of the time field.

While the implementation is correct, adding documentation comments would help explain:

  • Why the time field exists
  • The significance of the default value DateTime(0, 0, 0)
  • When to use the optional time parameter in Response.data
 sealed class Response<T> with _$Response<T> {
   Response._({DateTime? time}) : time = time ?? DateTime(0, 0, 0);
-  // Constructors may enable passing parameters to ._();
+  /// Private constructor that initializes the response timestamp.
+  /// Uses [DateTime(0, 0, 0)] as default if no time is provided.
   factory Response.data(T value, {DateTime? time}) = ResponseData;
-  // If those parameters are named optionals, they are not required to be passed.
+  /// Creates a success response containing [value] and an optional [time].
   factory Response.error(Object error) = ResponseError;
 
+  /// The timestamp when this response was created.
+  /// Defaults to [DateTime(0, 0, 0)] if not specified.
   @override
   final DateTime time;
 }
packages/freezed/test/multiple_constructors_test.dart (1)

29-37: Enhance test coverage for the Response class.

While the current tests are good, consider adding these test cases:

  1. Verify that Response.error also accepts custom time
  2. Test copyWith functionality
  3. Test pattern matching with sealed class
 test('Response', () {
   expect(Response.data('a').time, DateTime(0, 0, 0));
   expect(
     Response.data('a', time: DateTime(1, 0, 0)).time,
     DateTime(1, 0, 0),
   );

   expect(Response<String>.error('err').time, DateTime(0, 0, 0));
+  expect(
+    Response<String>.error('err', time: DateTime(1, 0, 0)).time,
+    DateTime(1, 0, 0),
+  );
+
+  // Test copyWith
+  final response = Response.data('a', time: DateTime(1, 0, 0));
+  expect(
+    response.copyWith(time: DateTime(2, 0, 0)).time,
+    DateTime(2, 0, 0),
+  );
+
+  // Test pattern matching
+  final result = switch (response) {
+    ResponseData<String>(value: final v) => v,
+    ResponseError<String>() => 'error'
+  };
+  expect(result, 'a');
 });
packages/freezed/CHANGELOG.md (4)

3-4: Clarify the "mixed mode" description.
The new text “Freezed 3.0 is about supporting a "mixed mode". From now on, Freezed supports both the usual syntax:” nicely introduces the feature. Consider expanding slightly or linking to documentation that explains what “mixed mode” means and its benefits.


23-27: Neutral tone for listing benefits.
The bullet point "- Simple classes don't need Freezed's "weird" syntax and can stay simple" might be perceived as informal. Consider rephrasing to a more neutral tone, for example:

  • Simple classes can use a more straightforward syntax without the extra boilerplate
    This maintains the intended message while keeping the tone professional.

46-46: Remove trailing punctuation in heading.
The heading “### Breaking changes:” includes a trailing colon, which conflicts with markdown style guidelines (as noted by MD026).

Apply the following diff:

-### Breaking changes:
+### Breaking changes
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

46-46: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


48-50: Refine phrasing for grammatical consistency.
The breaking change description reads:
Freezed classes should now either be abstract, sealed, or manually implements _$MyClass.
For grammatical correctness, consider changing “manually implements” to “manually implement”.

Apply the following diff:

-Freezed classes should now either be `abstract`, `sealed`, or manually implements `_$MyClass`.
+Freezed classes should now either be `abstract`, `sealed`, or manually implement `_$MyClass`.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6d33f8f and 6952218.

📒 Files selected for processing (3)
  • packages/freezed/CHANGELOG.md (1 hunks)
  • packages/freezed/test/integration/multiple_constructors.dart (4 hunks)
  • packages/freezed/test/multiple_constructors_test.dart (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
packages/freezed/CHANGELOG.md

46-46: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: freezed (packages/freezed_lint, master, get)
  • GitHub Check: freezed (packages/freezed_annotation, master, get)
  • GitHub Check: freezed (packages/freezed, master, get)
🔇 Additional comments (6)
packages/freezed/test/integration/multiple_constructors.dart (1)

5-7: LGTM! Well-structured sealed class implementation.

The sealed class with a private constructor that handles default DateTime initialization is a good design choice. The generic type parameter T provides flexibility for different response types.

packages/freezed/CHANGELOG.md (5)

6-11: Check the example for usual syntax.
The code block showing the traditional (sealed class factory) example is well formatted and clear. Optionally, you might add a brief inline comment (or a sentence immediately after the code block) to emphasize that this remains the conventional way to define Freezed classes.


13-14: Smooth transition to the alternative syntax.
The “But also:” line effectively signals that an alternative, more natural Dart class syntax is supported. No changes are required, though you might consider clarifying in a follow-up sentence what benefits this alternative brings.


15-21: Review the alternative Dart class example.
The example using a regular Dart class (with a non-factory constructor and a final field) is clear and succinct. Ensure that any accompanying documentation further explains how this new usage integrates with existing Freezed features (like immutability and copyWith).


28-31: Highlighting inheritance and default handling is clear.
The explanation that complex unions now support inheritance and non-constant default values (using a non-factory MyClass._() constructor) is informative. You might consider adding a brief note on when to favor this pattern over the conventional approach.


32-44: Complex union example is well demonstrated.
The provided code sample for the Response<T> class clearly illustrates the new approach with a custom constructor and default value handling. This example should help users understand how to leverage inheritance and default-initialization within their Freezed classes.

@rrousselGit rrousselGit merged commit b51e44f into master Feb 23, 2025
4 checks passed
@rrousselGit rrousselGit deleted the manual branch February 23, 2025 21:08
@larssn
Copy link
Copy Markdown

larssn commented Feb 25, 2025

This is an extremely cool feature. We will definitely be using this new (highly familiar) syntax.

Is json_serializable still supported in mixed mode?

part 'model.g.dart' and
factory Model.fromJson(Map<String, dynamic> json) => _$ModelFromJson(json); doesn't seem to cut it anymore.

@rrousselGit
Copy link
Copy Markdown
Owner Author

Is json_serializable still supported in mixed mode?

You have to manually add the @JsonSerializable
Freezed can't add it for you in this scenario

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants