Skip to content

fix: prevent ASI in wrapCode causing refactoring to fail#41727

Merged
subrata71 merged 1 commit intoreleasefrom
fix/prevent-asi-in-wrapcode-ast
Apr 9, 2026
Merged

fix: prevent ASI in wrapCode causing refactoring to fail#41727
subrata71 merged 1 commit intoreleasefrom
fix/prevent-asi-in-wrapcode-ast

Conversation

@subrata71
Copy link
Copy Markdown
Collaborator

@subrata71 subrata71 commented Apr 9, 2026

Description

When a UI module containing a custom widget is instantiated in an app, the inputs references inside the custom widget's defaultModel property are not refactored. For example, inputs.title should become Commons1.inputs.title but remains unchanged.

Root cause: The entityRefactorFromCode function in the AST package passes raw binding content (which may have leading whitespace/newlines) directly to wrapCode without sanitization. wrapCode wraps code as (function() { return ${code} }). When the binding content starts with a newline followed by { (common in custom widget defaultModel which contains multi-line object literals), JavaScript's Automatic Semicolon Insertion (ASI) rule inserts a semicolon after return. This causes { to be parsed as a block statement instead of an object literal, resulting in a SyntaxError. The error is silently swallowed in AstServiceCEImpl.refactorNameInDynamicBindings, leaving the binding unrefactored.

Fix: Trim leading whitespace from the script in entityRefactorFromCode before passing it to wrapCode, so { lands on the same line as return (preventing ASI). The leading whitespace is restored after unwrapping to preserve the original content. This fix is localized to entityRefactorFromCodewrapCode itself is unchanged because other consumers (linting, ActionCreator, etc.) pass multi-statement evaluation scripts through it, and those would break if the return expression were parenthesized. Also replaces the magic-number slicing in unwrapCode (flagged as tech-debt) with named constants.

Fixes #32841
Fixes https://linear.app/appsmith/issue/APP-15087/bug-ast-fails-to-refactor-if-moustache-binding-starts-with-a-new-line

TDD verification:

Phase Result
Red: multi-line object literal test Failed as expected (isSuccess: false)
Green: applied localized fix in entityRefactorFromCode All 73 tests across 4 AST suites pass
No regression to wrapCode consumers wrapCode output is identical to original

Automation

/ok-to-test tags="@tag.All"

🔍 Cypress test results

Tip

🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
Workflow run: https://github.com/appsmithorg/appsmith/actions/runs/24177924705
Commit: 76a1a67
Cypress dashboard.
Tags: @tag.All
Spec:


Thu, 09 Apr 2026 09:10:21 UTC

Communication

Should the DevRel and Marketing teams inform users about this change?

  • Yes
  • No

Summary by CodeRabbit

Release Notes

  • Tests

    • Added comprehensive test coverage for code entity refactoring functionality.
  • Refactor

    • Improved code wrapping logic with named constants for better maintainability.
    • Enhanced preservation of whitespace formatting in code transformations.

@subrata71 subrata71 self-assigned this Apr 9, 2026
@linear
Copy link
Copy Markdown

linear bot commented Apr 9, 2026

@github-actions github-actions bot added AST-backend Backend issues related to AST parsing AST-frontend Issues related to maintaining AST logic Bug Something isn't working Javascript Product Issues related to users writing javascript in appsmith Medium Issues that frustrate users due to poor UX Needs Triaging Needs attention from maintainers to triage Production Query & JS Pod Issues related to the query & JS Pod Query Widgets & IDE Pod All issues related to Query, JS, Eval, Widgets & IDE Up for grabs Issues that have little to no dependencies on design/product, can be picked up in an ad-hoc manner labels Apr 9, 2026
@subrata71 subrata71 requested a review from ashit-rath April 9, 2026 07:22
@subrata71 subrata71 added the ok-to-test Required label for CI label Apr 9, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 9, 2026

Walkthrough

The pull request fixes an AST refactoring bug triggered by moustache bindings starting with newlines. Changes refactor wrap/unwrap logic to use constants instead of magic numbers, capture and preserve leading whitespace, and address automatic semicolon insertion (ASI) issues when wrapped code begins with a newline before object literals.

Changes

Cohort / File(s) Summary
Wrap/Unwrap & Whitespace Handling
app/client/packages/ast/src/index.ts
Refactored wrapCode/unwrapCode to use fixed prefix/suffix constants instead of magic numbers. Updated entityRefactorFromCode to capture leading whitespace with regex, trim input before wrapping, and re-prepend whitespace after unwrapping to preserve original formatting and avoid ASI issues after return.
Entity Refactor Tests
app/client/packages/ast/src/index.test.ts
Added comprehensive entityRefactorFromCode test suite covering simple member reference refactoring, multiline and inline object-literal refactoring, non-inputs entity refactoring, and wrapCode behavior validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🔄 Newlines no longer lost in translation,
Constants replace magic numbers' temptation,
Whitespace preserved with careful precision,
ASI issues met with decisive decision,
Refactoring flows, the binding stays true! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main fix: preventing ASI (Automatic Semicolon Insertion) issues in wrapCode that cause refactoring failures.
Linked Issues check ✅ Passed The PR addresses the core objective from #32841: ensuring AST refactoring correctly handles bindings starting with leading newlines/multi-line object literals by trimming whitespace before wrapping and restoring it after unwrapping.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the ASI issue: test coverage for entityRefactorFromCode, refactoring of wrapCode/unwrapCode to use constants, and trimming logic in entityRefactorFromCode. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description is well-structured, comprehensive, and addresses all required sections including motivation, root cause analysis, fix details, issue references, and TDD verification with passing test results.

✏️ 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 fix/prevent-asi-in-wrapcode-ast

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
Copy Markdown
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.

🧹 Nitpick comments (1)
app/client/packages/ast/src/index.test.ts (1)

868-875: Test name is misleading—it doesn't test the roundtrip.

The test is named "wrapCode/unwrapCode roundtrip" but only asserts on wrapCode output. Either rename to "should wrap code with return statement" or actually test the roundtrip by verifying unwrapCode(wrapCode(code)) === code.

🔧 Suggested fix to test actual roundtrip
   it("should handle wrapCode/unwrapCode roundtrip correctly", () => {
     const code = "inputs.title";
     const wrapped = wrapCode(code);
 
     expect(wrapped).toContain("return");
     expect(wrapped).toContain(code);
+
+    // Import unwrapCode or replicate the unwrap logic to test roundtrip
+    const prefix = "\n    (function() {\n      return ";
+    const suffix = "\n    })\n  ";
+    const unwrapped = wrapped.slice(prefix.length, -suffix.length);
+    expect(unwrapped).toBe(code);
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/client/packages/ast/src/index.test.ts` around lines 868 - 875, The test
name claims a wrapCode/unwrapCode roundtrip but only checks wrapCode; update the
test to actually assert the roundtrip by calling unwrapCode(wrapCode(code)) and
expecting it to equal the original code (use wrapCode and unwrapCode symbols in
the same it block), or if you prefer to keep the simpler check, rename the test
to "should wrap code with return statement" to reflect it only verifies
wrapCode; make the change inside the existing test that references
wrapCode/unwrapCode.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/client/packages/ast/src/index.test.ts`:
- Around line 868-875: The test name claims a wrapCode/unwrapCode roundtrip but
only checks wrapCode; update the test to actually assert the roundtrip by
calling unwrapCode(wrapCode(code)) and expecting it to equal the original code
(use wrapCode and unwrapCode symbols in the same it block), or if you prefer to
keep the simpler check, rename the test to "should wrap code with return
statement" to reflect it only verifies wrapCode; make the change inside the
existing test that references wrapCode/unwrapCode.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 453c42c6-492f-44e0-a43e-b61d86e9fcc2

📥 Commits

Reviewing files that changed from the base of the PR and between 306f25f and 76a1a67.

📒 Files selected for processing (2)
  • app/client/packages/ast/src/index.test.ts
  • app/client/packages/ast/src/index.ts

@subrata71 subrata71 merged commit 5743047 into release Apr 9, 2026
156 of 158 checks passed
@subrata71 subrata71 deleted the fix/prevent-asi-in-wrapcode-ast branch April 9, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AST-backend Backend issues related to AST parsing AST-frontend Issues related to maintaining AST logic Bug Something isn't working Javascript Product Issues related to users writing javascript in appsmith Medium Issues that frustrate users due to poor UX Needs Triaging Needs attention from maintainers to triage ok-to-test Required label for CI Production Query & JS Pod Issues related to the query & JS Pod Query Widgets & IDE Pod All issues related to Query, JS, Eval, Widgets & IDE Up for grabs Issues that have little to no dependencies on design/product, can be picked up in an ad-hoc manner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: AST fails to refactor if moustache binding starts with a new line \n

2 participants