jsdotmd takes all JavaScript inline code tags from Github Flavored Markdown file and compiles them into JavaScript file.
You can use it if you want to write extensive code documentation. See Literate programming
I wanted to make a language, whose compiler is written on itself
and is also its README
.
Just for fun.
Install the package globally:
npm install --global jsdotmd
# or
yarn global add jsdotmd
After installing, use the following syntax:
jsdotmd [source file] [destination file]
Install the package locally:
npm install --save jsdotmd
# or
yarn add jsdotmd
import {parse} from 'jsdotmd'
const src = []
.concat('# Hello, Markdown!')
.concat('```javascript')
.concat('console.log("Hello, JavaScript!")')
.concat('```')
.join('\n')
const result = parse(source)
//=> 'console.log("Hello, JavaScript!")'
Since working with JavaScript code in Markdown code tags in JavaScript strings is a bit messy, you can also use file-to-file compiler:
import path from 'path'
import {compile} from 'jsdotmd'
const sourcePath = path.join(__dirname, 'index.js.md')
const destinationPath = path.join(__dirname, 'index.js')
compile(sourcePath, destinationPath)
.catch((err) => console.log('Something went wrong!', err))
The code is very simple.
It uses only two dependencies:
-
marked
for parsing Markdown source file. We don't need the HTML output, so we use only lexer.const {lexer} = require('marked')
-
fs-promise
to work with the file system easier.const fs = require('fs-promise')
By default, jsdotmd compiles into JavaScript code only those Markdown inline code tags,
which are marked javascript
, js
or node
.
const defaultLangCodes = ['javascript', 'js', 'node']
From CLI, you can specify tags like this:
jsdotmd [source file] [destination file] -l js,javascript,node,jsx,typescript
function parse (source, options) {
options = options || {}
const langCodes = options.langCodes || defaultLangCodes
const separator = options.separator || '\n\n'
parse
function joins code blocks using separator
specified in the second argments options
which is two line breaks by default.
const tokens = lexer(source)
Lexer returns an array of tokens. We are only interested in tokens with type 'code'
.
They look like this:
{
type: 'code',
lang: 'javascript',
text: ' const tokens = lexer(source)'
}
Next we filter only the tokens we need, retrieve text from them and join them with a separator.
const code = tokens
.filter(({type, lang}) => type === 'code' && langCodes.includes(lang))
.map(({text}) => text)
.join(separator)
return code
}
Compile function is even simpler. It just reads file, specified in the first argument,
parses it with parse
and writes it to file, specified in the second argument. Done!
function compile (sourcePath, destinationPath, options) {
options = options || {}
const encoding = options.encoding || 'utf-8'
return fs.readFile(sourcePath, {encoding})
.then((contents) => parse(contents, options))
.then((code) => fs.writeFile(destinationPath, code, {encoding}))
}
jsdotmd exports both parse
and compile
functions for you to use.
module.exports = {parse, compile}
It uses commander
.
Check bin/jsdotmd.js
.
I haven't written it in jsdotmd for simplicity.
Run npm run build
. It compiles README.md
into lib/index.js
.
Run npm test
. It runs npm run build
two times. If the compiler compiles itself after the recompiling,
it probably works. If not, well, no luck.
Probably not.
Thank you.