An extension for league/commonmark
to render elements specific to Obsidian.
Released under the MIT License.
- PHP 8.0.2+
Use Composer.
If you want to install this library globally to use the conversion script it provides:
composer global require elazar/league-commonmark-obsidian
If you want to install this library locally for use in your own codebase:
composer require elazar/league-commonmark-obsidian
There are three ways to use this library.
The conversion script requires only a single command to run, but offers a very minimal conversion with no options for customization. It is mainly intended to provide a minimal example of using the converter (see the next section), but can be invoked like so:
composer global exec obsidian-to-html /path/to/vault /path/to/vault/Attachments /path/to/build
/path/to/vault
is the path to the root directory of the Obsidian vault to convert to HTML/path/to/vault/Attachments
is the path to the subdirectory of the Obsidian vault that contains attachments/path/to/build
is the path to the directory to receive the converted HTML
If you want to use the extension in your own code, you can do so as follows.
$extension = new Elazar\LeagueCommonMarkObsidian\LeagueCommonMarkObsidianExtension(
vaultPath: '/path/to/Vault',
attachmentsPath: '/path/to/Vault/Attachments',
);
$environment = new League\CommonMark\Environment\Environment;
$environment->addExtension(new League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension);
$environment->addExtension($extension);
$converter = new League\CommonMark\MarkdownConverter($environment);
// Set the absolute path of the file being converted so that
// links can be resolved relative to that file
$extension->setFromPath('/path/to/Vault/Folder/File.md');
echo $converter->convert('[[Internal Link]]');
// Assuming that "Internal Link.md" is contained in the root
// directory of the vault, the above line outputs:
// <a href="../Internal Link.html">Internal Link</a>
echo $converter->convert('![[Attachment.pdf]]');
// Assuming that "Attachment.pdf" is contained in the "Attachments"
// subdirectory within the vault directory, the above line
// outputs: <img src="../Attachments/Attachment.pdf" />
The converter is a single class that can be used in your own conversion script or other code. It requires writing a bit of PHP code to use it, but offers more options for customization than the stock conversion script, such as including more extensions in the environment configuration or formatting the converted HTML.
Below is an example that adds the Strikethrough extension and a custom formatter that wraps the converted HTML in additional markup.
$vaultPath = '/path/to/vault';
$attachmentsPath = $vaultPath. '/Attachments';
$buildPath = __DIR__ . '/build';
$formatter = new class implements Elazar\LeagueCommonMarkObsidian\Formatter\FormatterInterface {
public function format(string $html, string $markdownFilePath): string {
$title = str_replace('.md', '', basename($markdownFilePath));
return <<<HTML
<!DOCTYPE html>
<html>
<head>
<title>$title</title>
</head>
<body>
<main>
$html
</main>
</body>
</html>
HTML;
}
};
$extension = new Elazar\LeagueCommonMarkObsidian\LeagueCommonMarkObsidianExtension(
$vaultPath,
$attachmentsPath,
);
$environment = new League\CommonMark\Environment\Environment([]);
$environment->addExtension(new League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension);
$environment->addExtension(new League\CommonMark\Extension\Strikethrough\StrikethroughExtension);
$environment->addExtension($extension);
$converter = new Elazar\LeagueCommonMarkObsidian\Converter;
$converter->convert($vaultPath, $attachmentsPath, $buildPath, $environment, $formatter);
In some instances, it can be helpful to be familiar with the internals of this library.
Here are some example use cases:
- If you want to contribute to this library, it's helpful to know what parts of the codebase you may need to modify to implement a given feature or fix a given bug.
- If you find a bug in this library and want to work around it, it may be possible to do so by overriding specific components of the library.
- If Obsidian adds support for a new attachment file type and you want to add support for it to this library before it's added to the library's core, you may be able to do so by adding to the embed renderers it uses.
The normal use case for LeagueCommonMarkObsidianExtension
is for it to receive a vault path and attachments path. In lieu of these, it can receive other dependencies detailed in subsequent sections of this document.
The main function of the extension is to add two inline parsers to the environment: InternalLinkParser
for internal links and EmbedParser
for embeds.
The internal link parser renders a natively supported link element. The embed parser uses its own renderers to render custom inline HTML elements, as at least some of these are not natively supported by CommonMark.
The EmbedRendererInterface
$embedRenderer
parameter of LeagueCommonMarkObsidianExtension
is used to render embeds.
The default used for $embedRenderer
is an instance of EmbedRenderer
, which extends CompositeEmbedRenderer
and composes all other renderers included in this library. It attempts to use each of these renderers in turn to render a given embed.
The LinkResolverInterface
$attachmentLinkResolver
parameter of LeagueCommonMarkObsidianExtension
is used to resolve links for embedded attachments.
The default used for $attachmentLinkResolver
is an instance of AttachmentLinkResolver
, which uses the vault and attachment paths to resolve attachment links and embeds relative to the Markdown file being rendered as HTML.
The LinkResolverInterface
$internalLinkResolver
parameter of LeagueCommonMarkObsidianExtension
is used to resolve internal links.
The default used for $internalLinkResolver
is an instance of InternalLinkResolver
, which uses the vault path to resolve internal links relative to the Markdown file being rendered as HTML.
Regardless of how you want to contribute, please start by filing an issue.
Please prefix issue titles with one of the following:
- Bug Report (if you find behavior you believe to be a bug)
- Feature Request (if you would like to suggest an addition or change to the library)
- Help Request (for everything you aren't sure about)
Doing this allows for discussion with maintainers to troubleshoot problems, confirm bugs, or determine how best to make suggested features work.
In cases where you wish to contribute code, this discussion may help to clarify your implementation approach and reduce potential rework required on your part to get your contribution merged.
Help requests are closed once they are resolved or if they are inactive for 30 days. Other issues are left open until either a related PR is merged or a formal decision is made by the maintainers that no further action will be taken.
Once consensus is reached on a bug or feature implementation approach, file a PR using a branch with a name prefixed with either bug/
or feature/
for a bug report or feature request respectively.
Please be sure to reference the original issue you filed in your PR description to provide context for the changes.