Skip to content

Conversation

@medz
Copy link
Collaborator

@medz medz commented Dec 6, 2025

  1. Remove complex custom Reactive Systems.
  2. Migrate to alien_signals 2.1 (version 2.1 has undergone a refactoring to meet Solidart requirements).
  3. Create more clearly defined public APIs, reducing incorrect naming conventions like hasValue that mark Signal as late.
  4. Ensure API compatibility and that all current tests pass.

resolves #156 ,next PR #167

@codecov
Copy link

codecov bot commented Dec 6, 2025

Codecov Report

❌ Patch coverage is 90.56604% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.91%. Comparing base (c762c82) to head (8290c55).

Files with missing lines Patch % Lines
packages/solidart/lib/src/core/computed.dart 55.55% 4 Missing ⚠️
packages/solidart/lib/src/core/effect.dart 94.11% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##              main     #166      +/-   ##
===========================================
- Coverage   100.00%   98.91%   -1.09%     
===========================================
  Files           18       18              
  Lines          931      831     -100     
===========================================
- Hits           931      822     -109     
- Misses           0        9       +9     
Files with missing lines Coverage Δ
...utter_solidart/lib/src/widgets/signal_builder.dart 100.00% <100.00%> (ø)
packages/solidart/lib/src/core/alien.dart 100.00% <100.00%> (ø)
packages/solidart/lib/src/core/batch.dart 100.00% <100.00%> (ø)
...ackages/solidart/lib/src/core/reactive_system.dart 100.00% <100.00%> (ø)
packages/solidart/lib/src/core/read_signal.dart 95.95% <100.00%> (-4.05%) ⬇️
packages/solidart/lib/src/core/untracked.dart 100.00% <100.00%> (ø)
packages/solidart/lib/src/core/effect.dart 97.56% <94.11%> (-2.44%) ⬇️
packages/solidart/lib/src/core/computed.dart 94.28% <55.55%> (-5.72%) ⬇️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@medz
Copy link
Collaborator Author

medz commented Dec 6, 2025

@nank1ro I'm wondering if _AlienComputed, _AlienEffect, and _AlienSignal are necessary? What was your original reason for adding them? Shouldn't ReactiveNode be implemented directly in Effect? ​​And shouldn't ComputedNode be implemented directly in Computed, and SignalNode be implemented directly in SignalNode?

@nank1ro
Copy link
Owner

nank1ro commented Dec 6, 2025

if _AlienComputed, _AlienEffect, and _AlienSignal are necessary? What was your original reason for adding them? Shouldn't ReactiveNode be implemented directly in Effect? ​​And shouldn't ComputedNode be implemented directly in Computed, and SignalNode be implemented directly in SignalNode?

I don't really remember, maybe for the comparison in update or the disposal?
If it's worth, I would prefer removing anything that is no longer needed

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 6, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR upgrades alien_signals to v2, adds preset/system re-exports, and refactors Solidart to use preset-based nodes and helpers (preset.getActiveSub/setActiveSub, preset.startBatch/endBatch, preset.run/stop) while removing the old ReactiveSystem and migrating types to system.ReactiveNode.

Changes

Cohort / File(s) Summary
Dependency updates
packages/solidart/pubspec.yaml, packages/flutter_solidart/pubspec.yaml
Bump alien_signals to ^2.0.1 and update solidart constraint in flutter_solidart to ^2.8.3.
Re-export modules
packages/solidart/lib/deps/preset.dart, packages/solidart/lib/deps/system.dart
New barrel files that re-export package:alien_signals/preset.dart and package:alien_signals/system.dart.
Core imports
packages/solidart/lib/src/core/core.dart
Replace direct alien_signals import with local preset and system deps imports.
Alien node replacements
packages/solidart/lib/src/core/alien.dart
Replace custom _Alien* node implementations with preset node types (ComputedNode, EffectNode, SignalNode); use preset.stop() for disposal and remove legacy update/update contract code.
ReactiveSystem removal & extensions
packages/solidart/lib/src/core/reactive_system.dart
Remove ReactiveSystem class and instance; update MayDisposeDependencies extension and related methods to use system.ReactiveNode.
Batching & computed evaluation
packages/solidart/lib/src/core/batch.dart, packages/solidart/lib/src/core/computed.dart
Delegate batching to preset.startBatch()/preset.endBatch(); computed evaluation now uses preset-based retrieval and clears pending flags when deps are empty.
Effect refactor & error handling
packages/solidart/lib/src/core/effect.dart
Make Effect extend preset.EffectNode, migrate dependency tracking to system.ReactiveNode, route execution through preset.run()/preset.link() and use a wrapper for error handling and delayed scheduling; add detach/isDetached wiring.
Signal access & subscription handling
packages/solidart/lib/src/core/read_signal.dart, packages/solidart/lib/src/core/signal_base.dart
Replace reactiveSystem signal access with _internalSignal.get()/set(); update subscriber collections to system.ReactiveNode; add analyzer suppression in SignalBase for unused element.
Untracked & widget subscription updates
packages/solidart/lib/src/core/untracked.dart, packages/flutter_solidart/lib/src/widgets/signal_builder.dart
Replace reactiveSystem active-sub management with preset.getActiveSub()/preset.setActiveSub() and set node flags to system.ReactiveFlags.watching where dependencies are established.
Miscellaneous wiring
packages/solidart/lib/src/core/batch.dart, packages/solidart/lib/src/core/computed.dart
Minor structural adjustments to ensure pending-flag clearing, type updates from alien.ReactiveNode to system.ReactiveNode, and removal of legacy helpers.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Areas needing careful review:
    • packages/solidart/lib/src/core/effect.dart — new error wrapper, delayed scheduling, detach semantics.
    • packages/solidart/lib/src/core/reactive_system.dart — removal of ReactiveSystem and migration implications.
    • packages/solidart/lib/src/core/read_signal.dart and alien.dart — behavioral equivalence of signal/computed/effect after switching to preset nodes.
    • Widget integration: packages/flutter_solidart/lib/src/widgets/signal_builder.dart — ensure active-subscription restore logic is correct.

