Skip to content

fix: wrap script in async IIFE to create isolated scope#6229

Merged
bijin-bruno merged 2 commits intousebruno:mainfrom
sanish-bruno:fix/merge-scripts
Dec 3, 2025
Merged

fix: wrap script in async IIFE to create isolated scope#6229
bijin-bruno merged 2 commits intousebruno:mainfrom
sanish-bruno:fix/merge-scripts

Conversation

@sanish-bruno
Copy link
Collaborator

@sanish-bruno sanish-bruno commented Nov 27, 2025

Description

Currently bruno concatenates all the scripts across the request tree path, so if we declare a variable within collection level script, we cannot redeclare the same variable, within any of the scripts that comes after it.

The problem exists even for guard clauses within the scripts, the script can return early within the collection level itself, and folder, request level scripts are never ran!

Fixes #6130

Contribution Checklist:

  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

  • Bug Fixes
    • Improved isolation between pre-request, post-response, and test script segments to prevent variable leakage and cross-script conflicts.
    • Corrected execution ordering for non-sequential script flows so post-response and test scripts run in the intended order.
    • Prevented early-return behavior in one segment from affecting other script segments.

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

@sanish-bruno sanish-bruno changed the title fix: lexical scope for running scripts fix: wrap script in async IIFE to create isolated scope Nov 27, 2025
@sanish-bruno sanish-bruno changed the title fix: wrap script in async IIFE to create isolated scope fix: wrap scripts in async IIFE to create isolated scope Nov 27, 2025
@sanish-bruno sanish-bruno changed the title fix: wrap scripts in async IIFE to create isolated scope fix: wrap script in async IIFE to create isolated scope Nov 27, 2025
@bijin-bruno
Copy link
Collaborator

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

Walkthrough

Wraps each script segment (collection, folder, request) in an async IIFE to isolate scope per segment and changes assembly logic for pre-request, post-response, and test scripts, including reversed ordering for non-sequential flows.

Changes

Cohort / File(s) Summary
Script Scope Isolation
packages/bruno-cli/src/utils/collection.js, packages/bruno-electron/src/utils/collection.js
Added internal wrapScriptInClosure helper that returns an async IIFE for non-empty scripts. Refactored assembly of prereq, post-response, and test scripts to wrap each segment individually and join with double-newlines. For non-sequential scriptFlow, reversed ordering of post-response and test segments before wrapping. Comments added describing scope isolation behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify wrapScriptInClosure handles empty inputs and produces valid async IIFE syntax.
  • Confirm ordering/reversal for non-sequential scriptFlow is correct across prereq, post-res, and tests.
  • Ensure no regression in concatenation/join semantics (double-newline separators) and consistent behavior between the two files.

Poem

Each script tucked in its own little shell,
Async IIFEs guard the stories they tell.
Collection talks first, endpoints still play,
Returns can’t cut the others away. 🎭

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: wrapping scripts in async IIFE to create isolated scopes, directly addressing the issue of variable conflicts and early returns blocking subsequent scripts.
Linked Issues check ✅ Passed The PR successfully implements scope isolation per script segment, preventing guard clauses and early returns from blocking downstream script execution, directly resolving #6130's requirements.
Out of Scope Changes check ✅ Passed All changes are focused on the closure-wrapping mechanism for pre-request, post-response, and test scripts across both CLI and Electron packages, remaining within scope of fixing script isolation.
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

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 218b156 and fa424e8.

📒 Files selected for processing (2)
  • packages/bruno-cli/src/utils/collection.js (2 hunks)
  • packages/bruno-electron/src/utils/collection.js (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CODING_STANDARDS.md)

**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation, never tabs
Use single quotes for strings instead of double quotes
Always add semicolons at the end of statements
No trailing commas in code
Always use parentheses around parameters in arrow functions, even for single parameters
For multiline constructs, put opening braces on the same line with a minimum of 2 elements for multiline formatting
No newlines inside function parentheses
Space before and after the arrow in arrow functions: () => {}
No space between function name and parentheses: func() not func ()
Semicolons should go at the end of the line, not on a new line
Function names should be concise and descriptive
Add JSDoc comments to provide details to abstractions
Avoid single-line abstractions where all that is being done is increasing the call stack with one additional function
Add meaningful comments to explain complex code flow instead of obvious comments

Files:

  • packages/bruno-cli/src/utils/collection.js
  • packages/bruno-electron/src/utils/collection.js
🧬 Code graph analysis (1)
packages/bruno-cli/src/utils/collection.js (2)
packages/bruno-electron/src/utils/collection.js (5)
  • wrapScriptInClosure (140-151)
  • preReqScripts (186-190)
  • collectionPreReqScript (155-155)
  • combinedPreReqScript (159-159)
  • os (5-5)
packages/bruno-electron/src/ipc/network/prepare-request.js (2)
  • request (306-306)
  • scriptFlow (321-321)
⏰ 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). (6)
  • GitHub Check: CLI Tests
  • GitHub Check: SSL Tests - macOS
  • GitHub Check: Unit Tests
  • GitHub Check: SSL Tests - Linux
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: SSL Tests - Windows
🔇 Additional comments (4)
packages/bruno-cli/src/utils/collection.js (2)

239-255: Async IIFE wrapper for scripts looks correct and safe

Guarding on !script || script.trim() === '' and returning an async IIFE string gives each segment its own scope and lets compact() drop empties cleanly. This mirrors the Electron implementation and respects our JS style + JSDoc guidance.

As per coding guidelines, this abstraction and its JSDoc look good.


285-331: mergeScripts correctly applies per-segment closures while preserving flow semantics

