Write your own markup parser as micro building blocks.
Demos
Why bother with this ?
We all love markdown, pandoc and the likes, but sometimes we may need extra-features, or LESS features. I have been through a bunch of markdown parsers myself and found a limited choice in that you always have to choose between 100kb-I-do-not-really-need-this
libs, and 1kb-I-wish-this-existed
libs.
Markty provides a zero calory core (just a cursive function using .exec()
), then we enrich this core with some plugins that are basically a set of regex rules. Combining the core
+ the rules
= you choose your balance between size/value.
At the end of the day, this library will be useful if and only if it can gather a maximum rule
set we could pick ideas/code from.
Originally I thought about giving it as a Gist, but I think it's handy to be able to get it through npm
as well :)
So we depend on YOU !!
Let's create a shiny new Markdown rule !
Requirement: make all text surrounded by two ~
, striked-through.
e.g: ~~erase me~~
should become <s>Erase me</s>
First install, npm install markty --save
then:
import markty from 'markty'
let myString = `Please ~~erase this!~~`
let matchingRule = /(\~{2})(?!\s)((?:(?!\n\n|\s?\~).)+)(\1)/g
let businessRules = (string, match) => {
if (match[2]) {
return '<s>' + match[2] + '</s>'
}
}
let myParsedString = markty(myString, matchingRule, businessRules)
console.log(myParsedString)
Nesting
Here is where Markty starts to show its value.
By using the true
option like this:
markty(myString, matchingRule, businessRules, true)
we tell Markty to continue processing it's own output until it finds any matchingRule
's pattern again. That means it indefinitely scans the output string for all possible occurences of the matchingRule
. This is useful in nesting situations. For example:
let matchingRule = /([/*=\-_^~]{2})(?!\s)((?:(?!\n\n|\s?\1).)+)(\1)/g
We owe to do somthing with those matches, like
if a string is found enclosed by two == : surround it with <mark></mark>
if a string is found enclosed by two // : surround it with <em></em>
etc...
A business rule for this regex could look like:
let businessRules = (string, match) => {
let [token, opening, content, closing] = match, t
const TAGS = ['em', 'strong', 'mark', 's', 'u', 'sup', 'sub']
const PATTERNS = ['//', '**', '==', '--', '__', '^^', '~~']
if (content) {
t = TAGS[PATTERNS.indexOf(open)]
return `<${t}>${content}</${t}>`
}
}
Then we can use Markty to process a random string:
let myString = `
==//__**--marked italic underlined bold striked--**__//==
`
let myParsedString = markty(myString, matchingRule, businessRules)
console.log(myParsedString)
As you can see, this is not quite what we wanted: <mark>//__**--marked italic underlined bold striked--**__//</mark>
.
To let Markty parse this result again, we need to allow it so by setting the last option to true
:
let myParsedString = markty(myString, matchingRule, businessRules, true)
console.log(myParsedString)
Huray !!
Markty RE-processed the output: RE-tried the matchingRule
and RE-processed the businessRules
until no further matchingRule
was found.
Is this markdown ?
Yes and No.
If you ask: "will it be commonMark compliant ?", then "NO NEVER".
Now, yes, you can re-write some markdown rules using Markty
, and you could eventually use it as a PRE/POST-processor of any other parser: be free :)
Credits
This was HEAVILY inspired by snarkdown (big kudos to @Jason Miller).