diff --git a/javascript/packages/formatter/src/format-printer.ts b/javascript/packages/formatter/src/format-printer.ts index 20f8f4678..654815219 100644 --- a/javascript/packages/formatter/src/format-printer.ts +++ b/javascript/packages/formatter/src/format-printer.ts @@ -1517,6 +1517,16 @@ export class FormatPrinter extends Printer { if (!openTagInline) return false if (children.length === 0) return true + const hasNonInlineChildElements = children.some(child => { + if (isNode(child, HTMLElementNode)) { + return !this.shouldRenderElementContentInline(child) + } + + return false + }) + + if (hasNonInlineChildElements) return false + let hasLeadingHerbDisable = false for (const child of node.body) { @@ -1538,7 +1548,7 @@ export class FormatPrinter extends Printer { if (fullInlineResult) { const totalLength = this.indent.length + fullInlineResult.length - return totalLength <= this.maxLineLength || totalLength <= 120 + return totalLength <= this.maxLineLength } return false @@ -1573,8 +1583,9 @@ export class FormatPrinter extends Printer { const childrenContent = this.renderChildrenInline(children) const fullLine = openTagResult + childrenContent + `` + const totalLength = this.indent.length + fullLine.length - if ((this.indent.length + fullLine.length) <= this.maxLineLength) { + if (totalLength <= this.maxLineLength) { return true } } diff --git a/javascript/packages/formatter/test/erb/case.test.ts b/javascript/packages/formatter/test/erb/case.test.ts index fcaf5ac00..d40aadd1e 100644 --- a/javascript/packages/formatter/test/erb/case.test.ts +++ b/javascript/packages/formatter/test/erb/case.test.ts @@ -174,4 +174,99 @@ describe("@herb-tools/formatter", () => { const output = formatter.format(input) expect(output).toEqual(input) }) + + test("case/when with long outputs inside inline element - breaks at ERB boundaries", () => { + const input = dedent` +
+ + <% case status %> + <% when 'pending' %> + <%= render partial: 'status_badge', locals: { text: 'Pending Review', color: 'yellow' } %> + <% when 'approved' %> + <%= render partial: 'status_badge', locals: { text: 'Approved', color: 'green' } %> + <% when 'rejected' %> + <%= render partial: 'status_badge', locals: { text: 'Rejected', color: 'red' } %> + <% end %> + +
+ ` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + + test("case/when with method calls and long paths - breaks at ERB boundaries", () => { + const input = dedent` +
+ + <% case user.subscription_tier %> + <% when :premium %> + <%= link_to "Premium Dashboard", premium_dashboard_path(user_id: user.id, features: :all) %> + <% when :basic %> + <%= link_to "Basic Dashboard", basic_dashboard_path(user_id: user.id, features: :limited) %> + <% else %> + <%= link_to "Free Dashboard", free_dashboard_path(user_id: user.id, features: :minimal) %> + <% end %> + +
+ ` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + + test("case/in with complex patterns and long outputs - breaks at ERB boundaries", () => { + const input = dedent` +
+ + <% case user_data %> + <% in { role: 'admin', permissions: { level: level } } if level > 5 %> + <%= link_to "Super Admin Panel", super_admin_path(user: user_data, access: :full) %> + <% in { role: 'moderator', permissions: } %> + <%= link_to "Moderator Tools", moderator_path(user: user_data, access: :limited) %> + <% else %> + <%= link_to "User Profile", profile_path(user: user_data, access: :basic) %> + <% end %> + +
+ ` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + + describe("no whitespace introduction on single-line case statements", () => { + test("short case/when stays on one line without whitespace", () => { + const input = `<% case x %><% when 1 %>One<% when 2 %>Two<% else %>Other<% end %>` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + + test("short case/when with ERB output stays on one line - no whitespace", () => { + const input = `<% case type %><% when :ok %><%= msg %><% else %>Error<% end %>` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + + test("short case/when with only text stays on one line - no whitespace", () => { + const input = `<% case status %><% when 'ok' %>OK<% else %>Fail<% end %>` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + + test("short case/in stays on one line - no whitespace", () => { + const input = `<% case val %><% in 1 %>A<% in 2 %>B<% else %>C<% end %>` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + + test("short case with symbols stays on one line - no whitespace", () => { + const input = `<% case role %><% when :admin %>Admin<% when :user %>User<% end %>` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + + test("short case with ERB output stays on one line - no whitespace", () => { + const input = `<% case a %><% when 1 %><%= x %><% when 2 %><%= y %><% end %>` + const output = formatter.format(input) + expect(output).toEqual(input) + }) + }) }) diff --git a/javascript/packages/formatter/test/erb/erb.test.ts b/javascript/packages/formatter/test/erb/erb.test.ts index e63ffb3c3..1dff621d8 100644 --- a/javascript/packages/formatter/test/erb/erb.test.ts +++ b/javascript/packages/formatter/test/erb/erb.test.ts @@ -795,100 +795,102 @@ describe("@herb-tools/formatter", () => { ` - const expected = dedent` -
- - - -
+ const expected = dedent` +
+ + +