Possibly related PRs

  • refactor signal builder #143 — Modifies the same SignalBuilder implementation and active-subscription wiring; likely overlaps with subscription changes here.
  • Feat/solidart hooks #137 — Also touches SignalBuilder and its error messaging; related to the same widget-level changes.

Poem

🐰 I nibbled code and found a nest,

preset paths now do their best,
Old system gone, the nodes unite,
Signals dance in v2 light,
Hop, hop — the updates feel just right. ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Changes comprehensively implement the upgrade to alien_signals 2.0 [#156], switching from custom ReactiveSystem to preset-based nodes and updating dependencies accordingly.
Out of Scope Changes check ✅ Passed All changes are directly aligned with upgrading to alien_signals 2.0; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title accurately describes the main objective: replacing a custom reactive system with alien_signals preset and simplifying the codebase from a complex implementation to under 1000 lines.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@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 (2)
packages/solidart/lib/src/core/effect.dart (1)

196-216: Consider whether the catch-rethrow block is reachable.

The safeCallback wrapper already handles exceptions: it either calls _onError and returns, or rethrows. If _onError is set, no exception escapes; if not, it rethrows from within the callback. This means the catch block at lines 207-210 is only reachable when _onError is null. While this works correctly, the comment at line 208-209 could be clarified to reflect this nuance.

     try {
       preset.run(_internalEffect);
     } catch (_) {
-      // The callback handles the error reporting, just rethrow to preserve
-      // the behavior when no handler is provided.
+      // Only reached when _onError is null; safeCallback rethrows in that case.
       rethrow;
     } finally {
packages/solidart/lib/src/core/alien.dart (1)

26-35: Consider adding a dispose() method for consistency.

Unlike _AlienComputed and _AlienEffect, _AlienSignal lacks a dispose() method. While signals may not require explicit stopping in alien_signals 2.0 (they're cleaned up when subscribers are cleared), adding a no-op or minimal dispose() could improve consistency and aid future maintenance.

Regarding the PR discussion about removing these wrapper classes: they serve a purpose by maintaining the association between preset nodes and solidart's Signal/Computed/Effect instances, enabling solidart-specific features like autoDispose and trackInDevTools. Keeping them is justified.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c762c82 and 0b3795e.

📒 Files selected for processing (13)
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart (3 hunks)
  • packages/flutter_solidart/pubspec.yaml (1 hunks)
  • packages/solidart/lib/deps/preset.dart (1 hunks)
  • packages/solidart/lib/deps/system.dart (1 hunks)
  • packages/solidart/lib/src/core/alien.dart (1 hunks)
  • packages/solidart/lib/src/core/batch.dart (1 hunks)
  • packages/solidart/lib/src/core/computed.dart (2 hunks)
  • packages/solidart/lib/src/core/core.dart (1 hunks)
  • packages/solidart/lib/src/core/effect.dart (3 hunks)
  • packages/solidart/lib/src/core/reactive_system.dart (1 hunks)
  • packages/solidart/lib/src/core/read_signal.dart (6 hunks)
  • packages/solidart/lib/src/core/untracked.dart (1 hunks)
  • packages/solidart/pubspec.yaml (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/{solidart,flutter_solidart}/lib/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/{solidart,flutter_solidart}/lib/**/*.dart: Use Signals for state, Effects for side effects, and Computed for derived values in library code
Use untracked() for reads that should not trigger reactivity
Ensure proper memory management: Signals auto-dispose in Flutter contexts; manually dispose in pure Dart code

Files:

  • packages/solidart/lib/deps/preset.dart
  • packages/solidart/lib/src/core/untracked.dart
  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/batch.dart
  • packages/solidart/lib/deps/system.dart
  • packages/solidart/lib/src/core/computed.dart
  • packages/solidart/lib/src/core/read_signal.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
  • packages/solidart/lib/src/core/reactive_system.dart
  • packages/solidart/lib/src/core/effect.dart
  • packages/solidart/lib/src/core/alien.dart
packages/flutter_solidart/{lib,test}/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

For Flutter Solidart changes, ensure widget tests cover SignalBuilder, Provider, and Show behaviors

Files:

  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Use Signals for state, Effects for side effects, and Computed for derived values in library code
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/solidart/test/solidart_test.dart : After Signal changes, always run `packages/solidart/test/solidart_test.dart`
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/solidart/test/solidart_test.dart : After Signal changes, always run `packages/solidart/test/solidart_test.dart`

Applied to files:

  • packages/solidart/lib/deps/preset.dart
  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/deps/system.dart
  • packages/solidart/lib/src/core/computed.dart
  • packages/solidart/lib/src/core/read_signal.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
  • packages/flutter_solidart/pubspec.yaml
  • packages/solidart/pubspec.yaml
  • packages/solidart/lib/src/core/alien.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/test/flutter_solidart_test.dart : After Flutter integration changes, always run `packages/flutter_solidart/test/flutter_solidart_test.dart`

Applied to files:

  • packages/solidart/lib/deps/preset.dart
  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/deps/system.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
  • packages/flutter_solidart/pubspec.yaml
  • packages/solidart/pubspec.yaml
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/{lib,test}/**/*.dart : For Flutter Solidart changes, ensure widget tests cover `SignalBuilder`, `Provider`, and `Show` behaviors

Applied to files:

  • packages/solidart/lib/deps/preset.dart
  • packages/solidart/lib/src/core/untracked.dart
  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/deps/system.dart
  • packages/solidart/lib/src/core/computed.dart
  • packages/solidart/lib/src/core/read_signal.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
  • packages/flutter_solidart/pubspec.yaml
  • packages/solidart/pubspec.yaml
  • packages/solidart/lib/src/core/effect.dart
  • packages/solidart/lib/src/core/alien.dart
📚 Learning: 2025-10-04T15:38:49.286Z
Learnt from: medz
Repo: nank1ro/solidart PR: 149
File: packages/solidart/lib/src/effect.dart:1-0
Timestamp: 2025-10-04T15:38:49.286Z
Learning: In Dart, multiple import statements can use the same prefix with the `as` keyword. For example, `import 'package:a/a.dart' as foo;` and `import 'package:b/b.dart' as foo;` is valid syntax. The symbols from both packages will be accessible under the single `foo` namespace.

Applied to files:

  • packages/solidart/lib/deps/preset.dart
  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/deps/system.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Use Signals for state, Effects for side effects, and Computed for derived values in library code

Applied to files:

  • packages/solidart/lib/deps/preset.dart
  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/deps/system.dart
  • packages/solidart/lib/src/core/computed.dart
  • packages/solidart/lib/src/core/read_signal.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
  • packages/flutter_solidart/pubspec.yaml
  • packages/solidart/pubspec.yaml
  • packages/solidart/lib/src/core/effect.dart
  • packages/solidart/lib/src/core/alien.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Ensure proper memory management: Signals auto-dispose in Flutter contexts; manually dispose in pure Dart code

Applied to files:

  • packages/solidart/lib/deps/preset.dart
  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/deps/system.dart
  • packages/solidart/lib/src/core/read_signal.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
  • packages/flutter_solidart/pubspec.yaml
  • packages/solidart/lib/src/core/reactive_system.dart
  • packages/solidart/lib/src/core/alien.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Use `untracked()` for reads that should not trigger reactivity

Applied to files:

  • packages/solidart/lib/src/core/untracked.dart
  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/computed.dart
  • packages/solidart/lib/src/core/read_signal.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
  • packages/flutter_solidart/pubspec.yaml
  • packages/solidart/lib/src/core/reactive_system.dart
  • packages/solidart/lib/src/core/alien.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/solidart/test/**/*.dart : Write unit tests covering Signal operations and state transitions

Applied to files:

  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/deps/system.dart
  • packages/solidart/lib/src/core/read_signal.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
📚 Learning: 2025-10-08T11:10:13.808Z
Learnt from: nank1ro
Repo: nank1ro/solidart PR: 151
File: packages/solidart_hooks/CHANGELOG.md:12-16
Timestamp: 2025-10-08T11:10:13.808Z
Learning: In solidart/flutter_solidart, SignalBuilder supports automatic signal tracking where signals are detected when accessed inside the builder. The builder signature for automatic tracking is `(BuildContext, Widget? child)`, not requiring an explicit signal parameter or value parameter. Example: `SignalBuilder(builder: (context, child) => Text('${counter.value}'))`.

Applied to files:

  • packages/solidart/lib/src/core/read_signal.dart
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
📚 Learning: 2025-10-07T14:44:49.132Z
Learnt from: nank1ro
Repo: nank1ro/solidart PR: 150
File: packages/flutter_solidart/lib/src/core/value_notifier_signal_mixin.dart:14-20
Timestamp: 2025-10-07T14:44:49.132Z
Learning: In `packages/flutter_solidart/lib/src/core/value_notifier_signal_mixin.dart`, the `ValueNotifierSignalMixin` intentionally does not support duplicate listener registrations. The `putIfAbsent` pattern is a deliberate design decision by the maintainer.

Applied to files:

  • packages/solidart/lib/src/core/read_signal.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Install Flutter stable channel and Dart SDK before development

Applied to files:

  • packages/flutter_solidart/pubspec.yaml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (21)
packages/solidart/pubspec.yaml (1)

15-19: alien_signals 2.0.1 constraint looks consistent with PR goals

The dependency bump to alien_signals: ^2.0.1 aligns with the migration to the preset/system-based API; no issues from this manifest change alone.

packages/flutter_solidart/pubspec.yaml (1)

16-22: solidart version alignment is reasonable

Updating solidart to ^2.8.3 keeps flutter_solidart in sync with the core package’s new reactive implementation; no manifest-level concerns here.

packages/solidart/lib/deps/system.dart (1)

1-1: System barrel export is straightforward

Re-exporting package:alien_signals/system.dart via this deps file is a clean way to centralize system imports; no issues spotted.

packages/solidart/lib/deps/preset.dart (1)

1-1: Preset barrel export matches new architecture

Exporting package:alien_signals/preset.dart here is consistent with the new preset-based layering and simplifies imports across the core modules.

packages/solidart/lib/src/core/batch.dart (1)

23-29: Batch now delegates to preset batching correctly

Switching from the old reactive system to preset.startBatch() / preset.endBatch() keeps the batching semantics intact (thanks to the existing try/finally) and aligns with the new preset-based API.

packages/solidart/lib/src/core/untracked.dart (1)

7-13: untracked correctly switches to preset-based active subscription

Replacing the old reactiveSystem calls with preset.setActiveSub preserves the save/restore pattern for the active subscription and keeps untracked semantics intact.

packages/solidart/lib/src/core/computed.dart (2)

127-127: _deps type updated to system.ReactiveNode is consistent

Changing _deps to Set<system.ReactiveNode> aligns it with the new system-based node types and keeps the disposal loop compatible with both _AlienSignal and _AlienComputed instances via type checks.


149-167: Pending flag handling for dependency-less computeds is correct

The logic explicitly clears system.ReactiveFlags.pending when deps == null before calling _internalComputed.get(), preventing a stuck pending state. This is consistent with the codebase pattern and preserves auto-dispose semantics and returned values.

packages/solidart/lib/src/core/core.dart (1)

7-8: Core now depends on preset/system barrels, which is appropriate

Importing solidart/deps/preset.dart as preset and solidart/deps/system.dart as system cleanly abstracts the underlying alien_signals modules and matches the rest of the refactor. All internal references, including the alien.dart part file, have been properly migrated to use the new prefixes.

packages/flutter_solidart/lib/src/widgets/signal_builder.dart (2)

3-4: LGTM!

The new imports for preset and system modules align with the alien_signals 2.0 preset-based API migration.


86-108: Correct active subscription management pattern.

The save/restore pattern using preset.getActiveSub() and preset.setActiveSub() properly manages the reactive context. Setting node.flags = system.ReactiveFlags.watching after establishing dependencies is appropriate for the new preset-based system.

packages/solidart/lib/src/core/effect.dart (2)

151-170: LGTM! Clean error handling encapsulation.

The safeCallback wrapper properly encapsulates error handling, routing exceptions to _onError when provided or rethrowing otherwise. The initialization with combined flags (watching | dirty) is appropriate for a newly created effect.


186-190: Type migration to system.ReactiveNode is consistent.

The _deps set, subscriber getter, and setDependencies parameter are all correctly updated to use system.ReactiveNode, maintaining type consistency with the new preset-based architecture.

Also applies to: 220-224

packages/solidart/lib/src/core/read_signal.dart (4)

119-123: LGTM! Direct internal signal access simplifies the reactive flow.

Replacing _reportObserved() and reactiveSystem.getSignalValue() with direct _internalSignal.get() calls is cleaner and aligns with the preset-based architecture. The subscription tracking in the auto-dispose path is correctly preserved.

Also applies to: 133-150


173-177: LGTM!

Direct use of _internalSignal.set(Some(newValue)) properly updates the signal value through the preset-based system.


262-262: Type consistency maintained.

The _subs set correctly uses system.ReactiveNode to match the updated type system.


336-342: The dirty flag check logic is correct.

The condition (flags & dirty) == none properly verifies that the dirty bit is not set: when unset, shouldUpdate() returns false (no update needed); when set, it proceeds to call _internalSignal.update(). This aligns with alien_signals 2.0 behavior, where the Dirty flag marks a node whose cached value is out-of-date and requires recomputation. The bitwise AND pattern matches the standard usage in the codebase (e.g., computed.dart's pending flag check).

packages/solidart/lib/src/core/reactive_system.dart (2)

6-27: LGTM! Type migration is consistent.

The MayDisposeDependencies extension correctly uses system.ReactiveNode throughout. The disposal logic properly traverses dependencies and triggers _mayDispose() on the appropriate parent instances.


29-43: LGTM!

ReactiveName utility class is correctly retained for generating unique identifiers.

packages/solidart/lib/src/core/alien.dart (2)

3-10: LGTM! Clean migration to preset.ComputedNode.

The _AlienComputed class correctly extends preset.ComputedNode<T> with the appropriate getter signature and initialization flags. Disposal via preset.stop(this) aligns with alien_signals 2.0.


12-24: LGTM! Effect node migration is correct.

The _AlienEffect class properly extends preset.EffectNode with configurable flags and the detach behavior. Using super.fn and super.flags is clean initialization.

- Remove _AlienEffect wrapper class
- Simplify delayed callback logic
- Improve dependency cleanup in ReadableSignal
- Reorder imports consistently
Copy link
Contributor

@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 (3)
packages/solidart/lib/src/core/alien.dart (1)

12-21: Prefer SignalBase<T> over SignalBase<dynamic> for type safety

Given _AlienSignal<T> is generic and _AlienComputed<T> keeps a Computed<T> parent, you can likely tighten the parent type here to preserve signal typings:

-  final SignalBase<dynamic> parent;
+  final SignalBase<T> parent;

This keeps the bridge strongly typed end‑to‑end and avoids unnecessary dynamic usage. Also ensure that whichever owner type wraps _AlienSignal is responsible for disposing the underlying node to satisfy manual-dispose expectations in pure Dart contexts.

As per coding guidelines, signals in pure Dart code should be explicitly disposed to avoid leaks.

packages/solidart/lib/src/core/effect.dart (2)

171-187: Consider adding a brief comment explaining the linking condition.

The condition on lines 173-176 is complex and handles multiple detachment scenarios. A brief inline comment would aid future maintainability.

   void run() {
     final currentSub = preset.getActiveSub();
+    // Link to parent subscriber unless globally detached, no parent exists,
+    // or either this effect or the parent effect is explicitly detached.
     if (!SolidartConfig.detachEffects &&
         currentSub != null &&
         (currentSub is! preset.EffectNode ||
             !(detach || (currentSub is Effect && currentSub.detach)))) {
       preset.link(this, currentSub, preset.cycle);
     }

216-225: Redundant _disposed check inside _mayDispose.

Line 220 checks _disposed again after line 217 already returned early if disposed. This is harmless but redundant.

   @override
   void _mayDispose() {
     if (_disposed) return;
 
     if (SolidartConfig.autoDispose) {
-      if (!autoDispose || _disposed) return;
+      if (!autoDispose) return;
       if (subscriber.deps?.dep == null) {
         dispose();
       }
     }
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b3795e and 1de6865.

📒 Files selected for processing (9)
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart (3 hunks)
  • packages/solidart/lib/src/core/alien.dart (1 hunks)
  • packages/solidart/lib/src/core/computed.dart (4 hunks)
  • packages/solidart/lib/src/core/core.dart (1 hunks)
  • packages/solidart/lib/src/core/effect.dart (5 hunks)
  • packages/solidart/lib/src/core/reactive_system.dart (1 hunks)
  • packages/solidart/lib/src/core/read_signal.dart (6 hunks)
  • packages/solidart/lib/src/core/signal_base.dart (1 hunks)
  • packages/solidart/lib/src/core/untracked.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/flutter_solidart/lib/src/widgets/signal_builder.dart
  • packages/solidart/lib/src/core/computed.dart
🧰 Additional context used
📓 Path-based instructions (1)
packages/{solidart,flutter_solidart}/lib/**/*.dart

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/{solidart,flutter_solidart}/lib/**/*.dart: Use Signals for state, Effects for side effects, and Computed for derived values in library code
Use untracked() for reads that should not trigger reactivity
Ensure proper memory management: Signals auto-dispose in Flutter contexts; manually dispose in pure Dart code

Files:

  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/untracked.dart
  • packages/solidart/lib/src/core/effect.dart
  • packages/solidart/lib/src/core/alien.dart
  • packages/solidart/lib/src/core/reactive_system.dart
  • packages/solidart/lib/src/core/signal_base.dart
  • packages/solidart/lib/src/core/read_signal.dart
🧠 Learnings (9)
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/solidart/test/solidart_test.dart : After Signal changes, always run `packages/solidart/test/solidart_test.dart`

Applied to files:

  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/alien.dart
  • packages/solidart/lib/src/core/signal_base.dart
  • packages/solidart/lib/src/core/read_signal.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/{lib,test}/**/*.dart : For Flutter Solidart changes, ensure widget tests cover `SignalBuilder`, `Provider`, and `Show` behaviors

Applied to files:

  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/untracked.dart
  • packages/solidart/lib/src/core/alien.dart
  • packages/solidart/lib/src/core/signal_base.dart
  • packages/solidart/lib/src/core/read_signal.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Use Signals for state, Effects for side effects, and Computed for derived values in library code

Applied to files:

  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/effect.dart
  • packages/solidart/lib/src/core/alien.dart
  • packages/solidart/lib/src/core/signal_base.dart
  • packages/solidart/lib/src/core/read_signal.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/test/flutter_solidart_test.dart : After Flutter integration changes, always run `packages/flutter_solidart/test/flutter_solidart_test.dart`

Applied to files:

  • packages/solidart/lib/src/core/core.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Ensure proper memory management: Signals auto-dispose in Flutter contexts; manually dispose in pure Dart code

Applied to files:

  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/alien.dart
  • packages/solidart/lib/src/core/reactive_system.dart
  • packages/solidart/lib/src/core/signal_base.dart
  • packages/solidart/lib/src/core/read_signal.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Use `untracked()` for reads that should not trigger reactivity

Applied to files:

  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/untracked.dart
  • packages/solidart/lib/src/core/reactive_system.dart
  • packages/solidart/lib/src/core/read_signal.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/solidart/test/**/*.dart : Write unit tests covering Signal operations and state transitions

Applied to files:

  • packages/solidart/lib/src/core/core.dart
  • packages/solidart/lib/src/core/signal_base.dart
  • packages/solidart/lib/src/core/read_signal.dart
📚 Learning: 2025-10-08T11:10:13.808Z
Learnt from: nank1ro
Repo: nank1ro/solidart PR: 151
File: packages/solidart_hooks/CHANGELOG.md:12-16
Timestamp: 2025-10-08T11:10:13.808Z
Learning: In solidart/flutter_solidart, SignalBuilder supports automatic signal tracking where signals are detected when accessed inside the builder. The builder signature for automatic tracking is `(BuildContext, Widget? child)`, not requiring an explicit signal parameter or value parameter. Example: `SignalBuilder(builder: (context, child) => Text('${counter.value}'))`.

Applied to files:

  • packages/solidart/lib/src/core/read_signal.dart
📚 Learning: 2025-10-07T14:44:49.132Z
Learnt from: nank1ro
Repo: nank1ro/solidart PR: 150
File: packages/flutter_solidart/lib/src/core/value_notifier_signal_mixin.dart:14-20
Timestamp: 2025-10-07T14:44:49.132Z
Learning: In `packages/flutter_solidart/lib/src/core/value_notifier_signal_mixin.dart`, the `ValueNotifierSignalMixin` intentionally does not support duplicate listener registrations. The `putIfAbsent` pattern is a deliberate design decision by the maintainer.

Applied to files:

  • packages/solidart/lib/src/core/read_signal.dart
🔇 Additional comments (13)
packages/solidart/lib/src/core/signal_base.dart (1)

108-109: Suppressing unused_element on _compare is reasonable here

Since _compare is a private abstract member intended for subclasses to implement, the analyzer’s unused warning is just noise, so this ignore is fine. If you ever want to drop the suppression, a longer‑term alternative would be to make it non‑private (or adjust lint rules) so the declaration isn’t flagged in abstract bases.

Also, because this touches the core SignalBase, ensure packages/solidart/test/solidart_test.dart still passes after this change. Based on learnings, …

packages/solidart/lib/src/core/alien.dart (1)

3-10: Computed node migration to preset.ComputedNode looks correct

Constructor wiring (passing flags: system.ReactiveFlags.none and the getter) and delegating teardown via dispose() => preset.stop(this) is consistent with offloading update logic to the preset; no issues from this snippet. To be safe, verify computed disposal behavior by running the existing solidart tests after the alien_signals 2.0 bump.

Based on learnings, please ensure packages/solidart/test/solidart_test.dart is run after these reactive changes.

packages/solidart/lib/src/core/core.dart (1)

9-10: LGTM!

The import migration from alien_signals.dart to the new preset.dart and system.dart dependency shims aligns with the PR objective of adopting the alien_signals 2.0 preset-based architecture. The aliased imports provide clear namespacing for the different layers.

packages/solidart/lib/src/core/untracked.dart (1)

7-13: LGTM!

The migration to preset.setActiveSub() correctly maintains the untracked semantics. The pattern saves the previous subscriber, clears the active subscriber to prevent tracking, executes the callback, and reliably restores the previous state in the finally block. This aligns with the coding guideline to use untracked() for reads that should not trigger reactivity.

packages/solidart/lib/src/core/reactive_system.dart (1)

6-27: LGTM!

The extension migration to system.ReactiveNode is consistent with the preset-based architecture. The disposal logic correctly handles both _AlienSignal and _AlienComputed types by calling their parent's _mayDispose() method.

Note: Per the PR discussion, there's a question about whether the _Alien* wrapper classes are still necessary. They're currently used here for type-based dispatch in disposal—if these wrappers are removed in a follow-up, this switch logic would need to be updated accordingly.

packages/solidart/lib/src/core/read_signal.dart (5)

119-123: LGTM!

The hasValue getter now properly triggers tracking by calling _internalSignal.get() before returning the cached _hasValue flag. This ensures reactive subscriptions are established when checking if a signal has a value.


133-150: LGTM!

The _value getter correctly uses _internalSignal.get().unwrap() for both disposed and active paths, with the disposed path wrapped in untracked() to prevent subscription registration. The subscription tracking logic for autoDispose properly rebuilds _subs from the internal signal's subscriber list.


173-177: LGTM!

The setter correctly updates both the internal tracking state (_untrackedPreviousValue, _untrackedValue) and propagates the change through _internalSignal.set(Some(newValue)).


337-348: LGTM!

The _reportChanged method correctly forces a change notification by re-setting the current value. The shouldUpdate method properly short-circuits when the internal signal is not dirty by checking (flags & dirty) == none before calling update().


275-306: The extension method call is valid and requires no changes.

The code at line 289 calls sub.mayDisposeDependencies() on a preset.EffectNode. Since this code already exists in the production codebase without compilation errors, preset.EffectNode necessarily extends system.ReactiveNode, confirming that the MayDisposeDependencies extension method is available and applicable.

packages/solidart/lib/src/core/effect.dart (3)

67-67: LGTM!

The class now extends preset.EffectNode directly, which aligns with the PR objective to use the preset-based architecture and potentially eliminate redundant wrapper classes.


96-122: LGTM!

The delayed callback implementation correctly:

  1. Cancels any pending timer before scheduling a new one
  2. Checks effect.disposed before executing the callback
  3. Cancels the timer if the effect is disposed
  4. Routes through Effect._internal consistently for both immediate and delayed callbacks

131-145: LGTM!

The error handling wrapper in the super constructor correctly:

  1. Wraps the callback in try-catch
  2. Converts exceptions to SolidartCaughtException when onError is provided
  3. Rethrows when no error handler is available
  4. Initializes with ReactiveFlags.watching | ReactiveFlags.dirty for proper tracking

@medz
Copy link
Collaborator Author

medz commented Dec 7, 2025

@nank1ro Both Signal and Computed implement SignalBase. Do you have any suggestions on this?

@medz medz marked this pull request as draft December 7, 2025 18:41
@nank1ro
Copy link
Owner

nank1ro commented Dec 7, 2025

@nank1ro Both Signal and Computed implement SignalBase. Do you have any suggestions on this?

A want to remove it completely if possible and rely on ReadSignal as the base any signal extends.
I even have ReadableSignal which was I mistake I made

@medz
Copy link
Collaborator Author

medz commented Dec 7, 2025

@nank1ro Both Signal and Computed implement SignalBase. Do you have any suggestions on this?

A want to remove it completely if possible and rely on ReadSignal as the base any signal extends. I even have ReadableSignal which was I mistake I made

Perhaps I should reorganize Solidart's base classes (and follow the principle that everything should be public, as you'd expect); I always feel it's a bit disorganized whenever I make changes 😂.

--- Of course, this is on the premise of not changing the current public API.


Besides SignalBase and ReadSignal, I think modifying ReadSignal to the ReadonlySignal interface is a good choice. It standardizes the reading behavior and API of signals (so that it is compatible with both signals and computed signals).

@nank1ro
Copy link
Owner

nank1ro commented Dec 7, 2025

Not sure if I like "ReadonlySignal" as a name, it's clear but I think even "ReadSignal" is clear and even shorter.
For the rest I agree it should be the base.

The purpose of it is that it has no public value setter, and other signals can be casted to ReadSignal to prevent altering the value.

@nank1ro
Copy link
Owner

nank1ro commented Dec 7, 2025

Of course, this is on the premise of not changing the current public API.

Thanks I really appreciate it! 💙☺️
The only thing I think I'll change is autodispose, it's a foot gun for many new users and I'll probably disable it by default and let users to opt-in.
In this way, they can opt-in only after knowing how it works.
But at the end it's just a different default value in SolidartConfig

@medz
Copy link
Collaborator Author

medz commented Dec 8, 2025

Of course, this is on the premise of not changing the current public API.

Thanks I really appreciate it! 💙☺️ The only thing I think I'll change is autodispose, it's a foot gun for many new users and I'll probably disable it by default and let users to opt-in. In this way, they can opt-in only after knowing how it works. But at the end it's just a different default value in SolidartConfig

If the public Signal API remains unchanged, I believe that such modifications would warrant a release of version 3.0, which seems to contradict the original intention of only supporting certain aspects.

The reasons are as follows:

  1. The SignalBase base class has been removed.
  2. The ReadonlySignal or ReadSignal interface has been changed.
  3. The ReadableSignal base class has been removed.
  4. Signal/Computed/Effect exposes the raw ReactiveNode property.

Of course, we could also force a release of version 2.9.0, which currently seems safer because there are no downstream scenarios using SignalBase in Solidart.

@nank1ro
Copy link
Owner

nank1ro commented Dec 8, 2025

@medz I agree, there are some important breaking changes like removing SignalBase and updating the default SolidartConfig.autoDispose setting so a new major (3.0) is required

@medz medz changed the title Replace custom reactive system with alien_signals preset [WIP]: Remove complex custom Reactive Systems and standardize the public API to make it easy to maintain with clear responsibilities and logic. (Goal: Single-file pure code under 1000 lines) Dec 8, 2025
@medz medz changed the title [WIP]: Remove complex custom Reactive Systems and standardize the public API to make it easy to maintain with clear responsibilities and logic. (Goal: Single-file pure code under 1000 lines) [WIP] - 3.0: Remove complex custom Reactive Systems and standardize the public API to make it easy to maintain with clear responsibilities and logic. (Goal: Single-file pure code under 1000 lines) Dec 8, 2025
medz added 7 commits December 8, 2025 18:21
Introduce a `Disposable` interface and `DisponsableMixin` (note: typo in
name) to provide a common disposal mechanism for `Signal`, `Computed`,
and `Effect`. This allows registering cleanup callbacks and ensures
proper resource disposal.
- Add SolidartConfig with static autoDispose flag
- Make ReadonlySignal implement Configuration
- Add name and autoDispose parameters to Signal, LazySignal, and
  Computed
- Export Configuration and Disposable from the main library
The Effect class now implements Configuration and accepts optional name
and autoDispose parameters, defaulting autoDispose to the global
SolidartConfig.autoDispose value when not provided.
Introduce an `Identifier` class that provides a unique integer value
alongside an optional name. This replaces the simple `name` property on
signals, computed values, and effects to ensure each reactive primitive
has a distinct identifier for debugging and tracking.
@medz
Copy link
Collaborator Author

medz commented Dec 8, 2025

@nank1ro I'm gradually recreating Solidart's functionality step-by-step from primitives in a single v3.dart file. Currently, the Reactive primitives and auto-dispose functionality (test files added) are complete.

I'd appreciate feedback. Do you have any other comments or suggestions regarding the API design (based on the current functionality of v3.dart)?

Please review this. Thank you! 🙏

@medz
Copy link
Collaborator Author

medz commented Dec 8, 2025

Next PR 👉 #167

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.

Upgrade alien_signals to version 2.0

2 participants