You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/3-packages/04-markdown.md
+227-5Lines changed: 227 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@ title: Markdown
3
3
description: "Fast and extensible Markdown in PHP"
4
4
---
5
5
6
-
`tempest/markdown` is a Markdown parser written in PHP. It's designed to be fast and extensible and has a bunch of additional features built-in like code highlighting, responsive images, tables, and frontmatter support.
6
+
`tempest/markdown` is a Markdown parser for server-side Markdown parsing with PHP. It's designed to be fast and extensible, and has a bunch of extended Markdown features built-in like code highlighting, table and div support, responsive images, and frontmatter support.
One thing that sets `tempest/markdown` apart from other Markdown implementations is that it comes with a bunch of extended features built-in.
28
30
29
31
### Code highlighting
30
32
@@ -41,7 +43,7 @@ $markdown = new Markdown(
41
43
);
42
44
```
43
45
44
-
Language definitions work in both inline and pre code blocks:
46
+
Language definitions work for both inline and multiline code blocks:
45
47
46
48
<pre>
47
49
This is an inline PHP codeblock: `{php}echo "Hello";`
@@ -63,9 +65,28 @@ $markdown = new Markdown(
63
65
);
64
66
```
65
67
68
+
### Frontmatter
69
+
70
+
Add frontmatter like you're used to with other Markdown parsers
71
+
72
+
```md
73
+
---
74
+
title: Markdown
75
+
description: "Fast and extensible Markdown in PHP"
76
+
---
77
+
78
+
`tempest/markdown` is a Markdown parser for server-side Markdown parsing with PHP. It's designed to be fast and extensible, and has a bunch of extended Markdown features built-in like code highlighting, table and div support, responsive images, and frontmatter support.
79
+
```
80
+
81
+
```php
82
+
$parsed = $markdown->parse($contents);
83
+
84
+
echo $parsed->frontmatter['title'];
85
+
```
86
+
66
87
### Responsive images
67
88
68
-
`tempest/markdown` has support for responsive images powered by [`tempest/responsive-image`](/docs/packages/responsive-image). You'll need to configure the responsive image factory before being able to use it.
89
+
`tempest/markdown` has support for responsive images powered by [`tempest/responsive-image`](/docs/packages/responsive-image). You'll need to configure the responsive image factory to enable this feature.
69
90
70
91
```php
71
92
use Tempest\Markdown\Markdown;
@@ -82,6 +103,207 @@ $markdown = new Markdown(
82
103
);
83
104
```
84
105
106
+
When enabled, `tempest/markdown` will generate different versions of the same image, and add them as `srcset` entries in the generate HTML.
`tempest/markdown` is meant to be extended. Adding custom parser rules is done in two steps: first you provide a `LexerRule`, this is a class that determines when your custom parsing logic should be triggered. Next you'll use a `Token` to render your selected Markdown code in any way you'd like.
201
+
202
+
Let's work with an example. Say you want to add support for including custom HTML snippets. It could look something like this:
203
+
204
+
```
205
+
Hello world
206
+
207
+
{{ snippets/call-to-action.html }}
208
+
```
209
+
210
+
The first step to adding this new feature is detecting when we run into our custom `{{ }}` syntax. This is done with a `LexerRule`. Let's call our implementation `SnippetRule`:
211
+
212
+
```php
213
+
use Tempest\Markdown\Lexer;
214
+
use Tempest\Markdown\Rule;
215
+
use Tempest\Markdown\Token;
216
+
217
+
final readonly class SnippetRule implements Rule
218
+
{
219
+
public function shouldLex(Lexer $lexer): bool
220
+
{
221
+
// Our rule takes effect as soon as we run into `{{`
222
+
223
+
return $lexer->comesNext('{{', length: 2);
224
+
}
225
+
226
+
public function lex(Lexer $lexer): ?Token
227
+
{
228
+
// We'll consume all { characters
229
+
$lexer->consumeWhile('{');
230
+
231
+
// Then we'll consume and store the snippet path itself until we encounter the closing } characters
232
+
$snippet = $lexer->consumeUntil('}');
233
+
234
+
// Then we'll consume the closing } characters
235
+
$lexer->consumeWhile('}');
236
+
237
+
// Finally, we return a token with the snippet
238
+
return new SnippetToken(trim($snippet));
239
+
}
240
+
}
241
+
```
242
+
243
+
:::info
244
+
For performance reasons, it's best to explcitly add the `{:hl-property:length:}` parameter to the `{:hl-property:comesNext:}` call. It's not required, but it will make parsing faster. If possible, also try not to rely on regex within your lexer rules, as it may become a performance bottleneck.
245
+
:::
246
+
247
+
So that's our rule implementation: we consumed our custom `{{ path }}` syntax, and created a token with that path. Let's take a look at the token implementation next.
248
+
249
+
The token's responsibility is to parse the content into HTML.
250
+
251
+
```php
252
+
use Tempest\Markdown\Parser;
253
+
use Tempest\Markdown\Token;
254
+
use Tempest\View\Exceptions\ViewNotFound;
255
+
use Tempest\View\ViewRenderer;
256
+
use function Tempest\Container\get;
257
+
258
+
final readonly class SnippetToken implements Token
259
+
{
260
+
public function __construct(
261
+
public string $path,
262
+
) {}
263
+
264
+
public function parse(Parser $parser): string
265
+
{
266
+
// Of course, you should add validation here depending on your use case
267
+
268
+
return file_get_contents($this->path);
269
+
}
270
+
}
271
+
```
272
+
273
+
Finally, you should add your custom rule to the Markdown parser:
274
+
275
+
```php
276
+
use Tempest\Markdown\Markdown;
277
+
278
+
$markdown = new Markdown();
279
+
280
+
$markdown->prependRules(
281
+
new SnippetRule(),
282
+
);
283
+
```
284
+
285
+
If needed, you can fully customize the Markdown parser by overwriting all rules:
286
+
287
+
```php
288
+
$markdown = new Markdown()->withRules(
289
+
new NewLineRule(),
290
+
new FrontMatterRule(),
291
+
new HeadingRule(),
292
+
new QuoteRule(),
293
+
new PreRule(),
294
+
new DivRule(),
295
+
new ThinRulerRule(),
296
+
new ThickRulerRule(),
297
+
new ListRule(),
298
+
new OrderedListRule(),
299
+
new TableRule(),
300
+
new HtmlRule(),
301
+
new ParagraphRule(),
302
+
);
303
+
```
304
+
305
+
This way you have full control over how the parser works. For more inspiration, you can look at the [rules that come built-in with the package](https://github.com/tempestphp/markdown/tree/main/src/LexerRules).
306
+
85
307
## Performance
86
308
87
309
This package began as a challenge to make a more performant Markdown parser in pure PHP. The primary performance gain is from not relying on regex but instead using a simple lexer to tokenize Markdown files and convert them to HTML.
@@ -90,7 +312,7 @@ Benchmarks are included in this repo and can be run with `composer bench` after
0 commit comments