Page Parsing
Parse different types of content.
jaspr_content
allows you to parse content from different files using a system of PageParser
objects. Each parser is responsible for handling specific file types (like markdown or HTML) and converting them into a tree of nodes that Jaspr can render.
To use parsers, add them to your ContentApp
:
ContentApp(
parsers: [
MarkdownParser(),
HtmlParser(),
],
)
With this configuration, you can mix markdown and HTML files in your content directory. For example:
content/
โโโ index.html
โโโ about.md
โโโ posts/
โโโ index.md
โโโ post1.html
โโโ post2.md
When a page is requested, jaspr_content
will select the appropriate parser based on the file extension and use it to parse the content.
MarkdownParser
The MarkdownParser
handles files with .md
or .mdx
extensions. It uses the markdown
package to parse Markdown content into nodes.
Customizing Markdown Parsing
The parser takes an optional documentBuilder
function, which you can use to customize the markdown parsing by defining a custom markdown Document
:
import 'package:markdown/markdown.dart' as md;
[...]
MarkdownParser(
documentBuilder: (Page page) {
return md.Document(
// specify any custom syntaxes, extension sets etc. here
blockSyntaxes: [
// Add your custom block syntaxes
],
inlineSyntaxes: [
// Add your custom inline syntaxes
],
extensionSet: md.ExtensionSet.gitHubFlavored,
);
}
)
By default, the MarkdownParser
uses the GitHub Web extension set and adds support for the component block syntax, which allows you to use Jaspr components in your markdown.
If you want to keep supporting Custom Components in your markdown files, make sure to use the ComponentBlockSyntax()
as part of your custom configuration.
HtmlParser
The HtmlParser
handles files with .html
extensions. It uses the html
package to parse HTML content into nodes.
ContentApp(
parsers: [
HtmlParser(),
],
)
This allows you to write direct HTML content:
<!-- content/page.html -->
<div class="container">
<h1>Welcome to my site</h1>
<p>This is a paragraph with <strong>bold text</strong>.</p>
</div>
Like with markdown, you can also use custom components in HTML files:
<div class="container">
<Info>
This is an info box component.
</Info>
</div>
Creating Custom Parsers
You can create your own parser by implementing the PageParser
interface. This lets you add support for other file types or custom formats.
class CustomParser implements PageParser {
@override
Pattern get pattern => RegExp(r'.*\.custom$'); // Match files with .custom extension.
@override
List<Node> parsePage(Page page) {
// Parse the content into nodes.
// This is where you convert your custom format into Jaspr's Node structure.
final nodes = <Node>[];
// Example: Converting a simple custom format.
final lines = page.content.split('\n');
for (final line in lines) {
if (line.startsWith('# ')) {
// Create a heading element.
nodes.add(ElementNode('h1', {}, [TextNode(line.substring(2))]));
} else if (line.isNotEmpty) {
// Create a paragraph element.
nodes.add(ElementNode('p', {}, [TextNode(line)]));
}
}
return nodes;
}
}
Then add your custom parser to your ContentApp
:
ContentApp(
parsers: [
CustomParser(),
MarkdownParser(),
HtmlParser(),
],
)
Understanding Nodes
When implementing a custom parser, you'll need to create a tree of nodes that represent the content. Jaspr provides three types of nodes:
TextNode
: Represents text content.ElementNode
: Represents an element with a tag, attributes, and children.ComponentNode
: Represents a Jaspr component.
A parser should usually only create TextNode
s and ElementNode
s. The ComponentNode
type is meant for extensions or custom components.
For example, the following nodes represent a simple paragraph element:
ElementNode('p', {'class': 'intro'}, [
TextNode('This is a '),
ElementNode('strong', {}, [TextNode('paragraph')]),
TextNode(' with styling.'),
])
This would be rendered as:
<p class="intro">This is a <strong>paragraph</strong> with styling.</p>
Parser Selection
When a content file is loaded, Jaspr selects the appropriate parser based on the file path and the parser's pattern
. The first parser with a pattern that matches the file path is used to parse the content.
Patterns are checked in the order the parsers are added to the ContentApp
, so put more specific parsers before more general ones.
When implementing a custom parser, make sure your pattern is specific enough to only match the files you want to parse. The pattern is checked against the full file path, not just the extension.