Skip to content

Fix Promise.all visualization for .map() patterns#247

Merged
zhubzy merged 1 commit intobubblelabai:mainfrom
depak7:fix/promise-all-map-visualization
Dec 27, 2025
Merged

Fix Promise.all visualization for .map() patterns#247
zhubzy merged 1 commit intobubblelabai:mainfrom
depak7:fix/promise-all-map-visualization

Conversation

@depak7
Copy link
Contributor

@depak7 depak7 commented Dec 25, 2025

Summary

All Promise.all patterns now correctly visualize multiple parallel nodes

Related Issues

#241

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactor
  • Other (please describe):

Checklist

  • My code follows the code style of this project
  • I have added appropriate tests for my changes
  • I have run pnpm check and all tests pass
  • I have tested my changes locally
  • I have linked relevant issues
  • I have added screenshots for UI changes (if applicable)

Screenshots (if applicable)

image

Additional Context

  • BubbleParser.ts: Merged array element extraction logic into unified method
  • BubbleParser.test.ts: Added comprehensive tests for all Promise.all patterns
  • promise-all-patterns.ts: Created fixture file with 5 test cases

Summary by CodeRabbit

  • Tests

    • Added comprehensive test suite validating Promise.all pattern recognition across multiple scenarios.
  • Improvements

    • Enhanced runtime support for concurrent async operation patterns using array-based approaches.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 25, 2025

📝 Walkthrough

Walkthrough

Enhanced BubbleParser to support Promise.all patterns using .map() callbacks in addition to existing .push() patterns. Includes expanded test coverage and a new fixture file demonstrating five distinct Promise.all pattern implementations.

Changes

Cohort / File(s) Summary
BubbleParser Implementation
packages/bubble-runtime/src/extraction/BubbleParser.ts
Renamed findArrayPushCalls to findArrayElements and expanded to collect elements from both .push() calls and .map() callbacks. Introduced three new helpers: extractCallbackExpression to derive callback return expressions, getSourceArrayElements to retrieve array elements (literals or identifiers), and findReturnStatements to locate return statements within function bodies. Updated Promise.all handling logic to support direct array expressions and identifier-based arrays.
BubbleParser Test Suite
packages/bubble-runtime/src/extraction/BubbleParser.test.ts
Added comprehensive test suite for Promise.all parsing covering five patterns: direct array literals, array building via .push(), .map() with expression bodies, .map() with block bodies, and mapping variable arrays. Introduced extractClass helper to isolate class blocks from fixtures and assertions validating parallel_execution nodes with three or more suitable children.
Fixture Registry
packages/bubble-runtime/tests/fixtures/index.ts
Added 'promise-all-patterns' entry to fixtures object, implicitly expanding the FixtureName type.
Promise.all Pattern Fixture
packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts
New fixture file introducing five exported flow classes (PromiseAllDirectArrayFlow, PromiseAllArrayPushFlow, PromiseAllArrayMapFlow, PromiseAllArrayMapBlockFlow, PromiseAllMapVariableFlow), each demonstrating a distinct Promise.all usage pattern with an Output interface defining the results shape.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A parser hops through patterns true,
From .push() calls to .map() too,
Callbacks bloom with promise flows,
Five fixtures dance in parallel rows! 🚀

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix Promise.all visualization for .map() patterns' clearly and concisely describes the main change: expanding Promise.all parsing to support .map() patterns for correct visualization.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@bubblelab-pearl
Copy link
Contributor

Suggested PR title from Pearl

Title: feat(parser): support .map() pattern in Promise.all array detection

Body:

Summary

Enhances the BubbleParser to detect and parse Promise.all patterns that use .map() in addition to the existing .push() and direct array literal support.

Changes

Parser Enhancements

  • Renamed method: findArrayPushCallsfindArrayElements to reflect broader functionality
  • Added .map() pattern detection: Handles both expression body and block body callbacks
    • items.map(item => this.process(item))
    • items.map(item => { return this.process(item); })
  • Support for variable arrays: Tracks array variables to resolve source elements

New Helper Methods

  • extractCallbackExpression(): Extracts expressions from arrow functions and function expressions
  • getSourceArrayElements(): Resolves array elements from literals or variable declarations
  • findReturnStatements(): Locates return statements within block bodies

Test Coverage

Added comprehensive test suite covering 5 Promise.all patterns:

  1. Direct array literal: Promise.all([task1(), task2()])
  2. Array with .push(): tasks.push(task1()); Promise.all(tasks)
  3. Array with .map() expression body: items.map(i => process(i))
  4. Array with .map() block body: items.map(i => { return process(i); })
  5. Variable array with .map(): Resolves source array from variable

