Embeddable code snippets derived from source files for jaspr_content
, with
support for semantic tokens.
Motivation
When writing documentation sites for larger projects, a common challenge is ensuring code snippets on the site are up-to-date. When code snippets are directly embedded in Markdown, this is quite hard to do: Every time an API is changed, you'd have to remember to update relevant snippets.
For sites built with jaspr_content
, this package offers an alternative: You
write Dart snippets as regular .dart
files into lib/
, meaning that they'd
get analyzed and that you can write tests ensuring they do what they're
supposed to do.
Then, you use a custom component provided by this package to show highlighted code.
A rendered demo of this package is available on my website.
Features
This package can generate excerpts from snippets for all languages and leave the user responsible for highlighting code. However, it also comes with dedicated support for the following languages:
- Dart: Source snippets are resolved to add support for semantic tokens,
resulting in improved syntax highlighting.
Additionally, the package can generate hyperlinks to generated
dart doc
pages for your projects. - SQL: Uses the
sqlparser
package for accurate syntax highlighting.
Note that this is a fairly low-level package designed for use in drift's documentation website. Feedback and PRs to make it more generally useful are definitely welcome though.
Getting started
To get started, apply the jaspr_content_snippets
builder to a target
containing snippets you want to extract.
For instance, if you have snippets in lib/src/snippets/
, you could write a
build.yaml
with:
targets:
$default:
builders:
jaspr_content_snippets:
enabled: true
options:
process_without_directives: true
generate_for:
- lib/src/snippets/**
By default, the builder will only process files that have at least one
#docregion
comment in them (see usage).
The process_without_directives
disables this rule.
Usage
This package exports three steps, some of which are optional:
- Mark some packages as targets for links when their APIs are used in snippets.
- Enable the snippets builder to extract snippets.
- Use a jaspr component to render snippets.
These steps are fairly modular, so you can replace them with your own logic where that makes sense.
Linking APIs
To link Dart identifiers and import URIs to their dart doc
pages, configure
the jaspr_content_snippets:api_index
builder to include those packages. Since
that builder runs on all packages, it's easier to configure it with a
global_options
entry in build.yaml
:
global_options:
"jaspr_content_snippets:api_index":
options:
packages: ['your_package', 'another_one']
To link to SDK documentation (api.dart.dev
), include the synthetic $sdk
package
in that list.
Extracting snippets
The snippets builder will, for each source file it's running on, generate a
.snippet.json
encoding
- Line ranges for
#docregion
and#enddocregion
pairs. - If the language is known (SQL and Dart are built-in to this package), tokens
encoded as
(offset, length)
keys with their semantic token identifier as specified in the LSP protocol. - Raw HTML consisting of
<span>
s for known tokens.
To generate the snippets, enable the builder:
targets:
$default:
builders:
jaspr_content_snippets:
enabled: true
options:
process_without_directives: true
generate_for:
- lib/src/snippets/**
Rendering snippets
Loading extracted snippets is somewhat tricky, since they're generated as hidden build files.
This package offers the jaspr_content_snippets:combiner
builder generating a
single generated_snippets.dart
file encoding all snippets.
The target path of that file can be customized:
targets:
$default:
builders:
jaspr_content_snippets:combiner:
options:
path: lib/generated_snippets.dart
This file can then be used in a jaspr_content
pipeline by registering it as a custom
component:
components: [
// ...
renderedSnippetComponent(snippets: generatedSnippets),
],
With that set up, you can use the <Snippet href="/lib/src/your_snippet.dart" name="region" />
tag to reference a snippet.
To render snippets you only have available as sources, use the HighlightBlock
component
or the builtin BetterCodeBlock
component which serves as a drop-in replacement for
CodeBlock
:
import 'package:jaspr_content/jaspr_content.dart';
import 'package:jaspr_content_snippets/jaspr_content_snippets.dart';
final root = ContentApp.custom(
// ...
configResolver: PageConfig.all(
// ...
components: [
BetterCodeBlock(),
renderedSnippetComponent(snippets: generatedSnippets),
// ...
],
),
);
Additional information
This package embeds parts of analysis_server
source code from the SDK.
That code imports internal analyzer
and _fe_analyzer_shared
APIs making this package somewhat
unstable.
Styling
This package does not use @style
annotations, nor does it ship with default styles for code
highlighting.
To get started quickly, consider adding this to your project's style:
@use "package:jaspr_content_snippets/common";
@use "package:jaspr_content_snippets/dracula" as dracula;
:root {
@include dracula.light;
}
@media (prefers-color-scheme: dark) {
:root {
@include dracula.dark;
}
}
Updating analyzer sources
The lib/src/highlight/dart/computer_highlights.dart
file is taken from the Dart SDK,
with some patches related to this package.
To update that file, copy it over and git apply assets/computer_highlights.patch
.
Libraries
- builders
- internal/client
- Client code this package contributes to jaspr websites.
- jaspr_content_snippets