Skip to content

Commit c0f0df7

Browse files
Formatter: Fix heredoc formatting (#1142)
Fixes #476 This PR addresses the heredoc formatting problem described in the issue. --------- Co-authored-by: Marco Roth <marco.roth@intergga.ch>
1 parent 7b187fa commit c0f0df7

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

javascript/packages/formatter/src/format-printer.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,17 @@ export class FormatPrinter extends Printer {
285285

286286
/**
287287
* Format ERB content with proper spacing around the inner content.
288-
* Returns empty string if content is empty, otherwise wraps content with single spaces.
288+
* Returns empty string if content is empty, otherwise adds a leading space
289+
* and a trailing space (or newline for heredoc content starting with "<<").
289290
*/
290291
private formatERBContent(content: string): string {
291-
return content.trim() ? ` ${content.trim()} ` : ""
292+
let trimmedContent = content.trim();
293+
294+
// See: https://github.com/marcoroth/herb/issues/476
295+
// TODO: revisit once we have access to Prism nodes
296+
let suffix = trimmedContent.startsWith("<<") ? "\n" : " "
297+
298+
return trimmedContent ? ` ${trimmedContent}${suffix}` : ""
292299
}
293300

294301
/**

javascript/packages/formatter/test/erb/erb.test.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,144 @@ describe("@herb-tools/formatter", () => {
15781578
expect(result).toBe(expected)
15791579
})
15801580

1581+
test("ERB output with heredoc (issue 476)", () => {
1582+
const input = dedent`
1583+
<%= <<EXAMPLE
1584+
example
1585+
EXAMPLE
1586+
%>
1587+
`
1588+
1589+
const result = formatter.format(input)
1590+
1591+
expect(result).toBe(input)
1592+
})
1593+
1594+
test("ERB output with squiggly heredoc", () => {
1595+
const input = dedent`
1596+
<%= <<~HEREDOC
1597+
example
1598+
HEREDOC
1599+
%>
1600+
`
1601+
1602+
const result = formatter.format(input)
1603+
1604+
expect(result).toBe(input)
1605+
})
1606+
1607+
test("ERB output with hyphen heredoc", () => {
1608+
const input = dedent`
1609+
<%= <<-HEREDOC
1610+
example
1611+
HEREDOC
1612+
%>
1613+
`
1614+
1615+
const result = formatter.format(input)
1616+
1617+
expect(result).toBe(input)
1618+
})
1619+
1620+
test("ERB output with single-quoted heredoc", () => {
1621+
const input = dedent`
1622+
<%= <<'HEREDOC'
1623+
no #{interpolation}
1624+
HEREDOC
1625+
%>
1626+
`
1627+
1628+
const result = formatter.format(input)
1629+
1630+
expect(result).toBe(input)
1631+
})
1632+
1633+
test("ERB output with double-quoted heredoc", () => {
1634+
const input = dedent`
1635+
<%= <<"HEREDOC"
1636+
with #{interpolation}
1637+
HEREDOC
1638+
%>
1639+
`
1640+
1641+
const result = formatter.format(input)
1642+
1643+
expect(result).toBe(input)
1644+
})
1645+
1646+
test("ERB output with heredoc and method chaining", () => {
1647+
const input = dedent`
1648+
<%= <<HEREDOC.strip
1649+
example
1650+
HEREDOC
1651+
%>
1652+
`
1653+
1654+
const result = formatter.format(input)
1655+
1656+
expect(result).toBe(input)
1657+
})
1658+
1659+
test("ERB output with bitshift operator", () => {
1660+
const input = `<%= 1 << 4 %>`
1661+
1662+
const result = formatter.format(input)
1663+
1664+
expect(result).toBe(input)
1665+
})
1666+
1667+
test("ERB output with append operator", () => {
1668+
const input = `<%= array << item %>`
1669+
1670+
const result = formatter.format(input)
1671+
1672+
expect(result).toBe(input)
1673+
})
1674+
1675+
// The heredoc is not detected because it doesn't start with "<<".
1676+
// See: https://github.com/marcoroth/herb/issues/476
1677+
// TODO: revisit once we have access to Prism nodes
1678+
test("ERB output with heredoc as method argument", () => {
1679+
const input = dedent`
1680+
<%= foo(<<HEREDOC)
1681+
example
1682+
HEREDOC
1683+
%>
1684+
`
1685+
1686+
const expected = dedent`
1687+
<%= foo(<<HEREDOC)
1688+
example
1689+
HEREDOC %>
1690+
`
1691+
1692+
const result = formatter.format(input)
1693+
1694+
expect(result).toBe(expected)
1695+
})
1696+
1697+
// The heredoc is not detected because it doesn't start with "<<".
1698+
// See: https://github.com/marcoroth/herb/issues/476
1699+
// TODO: revisit once we have access to Prism nodes
1700+
test("ERB output with heredoc after assignment", () => {
1701+
const input = dedent`
1702+
<%= x = <<HEREDOC
1703+
example
1704+
HEREDOC
1705+
%>
1706+
`
1707+
1708+
const expected = dedent`
1709+
<%= x = <<HEREDOC
1710+
example
1711+
HEREDOC %>
1712+
`
1713+
1714+
const result = formatter.format(input)
1715+
1716+
expect(result).toBe(expected)
1717+
})
1718+
15811719
test("keeps hyphen-attached inline element together during line wrapping", () => {
15821720
const input = dedent`
15831721
<div>

0 commit comments

Comments
 (0)