From a35468a25f90712e6df65763ba15b2d45264f629 Mon Sep 17 00:00:00 2001 From: wackbyte Date: Wed, 5 Jul 2023 14:20:56 -0400 Subject: [PATCH] Preserve whitespace in text surrounded by newlines (#816) * 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 --- .changeset/soft-eggs-exercise.md | 5 ++++ internal/transform/transform.go | 30 ++++++++++++++---------- internal/transform/transform_test.go | 2 +- packages/compiler/test/compact/minify.ts | 22 +++++++++++------ 4 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 .changeset/soft-eggs-exercise.md diff --git a/.changeset/soft-eggs-exercise.md b/.changeset/soft-eggs-exercise.md new file mode 100644 index 000000000..cfa3ecafd --- /dev/null +++ b/.changeset/soft-eggs-exercise.md @@ -0,0 +1,5 @@ +--- +'@astrojs/compiler': patch +--- + +Do not remove surrounding whitespace from text surrounded by newlines when `compressHTML` is enabled diff --git a/internal/transform/transform.go b/internal/transform/transform.go index f2aa24d52..c96661a1a 100644 --- a/internal/transform/transform.go +++ b/internal/transform/transform.go @@ -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) - } } }) } diff --git a/internal/transform/transform_test.go b/internal/transform/transform_test.go index fe1449bf2..ceb846b59 100644 --- a/internal/transform/transform_test.go +++ b/internal/transform/transform_test.go @@ -355,7 +355,7 @@ func TestCompactTransform(t *testing.T) { { name: "collapse surrounding newlines", source: "
\n\n\tC O O L\n\n\t
", - want: "
C O O L
", + want: "
\nC O O L\n
", }, { name: "expression trim first", diff --git a/packages/compiler/test/compact/minify.ts b/packages/compiler/test/compact/minify.ts index 1ab959ddb..e443f54e4 100644 --- a/packages/compiler/test/compact/minify.ts +++ b/packages/compiler/test/compact/minify.ts @@ -14,14 +14,14 @@ test('basic', async () => { test('preservation', async () => { assert.match(await minify(`
  !  
`), '$$render`
  !  
`'); - assert.ok(await minify(`
!
`), '$$render`
!
`'); - assert.ok(await minify(` ! `), '$$render` ! `'); + assert.match(await minify(`
!
`), '$$render`
!
`'); + assert.match(await minify(` ! `), '$$render` ! `'); }); test('collapsing', async () => { - assert.ok(await minify(` inline `), '$$render` inline `'); - assert.ok(await minify(`\n inline \t{\t expression \t}`), '$$render` inline ${ expression } `'); - assert.ok(await minify(` inline { expression }`), '$$render` inline ${ expression }`'); + assert.match(await minify(` inline `), '$$render` inline `'); + assert.match(await minify(`\n inline \t{\t expression \t}`), '$$render`\ninline ${expression}`'); + assert.match(await minify(` inline { expression }`), '$$render` inline ${expression}`'); }); test('space normalization between attributes', async () => { @@ -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 = 'foo\n\t\tbar\n\t\tbaz'; - const output = 'foobarbaz'; + const output = 'foo\nbar\nbaz'; + const result = await minify(input); + + assert.match(result, output); +}); + +test('separated by newlines (#815)', async () => { + const input = '

\n\ta\n\tb\n\tc\n

'; + const output = '

\na\nb\nc\n

'; const result = await minify(input); assert.match(result, output);