remark-ast-inline
An experimental package for adding nodes and values to a abstract syntax tree from template expressions, via a unified parser of the kind exposed by remark.
Usage
Import
import rai from 'remark-ast-express'
Configure
const md = rai({
converter // Optional
})
function converter(value) {
return { type: 'value', value: value }
}
The converter function is called (if present) with all the expressions that would be inserted into your template string. It can return either an unist node (an object with a type
field containing a string) to later be inserted into the AST or a value to be inserted into the string. For example, to make this package completely useless:
function converter(value) {
return String(value) // Can't just be `return value` or nodes would still be inserted.
)
Process Text
let { string, astInserter } = md`\
# This is some markdown...
I'm going to insert a value into the AST riiight ${"foobar"}here.
${{
type: 'strong',
children: [{type: 'text', value: 'not here'}]
}}
`
import remark from 'remark'
let tree = remark()
.use(...others...)
.use(astInserter) // The plugin returned above should be last
.parse(string) // The exact(!) string returned above
Gives:
{
"type": "root",
"children": [
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "This is some markdown...",
"position": ...
}
],
"position": ...
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "I'm going to insert a value into the AST riiight ",
"position": ...
},
{
"type": "value",
"value": "foobar",
"position": ...
},
{
"type": "text",
"value": "here.",
"position": ...
}
],
"position": ...
},
{
"type": "paragraph",
"children": [
{
"type": "value",
"value": {
"type": "strong",
"children": [
{
"type": "text",
"value": "not here"
}
]
},
"position": ...
}
],
"position": ...
}
],
"position": ...
}
Or, with no converter:
{
"type": "root",
"children": [
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "This is some markdown...",
"position": ...
}
],
"position": ...
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "I'm going to insert a value into the AST riiight foobarhere.",
"position": ...
}
],
"position": ...
},
{
"type": "paragraph",
"children": [
{
"type": "strong",
"children": [
{
"type": "text",
"value": "not here"
}
],
"position": ...
}
],
"position": ...
}
],
"position": ...
}
WTF? Why?
Well, this gives you a nice(ish) syntax in vanilla Javascript for programmatically inserting nodes into the AST inline; which might be useful...? I'm considering using it to implement a React/JS+Markdown website templating framework; it was the least awkward way to hack something together that I may like more than the alternatives (e.g. MDX).
How?
The code inserts tokens of the form <[prefix]:[index]>
into the string, where the prefix is a random alphabetic (upper and lower) string that occurs nowhere else in the string (same across the tokens) and the index corresponds to which node should be inserted there. A prefix
string and nodes
array fields are included in the tag function output.