Files Changed

  • packages/bubble-runtime/src/extraction/BubbleParser.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
  • packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts (new)
  • packages/bubble-runtime/tests/fixtures/index.ts

Copy link

@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 (4)
packages/bubble-runtime/src/extraction/BubbleParser.ts (3)

3883-3924: Consider documenting the map pattern detection limitations.

The current implementation only detects .map() patterns when the variable declaration directly matches the Promise.all array variable. This means intermediate variables won't be detected:

// ✅ Detected
const promises = items.map(x => this.process(x));
await Promise.all(promises);

// ❌ Not detected
const mapped = items.map(x => this.process(x));
const promises = mapped;
await Promise.all(promises);

Additionally, at lines 3915-3918, the same callbackExpr is duplicated for each source element without parameter substitution. While this appears intentional for visualization purposes, it means all parallel nodes will show identical expressions rather than reflecting the actual parameter values.

Consider adding a comment explaining these limitations and the rationale for duplicating expressions without substitution.


3939-3957: Document callback expression extraction edge cases.

The extractCallbackExpression method handles basic arrow and function expressions, but several edge cases aren't addressed:

  1. Async callbacks: async (x) => await this.process(x) - The async keyword isn't explicitly handled
  2. Multiple return paths: Line 3954 only takes the first return statement, which may not represent all code paths
  3. Destructured parameters: ({x, y}) => this.process(x, y)

While these may not be common in Promise.all patterns, consider adding a comment documenting these limitations.


3968-4018: Source array resolution is limited to literals and simple identifiers.

The getSourceArrayElements method only resolves:

  • Direct array literals: [1, 2, 3]
  • Simple variable identifiers: const arr = [1, 2, 3]; items.map(...)

It doesn't handle:

  • Function calls: items.map(x => this.process(getArray()))
  • Computed arrays: items.map(x => this.process(arr.slice(0, 2)))
  • Imported/external arrays

This is likely sufficient for most use cases, but consider adding a comment explaining this scope limitation.

packages/bubble-runtime/src/extraction/BubbleParser.test.ts (1)

432-455: Consider edge case handling in extractClass helper.

The extractClass helper extracts a single class from the fixture by finding the start and end lines. However, the logic at lines 442-450 assumes:

  1. Each class starts with export class
  2. The next class declaration marks the end of the current class
  3. The last class extends to the end of the file

This works for the current fixture structure, but could fail if:

  • A class contains a nested class
  • Comments contain the text "export class"
  • The class has complex formatting

Since this is test-only code and works for the current fixture, this is acceptable. Consider adding a comment noting these assumptions.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c72dde and 2a8cb74.

📒 Files selected for processing (4)
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.ts
  • packages/bubble-runtime/tests/fixtures/index.ts
  • packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-12-19T03:16:48.793Z
Learning: Applies to **/bubblelab-api/**/*.test.{js,ts} : Use `pnpm bun test` command to run backend tests to ensure setup files are properly loaded
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-12-19T03:16:48.793Z
Learning: Applies to **/bubblelab-api/**/*.test.{js,ts} : Reference webhook.test as the example for how backend tests should be written
📚 Learning: 2025-12-19T03:17:06.817Z
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/bundling.mdc:0-0
Timestamp: 2025-12-19T03:17:06.817Z
Learning: Applies to packages/bubble-core/src/index.ts : All new types and classes added to bubble-core must be exported from `packages/bubble-core/src/index.ts` to ensure they are included in the generated bundle

Applied to files:

  • packages/bubble-runtime/tests/fixtures/index.ts
  • packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
📚 Learning: 2025-12-19T03:17:06.817Z
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/bundling.mdc:0-0
Timestamp: 2025-12-19T03:17:06.817Z
Learning: When adding new types to `bubblelab/shared-schemas`, they are automatically included in the bundle without requiring manual configuration changes

Applied to files:

  • packages/bubble-runtime/tests/fixtures/index.ts
📚 Learning: 2025-12-19T03:17:06.817Z
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/bundling.mdc:0-0
Timestamp: 2025-12-19T03:17:06.817Z
Learning: Applies to packages/bubble-core/dist/**/*.d.ts : The type bundling system for Monaco Editor must process TypeScript declaration files (.d.ts) and inline all dependencies into a single self-contained bundle in `packages/bubble-core/dist/bubble-bundle.d.ts`

Applied to files:

  • packages/bubble-runtime/tests/fixtures/index.ts
  • packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
📚 Learning: 2025-12-22T09:55:47.864Z
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/bubblelab.mdc:0-0
Timestamp: 2025-12-22T09:55:47.864Z
Learning: Applies to packages/bubble-runtime/src/extraction/README.md : Refer to packages/bubble-runtime/src/extraction/README.md for information about bubble parsing, dependency graphs, and per-invocation cloning

