Skip to content

Commit 6f8fa39

Browse files
authored
Fix #44: Add markdown support for friendly exception solutions (#57)
1 parent 46b0e05 commit 6f8fa39

File tree

9 files changed

+1048
-389
lines changed

9 files changed

+1048
-389
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Enh #55: Defer exit on terminate (rustamwin)
66
- Enh #54: Add shutdown event, fix cwd (rustamwin)
7+
- Enh #57: Add markdown support for friendly exception solutions (vjik)
78

89
## 2.0.2 February 04, 2022
910

README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ The package provides advanced error handling. The features are:
2626
- Detects response format based on mime type of the request.
2727
- Supports responding with HTML, plain text, JSON, XML and headers out of the box.
2828
- Has ability to implement your own error rendering for additional types.
29+
- [Friendly exceptions](https://github.com/yiisoft/friendly-exception/) support.
2930

3031
## Requirements
3132

@@ -194,6 +195,36 @@ In the application middleware stack `Yiisoft\ErrorHandler\Middleware\ExceptionRe
194195
For use in the [Yii framework](http://www.yiiframework.com/),
195196
see [Yii guide to handling errors](https://github.com/yiisoft/docs/blob/master/guide/en/runtime/handling-errors.md).
196197

198+
## Friendly Exceptions
199+
200+
`HtmlRenderer` supports [friendly exceptions](https://github.com/yiisoft/friendly-exception/).
201+
202+
Code blocks in solution markdown support language syntax highlight:
203+
204+
| Language | Aliases |
205+
| -------- | ------- |
206+
| Bash | bash, sh, zsh |
207+
| CSS | css |
208+
| HTML, XML | xml, html, xhtml, rss, atom, xjb, xsd, xsl, plist, svg |
209+
| JavaScript | javascript, js, jsx |
210+
| JSON | json |
211+
| PHP | php |
212+
| Plaintext | plaintext, txt, text |
213+
| SQL | sql |
214+
215+
For example:
216+
217+
````
218+
```html
219+
<html>
220+
<body>
221+
<p>This text is normal.</p>
222+
<p><b>This text is bold.</b></p>
223+
</body>
224+
</html>
225+
```
226+
````
227+
197228
## Testing
198229

199230
### Unit testing
@@ -221,9 +252,13 @@ The code is statically analyzed with [Psalm](https://psalm.dev/). To run static
221252
./vendor/bin/psalm
222253
```
223254

255+
## Credits
256+
257+
The Yii Error Handler use code of [Highlight.js](https://highlightjs.org/) by Ivan Sagalaev and other contributors.
258+
224259
## License
225260

226-
The Yii error handler is free software. It is released under the terms of the BSD License.
261+
The Yii Error Handler is free software. It is released under the terms of the BSD License.
227262
Please see [`LICENSE`](./LICENSE.md) for more information.
228263

229264
Maintained by [Yii Software](https://www.yiiframework.com/).

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"ext-dom": "*",
2626
"ext-json": "*",
2727
"alexkart/curl-builder": "^1.0",
28+
"cebe/markdown": "^1.2",
2829
"psr/container": "^1.0|^2.0",
2930
"psr/http-message": "^1.0",
3031
"psr/http-server-middleware": "^1.0",

src/Renderer/HtmlRenderer.php

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Yiisoft\ErrorHandler\Renderer;
66

77
use Alexkart\CurlBuilder\Command;
8+
use cebe\markdown\GithubMarkdown;
89
use Psr\Http\Message\ServerRequestInterface;
910
use RuntimeException;
1011
use Throwable;
@@ -49,6 +50,8 @@
4950
*/
5051
final class HtmlRenderer implements ThrowableRendererInterface
5152
{
53+
private GithubMarkdown $markdownParser;
54+
5255
/**
5356
* @var string The full path to the default template directory.
5457
*/
@@ -110,11 +113,14 @@ final class HtmlRenderer implements ThrowableRendererInterface
110113
*/
111114
public function __construct(array $settings = [])
112115
{
116+
$this->markdownParser = new GithubMarkdown();
117+
$this->markdownParser->html5 = true;
118+
113119
$this->defaultTemplatePath = dirname(__DIR__, 2) . '/templates';
114120
$this->template = $settings['template'] ?? $this->defaultTemplatePath . '/production.php';
115121
$this->verboseTemplate = $settings['verboseTemplate'] ?? $this->defaultTemplatePath . '/development.php';
116-
$this->maxSourceLines = $settings['maxSourceLines'] ?? 19;
117-
$this->maxTraceLines = $settings['maxTraceLines'] ?? 13;
122+
$this->maxSourceLines = $settings['maxSourceLines'] ?? 19;
123+
$this->maxTraceLines = $settings['maxTraceLines'] ?? 13;
118124
$this->traceHeaderLine = $settings['traceHeaderLine'] ?? null;
119125
}
120126

@@ -146,6 +152,49 @@ public function htmlEncode(string $content): string
146152
return htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
147153
}
148154

155+
public function parseMarkdown(string $content): string
156+
{
157+
$html = $this->markdownParser->parse($content);
158+
/**
159+
* @psalm-suppress InvalidArgument
160+
*
161+
* @link https://github.com/vimeo/psalm/issues/4317
162+
*/
163+
return strip_tags($html, [
164+
'h1',
165+
'h2',
166+
'h3',
167+
'h4',
168+
'h5',
169+
'h6',
170+
'hr',
171+
'pre',
172+
'code',
173+
'blockquote',
174+
'table',
175+
'tr',
176+
'td',
177+
'th',
178+
'thead',
179+
'tbody',
180+
'strong',
181+
'em',
182+
'b',
183+
'i',
184+
'u',
185+
's',
186+
'span',
187+
'a',
188+
'p',
189+
'br',
190+
'nobr',
191+
'ul',
192+
'ol',
193+
'li',
194+
'img',
195+
]);
196+
}
197+
149198
/**
150199
* Renders the previous exception stack for a given Exception.
151200
*
@@ -286,7 +335,7 @@ public function renderRequest(ServerRequestInterface $request): string
286335

287336
$output .= "\n" . $request->getBody() . "\n\n";
288337

289-
return '<pre>' . $this->htmlEncode(rtrim($output, "\n")) . '</pre>';
338+
return '<pre class="codeBlock language-text">' . $this->htmlEncode(rtrim($output, "\n")) . '</pre>';
290339
}
291340

292341
/**
@@ -303,10 +352,10 @@ public function renderCurl(ServerRequestInterface $request): string
303352
->setRequest($request)
304353
->build();
305354
} catch (Throwable $e) {
306-
$output = 'Error generating curl command: ' . $e->getMessage();
355+
return $this->htmlEncode('Error generating curl command: ' . $e->getMessage());
307356
}
308357

309-
return $this->htmlEncode($output);
358+
return '<div class="codeBlock language-sh">' . $this->htmlEncode($output) . '</div>';
310359
}
311360

312361
/**

templates/_call-stack-item.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<?php for ($i = $begin; $i <= $end; ++$i): ?><div class="hover-line"></div><?php endfor ?>
5252
<div class="code">
5353
<?php for ($i = $begin; $i <= $end; ++$i): ?><span class="lines-item"><?= (int) ($i + 1) ?></span><?php endfor ?>
54-
<pre><?php
54+
<pre class="codeBlock language-php"><?php
5555
// Fill empty lines with a whitespace to avoid rendering problems in Opera.
5656
for ($i = $begin; $i <= $end; ++$i) {
5757
echo (trim($lines[$i]) === '') ? " \n" : $this->htmlEncode($lines[$i]);

0 commit comments

Comments
 (0)