Skip to content

Commit

Permalink
Preserve whitespace in text surrounded by newlines (#816)
Browse files Browse the repository at this point in the history
* fix: replace incorrect use of `assert.ok` with `assert.match`

* fix: don't remove all surrounding whitespace from text nodes surrounded by newlines

* fix: revert go tests

* fix: update js tests

* add changeset
  • Loading branch information
wackbyte authored Jul 5, 2023
1 parent 002fd34 commit a35468a
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/soft-eggs-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/compiler': patch
---

Do not remove surrounding whitespace from text surrounded by newlines when `compressHTML` is enabled
30 changes: 17 additions & 13 deletions internal/transform/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,59 +263,63 @@ func isRawElement(n *astro.Node) bool {
func collapseWhitespace(doc *astro.Node) {
walk(doc, func(n *astro.Node) {
if n.Type == astro.TextNode {
// Don't trim any whitespace if the node or any of its ancestors is raw
if n.Closest(isRawElement) != nil {
return
}
// Top-level expression children

// Trim the whitespace on each end of top-level expressions
if n.Parent != nil && n.Parent.Expression {
// Trim left for first child
// Trim left whitespace in the first child
if n.PrevSibling == nil {
n.Data = strings.TrimLeftFunc(n.Data, unicode.IsSpace)
}
// Trim right for last child
// Trim right whitespace in the last child
if n.NextSibling == nil {
n.Data = strings.TrimRightFunc(n.Data, unicode.IsSpace)
}
// Otherwise don't trim this!
// Don't trim any more!
return
}

// If the node is only whitespace, clear it
if len(strings.TrimFunc(n.Data, unicode.IsSpace)) == 0 {
n.Data = ""
return
}

// Collapse left whitespace into a single space
originalLen := len(n.Data)
hasLeftNewline := false
hasNewline := false
n.Data = strings.TrimLeftFunc(n.Data, func(r rune) bool {
if r == '\n' {
hasLeftNewline = true
hasNewline = true
}
return unicode.IsSpace(r)
})
if originalLen != len(n.Data) {
if hasLeftNewline {
if hasNewline {
n.Data = "\n" + n.Data
} else {
n.Data = " " + n.Data
}
}
hasRightNewline := false
// Collapse right whitespace into a single space
originalLen = len(n.Data)
hasNewline = false
n.Data = strings.TrimRightFunc(n.Data, func(r rune) bool {
if r == '\n' {
hasRightNewline = true
hasNewline = true
}
return unicode.IsSpace(r)
})
if originalLen != len(n.Data) {
if hasRightNewline {
if hasNewline {
n.Data = n.Data + "\n"
} else {
n.Data = n.Data + " "
}
}
if hasLeftNewline && hasRightNewline {
n.Data = strings.TrimSpace(n.Data)
}
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion internal/transform/transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ func TestCompactTransform(t *testing.T) {
{
name: "collapse surrounding newlines",
source: "<div>\n\n\tC O O L\n\n\t</div>",
want: "<div>C O O L</div>",
want: "<div>\nC O O L\n</div>",
},
{
name: "expression trim first",
Expand Down
22 changes: 15 additions & 7 deletions packages/compiler/test/compact/minify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ test('basic', async () => {

test('preservation', async () => {
assert.match(await minify(`<pre> ! </pre>`), '$$render`<pre> ! </pre>`');
assert.ok(await minify(`<div is:raw> ! </div>`), '$$render`<div> ! </div>`');
assert.ok(await minify(`<Markdown> ! </Markdown>`), '$$render` ! `');
assert.match(await minify(`<div is:raw> ! </div>`), '$$render`<div> ! </div>`');
assert.match(await minify(`<Markdown is:raw> ! </Markdown>`), '$$render` ! `');
});

test('collapsing', async () => {
assert.ok(await minify(`<span> inline </span>`), '$$render`<span> inline </span>`');
assert.ok(await minify(`<span>\n inline \t{\t expression \t}</span>`), '$$render`<span> inline ${ expression } </span>`');
assert.ok(await minify(`<span> inline { expression }</span>`), '$$render`<span> inline ${ expression }</span>`');
assert.match(await minify(`<span> inline </span>`), '$$render`<span> inline </span>`');
assert.match(await minify(`<span>\n inline \t{\t expression \t}</span>`), '$$render`<span>\ninline ${expression}</span>`');
assert.match(await minify(`<span> inline { expression }</span>`), '$$render`<span> inline ${expression}</span>`');
});

test('space normalization between attributes', async () => {
Expand Down Expand Up @@ -150,9 +150,17 @@ test('space normalization around text', async () => {
);
});

test('surrounded by newlines #7401', async () => {
test('surrounded by newlines (astro#7401)', async () => {
const input = '<span>foo</span>\n\t\tbar\n\t\t<span>baz</span>';
const output = '<span>foo</span>bar<span>baz</span>';
const output = '<span>foo</span>\nbar\n<span>baz</span>';
const result = await minify(input);

assert.match(result, output);
});

test('separated by newlines (#815)', async () => {
const input = '<p>\n\ta\n\t<span>b</span>\n\tc\n</p>';
const output = '<p>\na\n<span>b</span>\nc\n</p>';
const result = await minify(input);

assert.match(result, output);
Expand Down

0 comments on commit a35468a

Please sign in to comment.