From aaf6b3a9a864d090aaf02ec5558c9debab5e2e00 Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Thu, 9 Jul 2026 15:50:14 +0200 Subject: [PATCH] Add missing space between style and class attributes on line elements Lines that carry a line style (highlight, diff, focus) rendered as style="..."class='line ...' with no separator. Browsers recover, but HTML sanitizers reject the mangled attribute run - WordPress' wp_kses strips the class list from such lines entirely, breaking gutter padding and accent styling downstream. Acceptance fixtures updated accordingly. --- src/Generators/HtmlGenerator.php | 2 +- tests/LineAttributeSpacingTest.php | 21 +++++++++++++++++++ .../fixtures/tests/cpp-comment-is-removed.txt | 4 ++-- ...ators-in-place-of-line-numbers-but-off.txt | 4 ++-- ...ff-indicators-in-place-of-line-numbers.txt | 4 ++-- tests/fixtures/tests/diff-indicators.txt | 4 ++-- tests/fixtures/tests/diff-preserve-syntax.txt | 16 +++++++------- tests/fixtures/tests/files-html.txt | 8 +++---- .../fixtures/tests/fortnite-missing-words.txt | 12 +++++------ tests/fixtures/tests/http5.txt | 4 ++-- tests/fixtures/tests/jinja.txt | 4 ++-- tests/fixtures/tests/line-padding.txt | 4 ++-- .../tests/min-dark-has-git-diff-colors.txt | 4 ++-- .../tests/olalu-has-git-diff-colors.txt | 4 ++-- .../tests/one-dark-has-git-diff-colors.txt | 4 ++-- .../range-negative-offset-positive-length.txt | 4 ++-- .../range-positive-offset-positive-length.txt | 8 +++---- .../tests/relative-double-range-2.txt | 16 +++++++------- .../fixtures/tests/relative-double-range.txt | 16 +++++++------- tests/fixtures/tests/undefined-number.txt | 4 ++-- tests/fixtures/tests/yaml-with-config.txt | 12 +++++------ 21 files changed, 90 insertions(+), 69 deletions(-) create mode 100644 tests/LineAttributeSpacingTest.php diff --git a/src/Generators/HtmlGenerator.php b/src/Generators/HtmlGenerator.php index 67bbc4a..26d975c 100644 --- a/src/Generators/HtmlGenerator.php +++ b/src/Generators/HtmlGenerator.php @@ -691,7 +691,7 @@ private function buildLineElement(array $classes, string $content, int $currentL { $lineStyles = $this->themeResolver()->getLineStyles($classes); $styles = $this->themeResolver()->toStyleString($lineStyles); - $styleAttr = $styles !== '' ? "style=\"{$styles}\"" : ''; + $styleAttr = $styles !== '' ? "style=\"{$styles}\" " : ''; $attributes = $this->generationOptions()->lineAttributes[$currentLine] ?? []; $attributeString = ! empty($attributes) diff --git a/tests/LineAttributeSpacingTest.php b/tests/LineAttributeSpacingTest.php new file mode 100644 index 0000000..8badb7e --- /dev/null +++ b/tests/LineAttributeSpacingTest.php @@ -0,0 +1,21 @@ +codeToHtml($code, 'php', 'github-light'); + + // Lines that carry a line style used to render as `style="..."class='...'` + // (no space), which HTML sanitizers like WordPress' wp_kses reject, + // stripping the class list from highlighted and diff lines entirely. + expect($html)->toContain('line-highlight') + ->and($html)->toContain('line-add') + ->and($html)->toContain('line-remove') + ->and($html)->not->toMatch('/["\']class=/'); +}); diff --git a/tests/fixtures/tests/cpp-comment-is-removed.txt b/tests/fixtures/tests/cpp-comment-is-removed.txt index 2362add..64a8540 100644 --- a/tests/fixtures/tests/cpp-comment-is-removed.txt +++ b/tests/fixtures/tests/cpp-comment-is-removed.txt @@ -1,6 +1,6 @@ :::config { "language": "cpp", "theme": "nord" } return 0; /* [tl! ~~] */ :::expectation -
1return 0;
+
1return 0;
:::end -
1return 0;
\ No newline at end of file +
1return 0;
\ No newline at end of file diff --git a/tests/fixtures/tests/diff-indicators-in-place-of-line-numbers-but-off.txt b/tests/fixtures/tests/diff-indicators-in-place-of-line-numbers-but-off.txt index abf034f..c7b1693 100644 --- a/tests/fixtures/tests/diff-indicators-in-place-of-line-numbers-but-off.txt +++ b/tests/fixtures/tests/diff-indicators-in-place-of-line-numbers-but-off.txt @@ -6,9 +6,9 @@ function () { } :::expectation
function () { -
+ return 0;
- return 1;
} +
+ return 0;
- return 1;
}
:::end
function () { -
+ return 0;
- return 1;
} +
+ return 0;
- return 1;
}
\ No newline at end of file diff --git a/tests/fixtures/tests/diff-indicators-in-place-of-line-numbers.txt b/tests/fixtures/tests/diff-indicators-in-place-of-line-numbers.txt index 2467c84..9c590b7 100644 --- a/tests/fixtures/tests/diff-indicators-in-place-of-line-numbers.txt +++ b/tests/fixtures/tests/diff-indicators-in-place-of-line-numbers.txt @@ -6,9 +6,9 @@ function () { } :::expectation
1function () { -
+ return 0;
- return 1;
4} +
+ return 0;
- return 1;
4}
:::end
1function () { -
+ return 0;
- return 1;
4} +
+ return 0;
- return 1;
4}
\ No newline at end of file diff --git a/tests/fixtures/tests/diff-indicators.txt b/tests/fixtures/tests/diff-indicators.txt index 5cc6cb1..eb4f55a 100644 --- a/tests/fixtures/tests/diff-indicators.txt +++ b/tests/fixtures/tests/diff-indicators.txt @@ -6,9 +6,9 @@ function () { } :::expectation
1 function () { -
2+ return 0;
3- return 1;
4 } +
2+ return 0;
3- return 1;
4 }
:::end
1 function () { -
2+ return 0;
3- return 1;
4 } +
2+ return 0;
3- return 1;
4 }
\ No newline at end of file diff --git a/tests/fixtures/tests/diff-preserve-syntax.txt b/tests/fixtures/tests/diff-preserve-syntax.txt index 88bceac..07afd9d 100644 --- a/tests/fixtures/tests/diff-preserve-syntax.txt +++ b/tests/fixtures/tests/diff-preserve-syntax.txt @@ -7,14 +7,14 @@ function () { // [tl! ++:2] return 0; } :::expectation -
-function () {
- return 0; -
-} -
+function () {
+ return 0; -
+} +
-function () {
- return 0; +
-} +
+function () {
+ return 0; +
+}
:::end -
-function () {
- return 0; -
-} -
+function () {
+ return 0; -
+} +
-function () {
- return 0; +
-} +
+function () {
+ return 0; +
+}
\ No newline at end of file diff --git a/tests/fixtures/tests/files-html.txt b/tests/fixtures/tests/files-html.txt index 00b26c3..264d94d 100644 --- a/tests/fixtures/tests/files-html.txt +++ b/tests/fixtures/tests/files-html.txt @@ -118,8 +118,8 @@ resources/
blueprints/ # Partial comment
collections/
blog/ -
- post.yaml # Old name -
+ basic_post.yaml # New name +
- post.yaml # Old name +
+ basic_post.yaml # New name
art_directed_post.yaml
taxonomies/
tags/ @@ -140,8 +140,8 @@ resources/
blueprints/ # Partial comment
collections/
blog/ -
- post.yaml # Old name -
+ basic_post.yaml # New name +
- post.yaml # Old name +
+ basic_post.yaml # New name
art_directed_post.yaml
taxonomies/
tags/ diff --git a/tests/fixtures/tests/fortnite-missing-words.txt b/tests/fixtures/tests/fortnite-missing-words.txt index 8f79b9b..edc5092 100644 --- a/tests/fixtures/tests/fortnite-missing-words.txt +++ b/tests/fixtures/tests/fortnite-missing-words.txt @@ -4,10 +4,10 @@ return 2; // [tl! ~~] // Just a comment /* test [tl! ~~] */ :::expectation -
1return 1; // Add in Ziggy routes for SSR -
2return 2;
3// Just a comment -
4/* test */
+
1return 1; // Add in Ziggy routes for SSR +
2return 2;
3// Just a comment +
4/* test */
:::end -
1return 1; // Add in Ziggy routes for SSR -
2return 2;
3// Just a comment -
4/* test */
\ No newline at end of file +
1return 1; // Add in Ziggy routes for SSR +
2return 2;
3// Just a comment +
4/* test */
\ No newline at end of file diff --git a/tests/fixtures/tests/http5.txt b/tests/fixtures/tests/http5.txt index 115daf1..cc9e1ed 100644 --- a/tests/fixtures/tests/http5.txt +++ b/tests/fixtures/tests/http5.txt @@ -29,7 +29,7 @@ curl https://example.com/api/snap\
7
8curl https://example.com/api/snap?token=YOUR_TOKEN_HERE&url=https://example.com
9 -
10curl -H "Authorization: Bearer YOUR_TOKEN_HERE" http://testdomain.test/api/snap?url=https://example.com +
10curl -H "Authorization: Bearer YOUR_TOKEN_HERE" http://testdomain.test/api/snap?url=https://example.com
11
12curl https://api.stripe.com/v1/billing_portal/configurations \
13 -u sk_test_some_super_secret_but_awesome_api_key_here: \ @@ -51,7 +51,7 @@ curl https://example.com/api/snap\
7
8curl https://example.com/api/snap?token=YOUR_TOKEN_HERE&url=https://example.com
9 -
10curl -H "Authorization: Bearer YOUR_TOKEN_HERE" http://testdomain.test/api/snap?url=https://example.com +
10curl -H "Authorization: Bearer YOUR_TOKEN_HERE" http://testdomain.test/api/snap?url=https://example.com
11
12curl https://api.stripe.com/v1/billing_portal/configurations \
13 -u sk_test_some_super_secret_but_awesome_api_key_here: \ diff --git a/tests/fixtures/tests/jinja.txt b/tests/fixtures/tests/jinja.txt index 3b8c504..c629f09 100644 --- a/tests/fixtures/tests/jinja.txt +++ b/tests/fixtures/tests/jinja.txt @@ -22,7 +22,7 @@
7<body>
8 <h1>Welcome home!</h1>
9 -
- <p>age</p>
+ <p>{{ age }}</p>
12</body> +
- <p>age</p>
+ <p>{{ age }}</p>
12</body>
13</html>
:::end @@ -35,6 +35,6 @@
7<body>
8 <h1>Welcome home!</h1>
9 -
- <p>age</p>
+ <p>{{ age }}</p>
12</body> +
- <p>age</p>
+ <p>{{ age }}</p>
12</body>
13</html>
\ No newline at end of file diff --git a/tests/fixtures/tests/line-padding.txt b/tests/fixtures/tests/line-padding.txt index a557cce..3954734 100644 --- a/tests/fixtures/tests/line-padding.txt +++ b/tests/fixtures/tests/line-padding.txt @@ -33,7 +33,7 @@
8 1;
9 1;
10 1; -
11+ 1;
12 1; +
11+ 1;
12 1;
13 1;
14 1;
15 1; @@ -56,7 +56,7 @@
8 1;
9 1;
10 1; -
11+ 1;
12 1; +
11+ 1;
12 1;
13 1;
14 1;
15 1; diff --git a/tests/fixtures/tests/min-dark-has-git-diff-colors.txt b/tests/fixtures/tests/min-dark-has-git-diff-colors.txt index 46b05c0..d35c328 100644 --- a/tests/fixtures/tests/min-dark-has-git-diff-colors.txt +++ b/tests/fixtures/tests/min-dark-has-git-diff-colors.txt @@ -5,9 +5,9 @@ function () { } :::expectation
1function () { -
+ return 0;
- return 1;
4} +
+ return 0;
- return 1;
4}
:::end
1function () { -
+ return 0;
- return 1;
4} +
+ return 0;
- return 1;
4}
\ No newline at end of file diff --git a/tests/fixtures/tests/olalu-has-git-diff-colors.txt b/tests/fixtures/tests/olalu-has-git-diff-colors.txt index 8c4ad9f..f773606 100644 --- a/tests/fixtures/tests/olalu-has-git-diff-colors.txt +++ b/tests/fixtures/tests/olalu-has-git-diff-colors.txt @@ -2,6 +2,6 @@ return 1; // [tl! ++] return 1; // [tl! --] :::expectation -
+return 1;
-return 1;
+
+return 1;
-return 1;
:::end -
+return 1;
-return 1;
\ No newline at end of file +
+return 1;
-return 1;
\ No newline at end of file diff --git a/tests/fixtures/tests/one-dark-has-git-diff-colors.txt b/tests/fixtures/tests/one-dark-has-git-diff-colors.txt index b2a1907..0d535f0 100644 --- a/tests/fixtures/tests/one-dark-has-git-diff-colors.txt +++ b/tests/fixtures/tests/one-dark-has-git-diff-colors.txt @@ -5,9 +5,9 @@ function () { } :::expectation
1function () { -
+ return 0;
- return 1;
4} +
+ return 0;
- return 1;
4}
:::end
1function () { -
+ return 0;
- return 1;
4} +
+ return 0;
- return 1;
4}
\ No newline at end of file diff --git a/tests/fixtures/tests/range-negative-offset-positive-length.txt b/tests/fixtures/tests/range-negative-offset-positive-length.txt index 2e96588..9b4e611 100644 --- a/tests/fixtures/tests/range-negative-offset-positive-length.txt +++ b/tests/fixtures/tests/range-negative-offset-positive-length.txt @@ -9,14 +9,14 @@ EOT; // [tl! highlight:-3,1] :::expectation
$a = 1;
$test = <<<EOT -
1 +
1
2
3
EOT;
:::end
$a = 1;
$test = <<<EOT -
1 +
1
2
3
EOT;
\ No newline at end of file diff --git a/tests/fixtures/tests/range-positive-offset-positive-length.txt b/tests/fixtures/tests/range-positive-offset-positive-length.txt index b235e09..58e5461 100644 --- a/tests/fixtures/tests/range-positive-offset-positive-length.txt +++ b/tests/fixtures/tests/range-positive-offset-positive-length.txt @@ -7,15 +7,15 @@ $test = <<
$a = 1;
$test = <<<EOT -
1 +
$a = 1;
$test = <<<EOT +
1
2
3
EOT;
:::end -
$a = 1;
$test = <<<EOT -
1 +
$a = 1;
$test = <<<EOT +
1
2
3
EOT; diff --git a/tests/fixtures/tests/relative-double-range-2.txt b/tests/fixtures/tests/relative-double-range-2.txt index a00559a..d46dc27 100644 --- a/tests/fixtures/tests/relative-double-range-2.txt +++ b/tests/fixtures/tests/relative-double-range-2.txt @@ -8,15 +8,15 @@ steps: :::expectation
1steps: -
2 - name: Run Tests Locally
3 run: npm run test -
4 -
5 - name: Deploy to Staging -
6 uses: amondnet/vercel-action@v20 +
2 - name: Run Tests Locally
3 run: npm run test +
4 +
5 - name: Deploy to Staging +
6 uses: amondnet/vercel-action@v20
:::end
1steps: -
2 - name: Run Tests Locally
3 run: npm run test -
4 -
5 - name: Deploy to Staging -
6 uses: amondnet/vercel-action@v20 +
2 - name: Run Tests Locally
3 run: npm run test +
4 +
5 - name: Deploy to Staging +
6 uses: amondnet/vercel-action@v20
\ No newline at end of file diff --git a/tests/fixtures/tests/relative-double-range.txt b/tests/fixtures/tests/relative-double-range.txt index 15ffc08..4291222 100644 --- a/tests/fixtures/tests/relative-double-range.txt +++ b/tests/fixtures/tests/relative-double-range.txt @@ -8,13 +8,13 @@ steps: :::expectation
1steps: -
2 - name: Run Tests Locally
3 run: npm run test -
4 -
5 - name: Deploy to Staging -
6 uses: amondnet/vercel-action@v20
+
2 - name: Run Tests Locally
3 run: npm run test +
4 +
5 - name: Deploy to Staging +
6 uses: amondnet/vercel-action@v20
:::end
1steps: -
2 - name: Run Tests Locally
3 run: npm run test -
4 -
5 - name: Deploy to Staging -
6 uses: amondnet/vercel-action@v20
\ No newline at end of file +
2 - name: Run Tests Locally
3 run: npm run test +
4 +
5 - name: Deploy to Staging +
6 uses: amondnet/vercel-action@v20
\ No newline at end of file diff --git a/tests/fixtures/tests/undefined-number.txt b/tests/fixtures/tests/undefined-number.txt index 940aa18..cf305d3 100644 --- a/tests/fixtures/tests/undefined-number.txt +++ b/tests/fixtures/tests/undefined-number.txt @@ -17,7 +17,7 @@ return [
AttributesExtension::class,
// Add Torchlight syntax highlighting. -
SomeOtherHighlighter::class,
TorchlightExtension::class,
] +
SomeOtherHighlighter::class,
TorchlightExtension::class,
]
]
:::end @@ -27,6 +27,6 @@ return [
AttributesExtension::class,
// Add Torchlight syntax highlighting. -
SomeOtherHighlighter::class,
TorchlightExtension::class,
] +
SomeOtherHighlighter::class,
TorchlightExtension::class,
]
]
\ No newline at end of file diff --git a/tests/fixtures/tests/yaml-with-config.txt b/tests/fixtures/tests/yaml-with-config.txt index 12d9fdc..9e2b8a7 100644 --- a/tests/fixtures/tests/yaml-with-config.txt +++ b/tests/fixtures/tests/yaml-with-config.txt @@ -18,19 +18,19 @@ jobs: } :::expectation -
1jobs: -
2 test: +
1jobs: +
2 test:
3 runs-on: ubuntu-latest -
4 strategy: +
4 strategy:
5 matrix:
6 laravel: [ 7.*, 8.* ]
7 dependency-version: [ prefer-lowest, prefer-stable ]
:::end -
1jobs: -
2 test: +
1jobs: +
2 test:
3 runs-on: ubuntu-latest -
4 strategy: +
4 strategy:
5 matrix:
6 laravel: [ 7.*, 8.* ]
7 dependency-version: [ prefer-lowest, prefer-stable ]