A marked extension to support directives syntax.
You can install marked-directive
using npm or yarn:
npm i marked-directive
# or
yarn add marked-directive
Say we have the following file example.md
:
# Example
:::main{#foo .bar class="baz" .qux}
[Directives syntax](https://talk.commonmark.org/t/generic-directives-plugins-syntax/444)
::hr{.border-muted}
You can use :i[CSS] (Cascading Style Sheets) to style your :abbr[HTML]{title="HyperText Markup Language"}.
:::
And our module example.js
looks as follows:
import { readFileSync } from 'node:fs'
import { Marked } from 'marked'
import { createDirectives } from 'marked-directive'
const html = new Marked()
.use(createDirectives())
.parse(readFileSync('example.md', 'utf8'))
console.log(html)
Now, running node example.js
yields:
<h1>Example</h1>
<main id="foo" class="bar baz qux">
<p>
<a
href="https://talk.commonmark.org/t/generic-directives-plugins-syntax/444"
>Directives syntax</a
>
</p>
<hr class="border-muted" />
<p>
You can use <i>CSS</i> (Cascading Style Sheets) to style your
<abbr title="HyperText Markup Language">HTML</abbr>.
</p>
</main>
The marked-directive
extension accepts a set of custom configurations for your directives. You can specify how the directives are identified, how they should be rendered, and other behavior. The options include:
-
level
: The level of the directive, which can be'container'
,'block'
, or'inline'
. This determines where the directive can be used. -
marker
: The marker string that identifies the directive in the source text. -
tag
: An optional HTML tag that the directive should be rendered as. If not provided, the default tag is used based on the directive level. -
renderer
: A custom rendering function for the directive. This function can be used to customize how the directive is rendered.
Here's an example of custom options:
Say we have the following markdown code:
Custom directives:
::youtube[Dummy video]{vid="9xwazD5SyVg"}
1. @bent10
2. #markdown
3. :emoji[rocket]{title="Go!"}
And whatever is on your mind 🤯.
import { Marked } from 'marked'
import {
createDirectives,
presetDirectiveConfigs,
type DirectiveConfig
} from 'marked-directive'
// defines `:youtube` directive
const youtubeDirective: DirectiveConfig = {
level: 'block',
marker: '::',
renderer(token) {
if (token.meta.name === 'youtube') {
return `<iframe width="560" height="315" src="https://www.youtube.com/embed/${
token.attrs?.vid || ''
}" title="${
token.text
}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>`
}
return false
}
}
// defines `@mention` directive
const mentionDirective: DirectiveConfig = {
level: 'inline',
marker: '@',
renderer(token) {
return `<a class="user-mention notranslate" href="/users/${token.meta.name}">${token.meta.name}</a>`
}
}
// defines `#hashtag` directive
const hashtagDirective: DirectiveConfig = {
level: 'inline',
marker: '#',
renderer(token) {
return `<a class="hashtag" href="/tags/${token.meta.name}">${token.meta.name}</a>`
}
}
// defines `:emoji` directive
const emojis = { rocket: '🚀', 'red-exclamation': '❗' } // mock emoji api
const emojiDirective: DirectiveConfig = {
level: 'inline',
marker: ':',
renderer(token) {
if (token.meta.name === 'emoji') {
return `<span ${token.attrs?.toString()}>${emojis[token.text]}</span>`
}
return false
}
}
const html = new Marked()
.use(
createDirectives([
...presetDirectiveConfigs,
youtubeDirective,
mentionDirective,
hashtagDirective,
emojiDirective
])
)
.parse(md)
console.log(html)
When working with nested directives, it’s important to ensure proper distinction between different levels of nesting. If both the container and its nested items use the same marker character (e.g., :
), the number of marker characters should increment with each level of nesting to avoid conflicts and ensure correct parsing.
For example, in the following Markdown snippet, the .container
uses four colons (::::
) to define its boundaries, while the nested .item
uses three colons (:::
):
::::{.container}
:::{.item}
Title
Description
![Image](/image.jpg)
:::
::::
Alternatively, you can also use different markers for each level. For example, the .container
uses colons (:::
), and the .item
uses plus signs (+++
):
:::{.container}
+++{.item}
### Title
Content ![Image](/image.jpg), with code:
```python
num1 = 5
num2 = 3
sum = num1 + num2
print(f"The sum of {num1} and {num2} is {sum}")
```
+++
:::
To handle these custom markers, set up the directives like this:
import { Marked } from 'marked'
import { createDirectives, presetDirectiveConfigs } from 'marked-directive'
const md = `` // markdown above
const html = new Marked()
.use(
createDirectives([
...presetDirectiveConfigs,
// custom directives
{ level: 'container', marker: '::::' },
{ level: 'container', marker: '\\+\\+\\+' }
])
)
.parse(md)
console.log(html)
See extensions list.
We 💛 issues.
When committing, please conform to the semantic-release commit standards. Please install commitizen
and the adapter globally, if you have not already.
npm i -g commitizen cz-conventional-changelog
Now you can use git cz
or just cz
instead of git commit
when committing. You can also use git-cz
, which is an alias for cz
.
git add . && git cz
A project by Stilearning © 2023-2024.