Skip to content

Add when/map back#1271

Merged
rrousselGit merged 15 commits intomasterfrom
revert-pattern-removal
Jul 2, 2025
Merged

Add when/map back#1271
rrousselGit merged 15 commits intomasterfrom
revert-pattern-removal

Conversation

@rrousselGit
Copy link
Copy Markdown
Owner

@rrousselGit rrousselGit commented Jul 2, 2025

Summary by CodeRabbit

  • New Features

    • Added fine-grained configuration options to enable or disable generation of map, maybeMap, mapOrNull, when, maybeWhen, and whenOrNull methods for union types.
    • Introduced pattern-matching extension methods (map, maybeMap, mapOrNull, when, maybeWhen, whenOrNull) for sealed and union classes, supporting both exhaustive and fallback handling.
    • Enhanced generated data classes with improved copyWith, equality, hashCode, and toString implementations.
    • Updated documentation to describe legacy pattern matching utilities and their migration to Dart 3's native features.
  • Bug Fixes

    • Improved immutability and equality semantics for generated data classes and unions.
  • Chores

    • Updated Dart SDK requirement to 3.5.0 or higher.
    • Removed unrelated sealed class declarations from internal templates.
  • Tests

    • Added comprehensive tests for the new pattern-matching methods and configuration options, including compile-time checks and runtime behavior.
    • Enhanced test coverage for optional and forced generation of features such as copyWith, toString, equality, and toJson.
    • Added tests verifying generic support and asynchronous return types in pattern-matching methods.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jul 2, 2025

Warning

Rate limit exceeded

@rrousselGit has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 55 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 8f0a76b and 95f6f9f.

📒 Files selected for processing (3)
  • packages/freezed/CHANGELOG.md (1 hunks)
  • packages/freezed/test/optional_maybe_test.dart (1 hunks)
  • packages/freezed_annotation/CHANGELOG.md (1 hunks)

Walkthrough

This update introduces fine-grained configuration and comprehensive pattern-matching support for union types in the Freezed package. It adds new configuration options for generating map and when methods, implements pattern-matching extensions, enhances generated classes with concrete copyWith, equality, and toString, and provides extensive new and updated tests to verify these behaviors. Documentation is updated to clarify legacy and new pattern-matching utilities.

Changes

File(s) Change Summary
benchmarks/lib/src/copy_with.freezed.dart, benchmarks/lib/src/equal.freezed.dart Enhanced generated classes with concrete copyWith, equality, toString, and pattern-matching extensions.
packages/freezed_annotation/lib/freezed_annotation.dart,
freezed_annotation.g.dart
Added FreezedMapOptions and FreezedWhenOptions classes, converters, and integrated them into the Freezed annotation and JSON deserialization.
packages/freezed/lib/src/models.dart Added MapConfig and WhenConfig for configuration, updated ClassConfig and annotation parsing accordingly.
packages/freezed/lib/src/freezed_generator.dart Imported and invoked new pattern-matching template during code generation.
packages/freezed/lib/src/templates/pattern_template.dart Introduced new template for generating pattern-matching extension methods (map, when, etc.).
packages/freezed/lib/src/templates/concrete_template.dart Removed unused sealed class declarations (Foo, Bar, Baz).
packages/freezed/lib/src/tools/type.dart Broadened isNullable logic to include Dart core Null type.
benchmarks/pubspec.yaml Updated Dart SDK constraint to require version 3.5.0 or higher.
packages/freezed/README.md Added documentation for legacy pattern-matching utilities and migration guidance.
packages/freezed_annotation/test/freezed_test.dart Added tests for FreezedMapOptions, FreezedWhenOptions, and their integration with Freezed.
packages/freezed/test/generic_test.dart,
multiple_constructors_test.dart,
map_test.dart,
optional_maybe_test.dart,
single_class_constructor_test.dart,
when_test.dart,
integration/optional_maybe.dart
Added and updated tests for pattern-matching, configuration, and runtime behaviors of union types.
packages/freezed/test/options_test.dart Deleted obsolete test file (replaced by more granular tests elsewhere).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AnnotatedClass
    participant FreezedGenerator
    participant PatternTemplate

    User->>AnnotatedClass: Annotate with @Freezed (with map/when options)
    AnnotatedClass->>FreezedGenerator: Passes config and class info
    FreezedGenerator->>PatternTemplate: Requests pattern-matching code
    PatternTemplate-->>FreezedGenerator: Returns extensions (map, when, etc.)
    FreezedGenerator-->>AnnotatedClass: Emits generated code (copyWith, equality, pattern-matching)
    User->>AnnotatedClass: Calls map/when/maybeMap/maybeWhen methods
