Skip to content

Improved the readability of the all operator as well as added memory …#98

Merged
alexanderharding merged 3 commits into
mainfrom
all-improvements
May 19, 2026
Merged

Improved the readability of the all operator as well as added memory …#98
alexanderharding merged 3 commits into
mainfrom
all-improvements

Conversation

@alexanderharding

@alexanderharding alexanderharding commented May 19, 2026

Copy link
Copy Markdown
Owner

…optimizations.

Summary by CodeRabbit

  • Chores

    • Package version bumped to 0.20.0
  • Tests

    • Added coverage for empty observable sets, empty/custom iterables, and correct emission vs. return behavior
  • Refactor

    • Rewrote iterable handling for the aggregate operator to improve iteration efficiency, emission correctness, and overall reliability

Review Change Stack

@alexanderharding alexanderharding self-assigned this May 19, 2026
@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Reimplements all(...) to iterate a bounded iterable directly, track per-inner first-value and active subscriptions, buffer and snapshot values with Object.is checks, handle empty and aborted cases, add tests for undefined aggregation and empty inputs, and bump package version to 0.20.0.

Changes

Core all(...) Operator Refactor

Layer / File(s) Summary
Type definitions and module setup
all/mod.ts
Introduced BoundedIterable type and reduced imports to the module's used symbols.
Core all(...) implementation refactor
all/mod.ts
Replaced the operator-pipeline with a direct new Observable looping a BoundedIterable; tracks receivedFirstValueCount and activeInnerSubscriptions, updates a buffered array and cached frozen snapshot only when values change (via Object.is), uses per-inner finalize cleanup, short-circuits if an inner completes before its first value, and stops iteration when the subscriber is aborted.
Supporting utility functions
all/mod.ts
Added bound() to normalize arrays, sets, and custom iterables into a BoundedIterable (stable iterator + size), and simplified the isIterable type guard.
Test coverage and package version
all/mod.test.ts, all/deno.json
Updated test imports to include the Observable type; added tests asserting aggregation of multiple of(undefined) inputs, that all(new Set<Observable>()) returns empty, and that an empty custom iterable materializes to only a return notification; bumped the Deno manifest version to 0.20.0.

Sequence Diagram(s)

sequenceDiagram
  participant Subscriber
  participant all_op as all(...)
  participant Inner as InnerObservable
  participant Observer
  Subscriber->>all_op: subscribe(iterable of InnerObservable)
  all_op->>Inner: subscribe each inner from BoundedIterable
  Inner->>all_op: emit first value / subsequent next
  all_op->>all_op: increment receivedFirstValueCount, update buffer snapshot (Object.is check)
  all_op->>Observer: emit frozen snapshot when all first values received
  Inner->>all_op: complete -> finalize -> decrement activeInnerSubscriptions
  all_op->>Observer: complete when all inner completed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I bounded the iterables, one, two, three,
I tracked first values till they came to be,
Snapshots frozen where changes were few,
Empties returned, tests ran true,
A tiny hop — bumped to zero-point-two-oh.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title references improving readability and adding memory optimizations, which align with the main changes in all/mod.ts (rewritten implementation) and the version bump indicating a release.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch all-improvements

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@all/mod.test.ts`:
- Line 2: The import of Observable in all/mod.test.ts is treated as a runtime
value but is only used in type positions (Observable at lines referencing its
type and Observer), so change the import to a type-only import: replace the
current import of Observable (and Observer if it’s only used as a type) with an
"import type" form to satisfy Deno's verbatim-module-syntax; locate the import
statement that currently reads "import { Observable, Observer } from
'`@observable/core`'" and update it to import type for the symbols used only as
types while leaving any runtime imports untouched.

In `@all/mod.ts`:
- Around line 203-208: The current Object.is(buffer[indexSnapshot], value) check
skips storing the first undefined because sparse buffer slots read as undefined;
instead add per-index receipt tracking (e.g., a boolean array like hasValue) and
use that to decide updates: only treat values as "unchanged" when
hasValue[indexSnapshot] is true and Object.is(buffer[indexSnapshot], value) is
true; otherwise assign buffer[indexSnapshot] = value, set
hasValue[indexSnapshot] = true, and reset snapshot = undefined. Ensure hasValue
is initialized alongside buffer and updated wherever values are written.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ceb265bc-e442-4d09-922a-5f821c539f63

📥 Commits

Reviewing files that changed from the base of the PR and between 0861d81 and 1a1d3f4.

📒 Files selected for processing (3)
  • all/deno.json
  • all/mod.test.ts
  • all/mod.ts

Comment thread all/mod.test.ts Outdated
Comment thread all/mod.ts Outdated
@alexanderharding

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@all/mod.ts`:
- Around line 233-236: The bound() function must snapshot mutable inputs and
return a frozen BoundedIterable: instead of returning the original Set or an
unfrozen literal, create an immutable snapshot array (use value instanceof Set ?
Array.from(value) : Array.isArray(value) ? value.slice() : Array.from(value)),
build the iterable whose [Symbol.iterator]() iterates over that snapshot and
whose size is snapshot.length, then wrap the returned object with
Object.freeze(...) before returning; update references to the bound function and
BoundedIterable to use this frozen snapshot so live iterator mutations cannot
desynchronize counts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d9652af9-794a-4b3a-bd4f-3ea32d9dfc58

📥 Commits

Reviewing files that changed from the base of the PR and between a9de15d and 2f92dc5.

📒 Files selected for processing (2)
  • all/mod.test.ts
  • all/mod.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • all/mod.test.ts

Comment thread all/mod.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
all/mod.test.ts (1)

129-129: ⚡ Quick win

Consider explicit type parameter for consistency.

Line 129 uses Set<Observable>() while line 138 uses Observable<unknown>. For consistency and explicitness, consider using the full type annotation.

♻️ Suggested change for consistency
-  const observable = all(new Set<Observable>());
+  const observable = all(new Set<Observable<unknown>>());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@all/mod.test.ts` at line 129, Change the ambiguous generic usage to an
explicit unknown type for consistency: update the call site using all and the
Set instantiation so they reference Observable<unknown> (e.g., construct new
Set<Observable<unknown>>() and/or call all<unknown>(...) ), ensuring both the
Set and the all invocation use the Observable<unknown> type instead of bare
Observable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@all/mod.test.ts`:
- Line 129: Change the ambiguous generic usage to an explicit unknown type for
consistency: update the call site using all and the Set instantiation so they
reference Observable<unknown> (e.g., construct new Set<Observable<unknown>>()
and/or call all<unknown>(...) ), ensuring both the Set and the all invocation
use the Observable<unknown> type instead of bare Observable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7503fe3c-3db3-4b7e-9f1c-48a6360c11e9

📥 Commits

Reviewing files that changed from the base of the PR and between 0861d81 and 2f92dc5.

📒 Files selected for processing (3)
  • all/deno.json
  • all/mod.test.ts
  • all/mod.ts

@alexanderharding alexanderharding merged commit da4cd2a into main May 19, 2026
2 checks passed
@alexanderharding alexanderharding deleted the all-improvements branch May 19, 2026 05:33
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.

1 participant