The new construction of preReqScripts, postResScripts, and testScripts arrays, followed by compact(...map(wrapScriptInClosure)).join(os.EOL + os.EOL), keeps the original ordering for scriptFlow === 'sequential' and reverses only post-res/tests for non-sequential flow, while ensuring each segment runs in its own isolated scope. No functional regressions or ordering issues stand out.

packages/bruno-electron/src/utils/collection.js (2)

135-152: Helper mirrors CLI behavior and cleanly isolates script scopes

This wrapScriptInClosure implementation is consistent with the CLI version, with the same empty-script guard and async IIFE wrapping, so Electron and CLI now share identical scope-isolation semantics for scripts.


182-228: Electron mergeScripts implementation stays in sync with CLI and honors scriptFlow

The per-segment wrapping and join logic here matches the CLI version: prereq scripts are always collection→folders→request; post-res and tests respect scriptFlow by using sequential or reversed ordering, with each segment wrapped via wrapScriptInClosure and filtered through compact. This alignment should avoid platform-specific surprises for users.


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 (4)
packages/bruno-cli/src/utils/collection.js (3)

285-294: Optional: First compact() call is redundant.

Since wrapScriptInClosure returns '' for falsy/empty values, the second compact() on line 294 will handle filtering. The first compact() on line 289 could be removed without affecting behavior.

-  const preReqScripts = compact([
+  const preReqScripts = [
     collectionPreReqScript,
     ...combinedPreReqScript,
     request?.script?.req || ''
-  ]);
+  ];
   request.script.req = compact(preReqScripts.map(wrapScriptInClosure)).join(os.EOL + os.EOL);

296-312: Optional: Minor style improvements.

Two minor opportunities for cleaner code:

  1. The first compact() is redundant (same reasoning as pre-request scripts)
  2. .reverse() mutates the array; consider creating a copy first for immutability
   if (scriptFlow === 'sequential') {
-    const postResScripts = compact([
+    const postResScripts = [
       collectionPostResScript,
       ...combinedPostResScript,
       request?.script?.res || ''
-    ]);
+    ];
     request.script.res = compact(postResScripts.map(wrapScriptInClosure)).join(os.EOL + os.EOL);
   } else {
-    const postResScripts = compact([
+    const postResScripts = [
       request?.script?.res || '',
-      ...combinedPostResScript.reverse(),
+      ...[...combinedPostResScript].reverse(),
       collectionPostResScript
-    ]);
+    ];
     request.script.res = compact(postResScripts.map(wrapScriptInClosure)).join(os.EOL + os.EOL);
   }

314-330: Optional: Apply same refactoring as post-response scripts.

Same opportunities as the post-response section: redundant compact() and array mutation.

   if (scriptFlow === 'sequential') {
-    const testScripts = compact([
+    const testScripts = [
       collectionTests,
       ...combinedTests,
       request?.tests || ''
-    ]);
+    ];
     request.tests = compact(testScripts.map(wrapScriptInClosure)).join(os.EOL + os.EOL);
   } else {
-    const testScripts = compact([
+    const testScripts = [
       request?.tests || '',
-      ...combinedTests.reverse(),
+      ...[...combinedTests].reverse(),
       collectionTests
-    ]);
+    ];
     request.tests = compact(testScripts.map(wrapScriptInClosure)).join(os.EOL + os.EOL);
   }
packages/bruno-electron/src/utils/collection.js (1)

182-227: Optional: Apply same refactoring suggestions as CLI version.

The script wrapping logic (pre-request, post-response, tests) has the same opportunities for minor cleanup as the CLI version:

  1. Redundant first compact() calls (lines 186, 195, 203, 213, 221)
  2. Array mutation via .reverse() (lines 205, 223)

Refer to the refactoring suggestions in the CLI file for specific diff blocks.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb0096e and 218b156.

📒 Files selected for processing (2)
  • packages/bruno-cli/src/utils/collection.js (2 hunks)
  • packages/bruno-electron/src/utils/collection.js (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CODING_STANDARDS.md)

**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single parameters
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses. Keep 'em tight
Space before and after the arrow in arrow functions. () => {} is good
No space between function name and parentheses. func() not func ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Avoid single line abstractions where all that's being done is increasing the call stack with one additional function
Add in meaningful comments instead of obvious ones where complex code flow is explained properly

Files:

  • packages/bruno-cli/src/utils/collection.js
  • packages/bruno-electron/src/utils/collection.js
🔇 Additional comments (4)
packages/bruno-cli/src/utils/collection.js (2)

239-254: LGTM - IIFE wrapper correctly isolates script scope.

The implementation properly prevents variable re-declaration and confines early returns to each script segment, addressing the core issue from #6130.


251-253: Verify that the script execution environment supports top-level await or provides an async context for these async IIFEs.

The wrapped scripts use await (async () => { ... })(), which requires either top-level await support or execution within an already-async context. Confirm that the runner/executor evaluates these scripts appropriately.

packages/bruno-electron/src/utils/collection.js (2)

135-151: LGTM - Implementation mirrors CLI version correctly.

The wrapScriptInClosure function and its usage are consistent across both packages, ensuring uniform behavior.


148-150: Verify async IIFE execution support in Electron's script runtime.

The code wraps scripts in an async IIFE pattern (await (async () => { ${script} })();). Confirm that Electron's script executor properly handles async/await syntax and that this pattern is consistent with the CLI implementation.

bijin-bruno
bijin-bruno previously approved these changes Dec 2, 2025
@helloanoop
Copy link
Contributor

This is a breaking change. We should carefully consider if we should do this for v3 release.

@bijin-bruno @sid-bruno

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Collection-level pre-request script is stopping endpoint-level re-req script

3 participants