Applied to files:

  • packages/bubble-runtime/src/extraction/BubbleParser.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
📚 Learning: 2025-12-19T03:16:48.793Z
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-12-19T03:16:48.793Z
Learning: Applies to **/bubblelab-api/**/*.test.{js,ts} : Reference webhook.test as the example for how backend tests should be written

Applied to files:

  • packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
📚 Learning: 2025-12-19T03:16:48.793Z
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/api.mdc:0-0
Timestamp: 2025-12-19T03:16:48.793Z
Learning: Applies to **/bubblelab-api/**/*.test.{js,ts} : Use `pnpm bun test` command to run backend tests to ensure setup files are properly loaded

Applied to files:

  • packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
📚 Learning: 2025-12-19T03:17:06.817Z
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/bundling.mdc:0-0
Timestamp: 2025-12-19T03:17:06.817Z
Learning: Applies to packages/bubble-core/dist/**/*.d.ts : All external imports (except relative imports) must be removed from the bundled output to prevent circular processing and external dependency issues

Applied to files:

  • packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
📚 Learning: 2025-12-22T09:55:47.864Z
Learnt from: CR
Repo: bubblelabai/BubbleLab PR: 0
File: .cursor/rules/bubblelab.mdc:0-0
Timestamp: 2025-12-22T09:55:47.864Z
Learning: Applies to packages/bubble-shared-schemas/src/bubbleflow-generation-prompts.ts : Refer to packages/bubble-shared-schemas/src/bubbleflow-generation-prompts.ts for documentation on how bubble flow is supposed to be generated

Applied to files:

  • packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts
  • packages/bubble-runtime/src/extraction/BubbleParser.test.ts
🧬 Code graph analysis (2)
packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts (2)
packages/bubble-core/src/index.ts (1)
  • BubbleFlow (19-19)
packages/bubble-shared-schemas/src/trigger.ts (1)
  • WebhookEvent (64-66)
packages/bubble-runtime/src/extraction/BubbleParser.test.ts (4)
packages/bubble-core/src/bubble-factory.ts (1)
  • BubbleFactory (61-810)
packages/bubble-core/src/index.ts (1)
  • BubbleFactory (118-118)
packages/bubble-runtime/tests/fixtures/index.ts (1)
  • getFixture (90-92)
packages/bubble-runtime/src/extraction/BubbleParser.ts (1)
  • BubbleParser (50-4407)
⏰ 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: test
🔇 Additional comments (5)
packages/bubble-runtime/src/extraction/BubbleParser.ts (1)

3843-3934: LGTM! Well-structured refactoring with expanded functionality.

The renaming from findArrayPushCalls to findArrayElements appropriately reflects the expanded scope. The implementation correctly handles both .push() and .map() patterns, properly using scope resolution to match variable IDs and avoid false positives from same-named variables in different scopes.

packages/bubble-runtime/tests/fixtures/promise-all-patterns.ts (1)

1-112: Excellent test fixture with comprehensive coverage.

This fixture file provides thorough coverage of Promise.all patterns:

  1. Direct array literals
  2. Array with .push() calls
  3. .map() with expression body
  4. .map() with block body
  5. .map() with variable arrays

Each test case is clear, focused, and representative of real-world usage patterns. The consistent structure (extending BubbleFlow, returning Output, using simple helper methods) makes them easy to understand and maintain.

packages/bubble-runtime/tests/fixtures/index.ts (1)

71-71: LGTM! Fixture properly registered.

The new fixture is correctly added to the registry, following the established pattern.

packages/bubble-runtime/src/extraction/BubbleParser.test.ts (2)

457-632: Comprehensive test coverage validates the fix.

The test suite thoroughly exercises all Promise.all patterns:

  • Direct array literals
  • .push() patterns
  • .map() with expression bodies
  • .map() with block bodies
  • .map() with variable arrays

Each test appropriately verifies:

  1. A parallel_execution node is created
  2. The correct number of children are present
  3. Children are of the expected types (function_call or transformation_function)

The use of toBeGreaterThanOrEqual for the variable array test (line 624) is appropriate since the array size is determined by fixture content rather than being explicitly 3.


634-667: Good defensive testing with relaxed assertions for edge cases.

The final test using the existing bubble-inside-promise fixture is valuable as a regression test. The relaxed assertions (line 665: toBeGreaterThan(0) instead of exact count) are appropriate here since the test comment notes the pattern might not be fully detected by the current implementation.

This test ensures the parser doesn't break on existing fixtures while the new tests validate the enhanced functionality.

@zhubzy zhubzy merged commit 7a586a2 into bubblelabai:main Dec 27, 2025
1 of 2 checks passed
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.

3 participants