Loading

Possibly related PRs

  • rrousselGit/freezed#1224: Fixes equality/hashCode generation for superclasses, directly related to the equality/hashCode enhancements in generated classes in this PR.
  • rrousselGit/freezed#1152: Removes pattern-matching configuration and related code, the inverse of this PR's addition of such features.
  • rrousselGit/freezed#1189: Documents migration to Dart 3 sealed classes and native pattern matching, conceptually linked to the pattern-matching features implemented here.

Poem

In fields of code where unions play,
The rabbit hops with joy today!
With map and when, the patterns grow,
And copyWith lets the models flow.
Equality shines, tests abound—
🐇 Pattern-matching magic now is found!


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @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.

@rrousselGit rrousselGit changed the title Merge Add when/map back Jul 2, 2025
@rrousselGit rrousselGit marked this pull request as ready for review July 2, 2025 20:30
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

🧹 Nitpick comments (3)
packages/freezed_annotation/test/freezed_test.dart (1)

156-226: Fix const constructor warnings.

The tests correctly verify complex JSON deserialization scenarios and error handling, but need const keywords to address linting warnings.

Apply this diff to fix the linting warnings:

-    test('()', () {
-      expect(FreezedMapOptions().map, isNull);
-      expect(FreezedMapOptions().maybeMap, isNull);
-      expect(FreezedMapOptions().mapOrNull, isNull);
+    test('()', () {
+      expect(const FreezedMapOptions().map, isNull);
+      expect(const FreezedMapOptions().maybeMap, isNull);
+      expect(const FreezedMapOptions().mapOrNull, isNull);
-    test('()', () {
-      expect(FreezedWhenOptions().when, isNull);
-      expect(FreezedWhenOptions().maybeWhen, isNull);
-      expect(FreezedWhenOptions().whenOrNull, isNull);
+    test('()', () {
+      expect(const FreezedWhenOptions().when, isNull);
+      expect(const FreezedWhenOptions().maybeWhen, isNull);
+      expect(const FreezedWhenOptions().whenOrNull, isNull);
packages/freezed_annotation/lib/freezed_annotation.dart (2)

167-168: Fix typo in error message.

The error message has a grammatical error.

-      'Expected a bool a Map, got ${json.runtimeType}',
+      'Expected a bool or a Map, got ${json.runtimeType}',

173-173: Consider consistent implementation between converters.

The toJson methods are inconsistent - one returns null while the other throws UnimplementedError. Since these are read-only configuration options, either approach works, but consistency would improve maintainability.

Consider using the same approach in both converters. Either both return null or both throw UnimplementedError.

Also applies to: 195-195

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 170db3b and a5e0ef0.

📒 Files selected for processing (20)
  • benchmarks/lib/src/copy_with.freezed.dart (2 hunks)
  • benchmarks/lib/src/equal.freezed.dart (4 hunks)
  • benchmarks/pubspec.yaml (1 hunks)
  • packages/freezed/README.md (2 hunks)
  • packages/freezed/lib/src/freezed_generator.dart (2 hunks)
  • packages/freezed/lib/src/models.dart (5 hunks)
  • packages/freezed/lib/src/templates/concrete_template.dart (0 hunks)
  • packages/freezed/lib/src/templates/pattern_template.dart (1 hunks)
  • packages/freezed/lib/src/tools/type.dart (1 hunks)
  • packages/freezed/test/generic_test.dart (1 hunks)
  • packages/freezed/test/integration/optional_maybe.dart (2 hunks)
  • packages/freezed/test/map_test.dart (1 hunks)
  • packages/freezed/test/multiple_constructors_test.dart (1 hunks)
  • packages/freezed/test/optional_maybe_test.dart (1 hunks)
  • packages/freezed/test/options_test.dart (0 hunks)
  • packages/freezed/test/single_class_constructor_test.dart (1 hunks)
  • packages/freezed/test/when_test.dart (1 hunks)
  • packages/freezed_annotation/lib/freezed_annotation.dart (3 hunks)
  • packages/freezed_annotation/lib/freezed_annotation.g.dart (2 hunks)
  • packages/freezed_annotation/test/freezed_test.dart (2 hunks)
💤 Files with no reviewable changes (2)
  • packages/freezed/lib/src/templates/concrete_template.dart
  • packages/freezed/test/options_test.dart
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
packages/freezed/lib/src/freezed_generator.dart (2)
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version upgrade in freezed_lint is blocked by invertase/dart_custom_lint#300 which handles the broader upgrade of analyzer, analyzer_plugin, and source_gen dependencies in custom_lint.
benchmarks/pubspec.yaml (2)
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version upgrade in freezed_lint is blocked by invertase/dart_custom_lint#300 which handles the broader upgrade of analyzer, analyzer_plugin, and source_gen dependencies in custom_lint.
packages/freezed_annotation/lib/freezed_annotation.g.dart (1)
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
packages/freezed_annotation/test/freezed_test.dart (1)
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
packages/freezed/test/optional_maybe_test.dart (2)
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version upgrade in freezed_lint is blocked by invertase/dart_custom_lint#300 which handles the broader upgrade of analyzer, analyzer_plugin, and source_gen dependencies in custom_lint.
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
packages/freezed_annotation/lib/freezed_annotation.dart (1)
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
🪛 LanguageTool
packages/freezed/README.md

[uncategorized] ~1273-~1273: You might be missing the article “a” here.
Context: ...t b, bool c) = Second; } With such class, while [when] will be: dart var mod...

(AI_EN_LECTOR_MISSING_DETERMINER_A)

🪛 GitHub Actions: Build
packages/freezed_annotation/test/freezed_test.dart

[warning] 65-65: Use 'const' with the constructor to improve performance (prefer_const_constructors)


[warning] 66-66: Use 'const' with the constructor to improve performance (prefer_const_constructors)


[warning] 67-67: Use 'const' with the constructor to improve performance (prefer_const_constructors)


[warning] 133-133: Use 'const' with the constructor to improve performance (prefer_const_constructors)


[warning] 134-134: Use 'const' with the constructor to improve performance (prefer_const_constructors)


[warning] 135-135: Use 'const' with the constructor to improve performance (prefer_const_constructors)

🔇 Additional comments (47)
benchmarks/pubspec.yaml (1)

5-5: LGTM: SDK constraint appropriately updated for Dart 3 features.

The SDK constraint update to ^3.5.0 is necessary to support the enhanced pattern matching capabilities introduced in this PR.

packages/freezed/lib/src/freezed_generator.dart (2)

4-4: LGTM: Pattern template import added correctly.

The import enables access to the new pattern matching template generation functionality.


110-110: LGTM: Pattern generation properly integrated into the workflow.

The yield patterns(data); statement is correctly positioned after the Abstract template and before the Concrete template loop, ensuring pattern matching methods are generated for sealed classes at the appropriate point in the generation process.

packages/freezed/lib/src/tools/type.dart (1)

14-16: LGTM: Enhanced nullability detection for the Null type.

The addition of isDartCoreNull to the nullability check is a logical improvement that ensures the Dart core Null type is correctly identified as nullable, which supports accurate pattern matching code generation.

packages/freezed/test/generic_test.dart (1)

62-81: LGTM: Comprehensive test coverage for generic pattern matching.

The test effectively verifies that map and maybeMap methods work correctly with generic type parameters, ensuring type safety and proper behavior across all constructor variants of MultipleConstructors<int, double>.

packages/freezed/test/single_class_constructor_test.dart (4)

375-382: LGTM: Comprehensive test for single-case union map method.

The test correctly verifies that the map method is now available on single-constructor unions and properly executes the callback with the expected return value.


384-392: LGTM: Proper test coverage for maybeMap method.

The test effectively verifies the maybeMap method functionality, including the orElse callback handling for single-case unions.


394-399: LGTM: Well-structured when method test.

The test properly validates the when method execution with parameter extraction and return value verification.


401-409: LGTM: Complete maybeWhen method test coverage.

The test thoroughly validates the maybeWhen method with proper parameter handling and orElse callback verification.

packages/freezed_annotation/lib/freezed_annotation.g.dart (2)

11-21: LGTM: Generated JSON deserialization functions look correct.

The generated _$FreezedMapOptionsFromJson and _$FreezedWhenOptionsFromJson functions follow the expected json_serializable patterns for deserializing boolean options from JSON keys.


33-34: LGTM: Integration with custom converters is properly implemented.

The Freezed class JSON deserialization correctly integrates the new map and when fields using the custom converters, maintaining consistency with the existing pattern.

packages/freezed/test/multiple_constructors_test.dart (5)

234-241: LGTM: Comprehensive when method testing.

The tests correctly verify that the when method dispatches to the appropriate callbacks based on the constructor used, covering both the unnamed constructor and named second constructor.


242-263: LGTM: Thorough whenOrNull method testing.

The tests properly verify whenOrNull behavior including:

  • Correct callback dispatch for both constructors
  • Null return when callback is null
  • Null return when matching callback is missing

265-285: LGTM: Complete map method testing.

The map and mapOrNull tests correctly verify the pattern matching behavior with proper callback dispatch and null handling for missing callbacks.


287-311: LGTM: Solid maybeMap and maybeWhen testing.

The tests correctly verify the maybeMap and maybeWhen methods with their orElse fallback behavior when callbacks are null or missing.


313-403: LGTM: Excellent async pattern matching coverage.

The FutureOr tests comprehensively verify that all pattern matching methods (maybeMap, mapOrNull, map, maybeWhen, whenOrNull, when) correctly handle both synchronous values and Future completions. The test structure properly uses expectLater for async assertions.

packages/freezed/README.md (3)

1193-1203: LGTM: Clear legacy warning and migration guidance.

The warning section effectively communicates that these are legacy features superseded by Dart 3's built-in pattern matching, while still providing support for users who haven't migrated yet.


1204-1255: LGTM: Accurate when method documentation.

The when method documentation correctly explains:

  • Destructuring behavior
  • How callback signatures match constructor parameters
  • Proper usage examples with multiple union cases

1259-1309: LGTM: Clear map method documentation.

The map method documentation effectively explains:

  • Non-destructuring behavior (receives whole instance)
  • Differences from when method
  • Practical usage examples including copyWith operations
packages/freezed/test/integration/optional_maybe.dart (2)

6-16: LGTM: Proper configuration for disabling map and when methods.

The OptionalMaybeMap and OptionalMaybeWhen classes correctly use FreezedMapOptions.none and FreezedWhenOptions.none to disable their respective pattern matching methods. The union structure with two constructors provides good test coverage.


33-41: LGTM: Correct configuration for forcing pattern matching methods.

The ForceUnionMethod and ForceUnionMethod2 classes properly use FreezedMapOptions.all and FreezedWhenOptions.all to enable all pattern matching methods. The mix of single constructor and named constructor provides diverse test scenarios.

packages/freezed_annotation/test/freezed_test.dart (3)

5-69: LGTM: Comprehensive FreezedMapOptions testing.

The test suite thoroughly covers FreezedMapOptions functionality including JSON deserialization, static presets (.all, .none), and default constructor behavior. All assertions verify the correct boolean flag handling.


71-137: LGTM: Complete FreezedWhenOptions testing.

The FreezedWhenOptions tests mirror the map options tests appropriately, ensuring comprehensive coverage of all when-related functionality with proper flag verification.


147-152: LGTM: Proper integration testing for new fields.

The updates to the default Freezed test correctly verify that the new map and when properties are null by default, maintaining consistency with other optional fields.

packages/freezed/test/when_test.dart (1)

1-437: Comprehensive test coverage for when methods!

The test suite provides excellent coverage of when, maybeWhen, and whenOrNull methods with proper compile-time error validation and runtime behavior tests.

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

390-412: Clean configuration classes for pattern matching methods.

The MapConfig and WhenConfig classes provide a clear structure for managing the generation options of pattern matching methods.


1144-1162: Well-designed logic for pattern matching generation.

The condition for generating pattern matching methods is appropriate - checking for non-manual, non-private constructors ensures patterns are only generated when there are actual union cases to match against.


1234-1279: Consistent annotation parsing for map/when options.

The parsing logic properly handles nested configuration objects and falls back to global configs when local values are not specified.

packages/freezed/test/map_test.dart (1)

1-438: Excellent test coverage for map methods!

The test suite mirrors the structure of when_test.dart and provides comprehensive coverage of map, maybeMap, and mapOrNull methods with proper type safety validation.

benchmarks/lib/src/equal.freezed.dart (1)

87-241: Generated pattern matching extension looks correct.

The ModelWithListPatterns extension demonstrates the new pattern matching methods (map, maybeMap, mapOrNull, when, maybeWhen, whenOrNull) with proper switch expression usage and documentation.

packages/freezed/lib/src/templates/pattern_template.dart (4)

1-26: LGTM! Well-structured pattern matching template.

The overall structure is clean and follows a consistent pattern for generating extension methods. The empty buffer check prevents generating empty extensions.


198-268: Excellent implementation of map-style pattern matching.

The _mapImpl function correctly handles all edge cases:

  • Optional callbacks with proper null checks
  • Different return type scenarios (nullable vs non-nullable)
  • Fallback behavior with orElse
  • Proper error handling for non-sealed classes

The generated switch expression is clean and follows Dart 3 best practices.


270-343: Well-implemented when-style pattern matching with proper destructuring.

The _whenImpl correctly handles parameter transformation and property access for destructuring. The fallback logic mirrors _mapImpl consistently.


363-363: constructorNameToCallbackName: Definition and Import Verified

  • The function constructorNameToCallbackName is defined in packages/freezed/lib/src/templates/prototypes.dart.
  • prototypes.dart is correctly imported in packages/freezed/lib/src/templates/pattern_template.dart.

No further changes needed.

packages/freezed_annotation/lib/freezed_annotation.dart (2)

65-104: Clean and well-documented configuration class for map options.

The FreezedMapOptions class follows good practices:

  • Clear documentation for each field
  • Convenient static presets (all and none)
  • Proper JSON deserialization support
  • Nullable fields for configuration cascading

479-491: Excellent integration of pattern matching options.

The new map and when fields are well-integrated into the Freezed annotation:

  • Clear documentation about configuration cascading
  • Proper use of custom JsonConverters
  • Consistent with existing option fields
benchmarks/lib/src/copy_with.freezed.dart (2)

75-230: Generated pattern matching extensions look correct.

The generated ModelPatterns extension properly implements all six pattern matching methods (maybeMap, map, mapOrNull, maybeWhen, when, whenOrNull) with:

  • Correct switch expression syntax
  • Proper null handling for optional callbacks
  • Appropriate fallback behavior
  • Clear documentation

This demonstrates the pattern template is working as designed.


370-525: Consistent pattern matching generation for ModelWrapper.

The ModelWrapperPatterns extension shows the same high-quality code generation, confirming the template works correctly for different model types.

packages/freezed/test/optional_maybe_test.dart (9)

1-6: LGTM! Clean and appropriate imports.

The imports are well-organized and include all necessary dependencies for analyzer integration testing, build testing, and local test utilities.


8-23: LGTM! Comprehensive error checking test.

The test correctly validates that the generated .freezed.dart file compiles without errors using the analyzer API. The approach of resolving sources and checking for errors is appropriate for integration testing.


25-48: LGTM! Well-structured test for selective method generation.

The test effectively demonstrates that:

  1. Accessing disabled maybeMap method causes compile errors (lines 32, 39)
  2. Other related methods (map, mapOrNull, whenOrNull, maybeWhen, when) remain functional (lines 33-47)

The dual approach of testing compile failures and then showing working alternatives provides comprehensive coverage.


50-73: LGTM! Consistent test pattern for maybeWhen disabling.

This test mirrors the maybeMap test structure effectively, validating that disabling maybeWhen causes compile errors while preserving other pattern matching methods. The consistency in test approach enhances maintainability.


75-83: LGTM! Straightforward test for copyWith disabling.

The test correctly verifies that accessing the disabled copyWith method results in a compile error, which is the expected behavior for optional code generation features.


85-90: LGTM! Appropriate test for disabled toString behavior.

The test correctly validates that when toString is disabled, the object falls back to Dart's default instance string representation. The expected string format matches Dart's standard behavior.


92-101: LGTM! Thorough test for disabled equality and hash code.

The test appropriately verifies that when equality and hash code generation are disabled:

  1. Two instances of the same class are not equal (lines 94-96)
  2. Two instances have different hash codes (lines 98-100)

This confirms the fallback to Dart's default reference-based equality.


103-119: LGTM! Comprehensive test for forced union method generation.

This test excellently demonstrates two different union patterns:

  1. Traditional union-style methods with named parameters (ForceUnionMethod2, lines 104-110)
  2. Single-value union methods (ForceUnionMethod, lines 112-118)

The test validates all pattern matching methods (map, mapOrNull, maybeMap, when, whenOrNull, maybeWhen) work correctly when forced to generate.


121-136: LGTM! Complete test coverage for JSON serialization control.

The tests effectively cover both aspects of JSON serialization control:

  1. Disabling toJson while preserving fromJson functionality (lines 121-132)
  2. Forcing toJson generation and validating output format (lines 134-136)

The JSON output assertion {'a': 42} provides concrete validation of the serialization behavior.

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: 3

♻️ Duplicate comments (1)
packages/freezed/test/optional_maybe_test.dart (1)

18-20: File path is correct - past review comment appears to be mistaken.

The current file path /freezed/test/integration/optional_maybe.freezed.dart is correct since the source file is located at test/integration/optional_maybe.dart (as seen in line 12). The generated file should be in the same directory as the source file.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9c6d491 and 8f0a76b.

📒 Files selected for processing (1)
  • packages/freezed/test/optional_maybe_test.dart (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
packages/freezed/test/optional_maybe_test.dart (2)
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version update to >=7.0.0 in freezed_lint package is blocked by invertase/dart_custom_lint#300, preventing alignment with freezed package's analyzer requirements.
Learnt from: lishaduck
PR: rrousselGit/freezed#1147
File: packages/freezed_lint/pubspec.yaml:12-12
Timestamp: 2025-01-07T20:51:22.701Z
Learning: The analyzer version upgrade in freezed_lint is blocked by invertase/dart_custom_lint#300 which handles the broader upgrade of analyzer, analyzer_plugin, and source_gen dependencies in custom_lint.
🪛 GitHub Actions: Build
packages/freezed/test/optional_maybe_test.dart

[error] 1-1: Dart format check failed. The file was reformatted. Run 'dart format .' to apply formatting changes.

🔇 Additional comments (7)
packages/freezed/test/optional_maybe_test.dart (7)

25-39: LGTM! Test correctly verifies maybeMap is not generated.

The test properly uses throwsCompileError to verify that accessing maybeMap on OptionalMaybeMap results in a compile-time error, while other methods remain accessible.


50-64: LGTM! Test correctly verifies maybeWhen is not generated.

The test properly verifies that maybeWhen is not available on OptionalMaybeWhen while other pattern matching methods remain functional.


75-83: LGTM! Test correctly verifies copyWith can be disabled.

The test appropriately verifies that accessing copyWith results in a compile error when the method generation is disabled.


85-90: LGTM! Test correctly verifies toString can be disabled.

The test confirms that when toString generation is disabled, the object falls back to Dart's default toString implementation showing the runtime type.


92-101: LGTM! Test correctly verifies equality and hashCode can be disabled.

The test properly verifies that when equality generation is disabled, object instances don't compare as equal and have different hash codes, falling back to identity comparison.


103-119: LGTM! Test correctly verifies forced generation of when/map methods.

The test demonstrates that both union-style and single-case pattern matching methods can be forced to be generated, covering all variants (map, mapOrNull, maybeMap, when, whenOrNull, maybeWhen).


121-136: LGTM! Tests correctly verify toJson can be disabled and forced.

Both tests properly verify that toJson method generation can be controlled - disabled by default but forced when needed, and that fromJson remains available when toJson is disabled.

Comment on lines +1 to +137
import 'package:analyzer/dart/analysis/results.dart';
import 'package:build_test/build_test.dart';
import 'package:test/test.dart';

import 'common.dart';
import 'integration/optional_maybe.dart';

void main() {
test('has no issue', () async {
final main = await resolveSources(
{
'freezed|test/integration/optional_maybe.dart': useAssetReader,
},
(r) => r.libraries.firstWhere(
(element) => element.source.toString().contains('optional_maybe')),
);

final errorResult = await main.session.getErrors(
'/freezed/test/integration/optional_maybe.freezed.dart')
as ErrorsResult;

expect(errorResult.errors, isEmpty);
});

test('does not generates maybeMap', () async {
await expectLater(compile(r'''
import 'optional_maybe.dart';

void main() {
final value = OptionalMaybeMap.first();

value.maybeMap(orElse: () => null);
value.map(
first: (_) {},
second: (_) {},
);
value.mapOrNull();
}
'''), throwsCompileError);

const OptionalMaybeMap.first()
..whenOrNull()
..maybeWhen(orElse: () {})
..when(
first: () {},
second: () {},
);
});

test('does not generates maybeWhen', () async {
await expectLater(compile(r'''
import 'optional_maybe.dart';

void main() {
final value = OptionalMaybeWhen.first();

value.maybeWhen(orElse: () => null);
value.when(
first: () {},
second: () {},
);
value.whenOrNull();
}
'''), throwsCompileError);

const OptionalMaybeWhen.first()
..mapOrNull()
..maybeMap(orElse: () {})
..map(
first: (_) {},
second: (_) {},
);
});

test('can disable copyWith', () async {
await expectLater(compile(r'''
import 'optional_maybe.dart';

void main() {
OptionalCopyWith().copyWith;
}
'''), throwsCompileError);
});

test('can disable toString', () {
expect(
const OptionalToString().toString(),
r"Instance of '_OptionalToString'",
);
});

test('can disable ==/hash', () {
expect(
OptionalEqual(),
isNot(OptionalEqual()),
);
expect(
OptionalEqual().hashCode,
isNot(OptionalEqual().hashCode),
);
});

test('can force the generation of when/map', () {
ForceUnionMethod2.two()
..map(two: (_) {})
..mapOrNull()
..maybeMap(orElse: () {})
..when(two: () {})
..whenOrNull()
..maybeWhen(orElse: () {});

ForceUnionMethod()
..map((value) => null)
..mapOrNull((value) => null)
..maybeMap((value) => null, orElse: () {})
..when(() => null)
..whenOrNull(() => null)
..maybeWhen(() => null, orElse: () {});
});

test('can disable toJson', () async {
OptionalToJson();
OptionalToJson.fromJson({});

await expectLater(compile(r'''
import 'optional_maybe.dart';

void main() {
OptionalToJson().toJson;
}
'''), throwsCompileError);
});

test('can force toJson', () async {
expect(ForceToJson(42).toJson(), {'a': 42});
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Apply dart formatting to fix pipeline failure.

The pipeline indicates this file needs formatting. Please run dart format . to resolve the formatting issues.

🧰 Tools
🪛 GitHub Actions: Build

[error] 1-1: Dart format check failed. The file was reformatted. Run 'dart format .' to apply formatting changes.

🤖 Prompt for AI Agents
In packages/freezed/test/optional_maybe_test.dart from lines 1 to 137, the file
has formatting issues causing pipeline failures. Run the command `dart format .`
in the project root to automatically format the entire file according to Dart
style guidelines and fix the formatting problems.

Comment on lines +66 to +73
const OptionalMaybeWhen.first()
..mapOrNull()
..maybeMap(orElse: () {})
..map(
first: (_) {},
second: (_) {},
);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Move floating code into a proper test method.

This code is executing outside of any test method. These statements should be moved into a dedicated test method to verify that other pattern matching methods remain available when maybeWhen is disabled.

-    const OptionalMaybeWhen.first()
-      ..mapOrNull()
-      ..maybeMap(orElse: () {})
-      ..map(
-        first: (_) {},
-        second: (_) {},
-      );
+
+  test('other methods remain available when maybeWhen is disabled', () {
+    const OptionalMaybeWhen.first()
+      ..mapOrNull()
+      ..maybeMap(orElse: () {})
+      ..map(
+        first: (_) {},
+        second: (_) {},
+      );
+  });
🤖 Prompt for AI Agents
In packages/freezed/test/optional_maybe_test.dart around lines 66 to 73, the
code invoking mapOrNull, maybeMap, and map on OptionalMaybeWhen.first() is
floating outside any test method. Wrap this code inside a properly named test
method to ensure it runs as part of the test suite and verifies that pattern
matching methods work when maybeWhen is disabled.

Comment on lines +41 to +48
const OptionalMaybeMap.first()
..whenOrNull()
..maybeWhen(orElse: () {})
..when(
first: () {},
second: () {},
);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Move floating code into a proper test method.

This code is executing outside of any test method, which is problematic for test organization and execution. These statements should be moved into a dedicated test method to verify that other pattern matching methods remain available when maybeMap is disabled.

-    const OptionalMaybeMap.first()
-      ..whenOrNull()
-      ..maybeWhen(orElse: () {})
-      ..when(
-        first: () {},
-        second: () {},
-      );
+
+  test('other methods remain available when maybeMap is disabled', () {
+    const OptionalMaybeMap.first()
+      ..whenOrNull()
+      ..maybeWhen(orElse: () {})
+      ..when(
+        first: () {},
+        second: () {},
+      );
+  });
🤖 Prompt for AI Agents
In packages/freezed/test/optional_maybe_test.dart around lines 41 to 48, the
code invoking OptionalMaybeMap methods is outside any test function, which
breaks test structure. Wrap this code inside a properly named test method using
the test() function to ensure it runs as part of the test suite and verifies the
pattern matching methods correctly.

@rrousselGit rrousselGit merged commit 05e2bb4 into master Jul 2, 2025
5 checks passed
@rrousselGit rrousselGit deleted the revert-pattern-removal branch July 2, 2025 20:58
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.

Feature Request: Option to Generate when Method for Sealed Classes in v3+

1 participant