marcco
v0.1.0
Published
turn source code into markdown
Downloads
2
Maintainers
Readme
Marcco turns your source code into markdown: comments become the main body of the text, and code becomes code blocks inside that text. This lets you generate READMEs from your source code, or program in a more literate style. Marcco is inspired by Docco.
Behaviour
Marcco is language-agnostic; it doesn't try to parse or interpret the source
code. It just reads it line by line and decides, based on whether the
commentMarker
regex matches, whether the line is prose or code. Comment
markers are removed from blocks of prose, whereas indentation is added to
blocks of code (or code fences, depending on the codePrefix
option).
So
1 + 1 == 2 // This is some code
// Now this is some prose
renders as
1 + 1 == 2 // This is some code
Now this is some prose
Source code is handled line-by-line
Marcco isn't smart enough to handle comments that "open" and "close", because it only looks at a single line to decide whether it's a comment or some code. For example,
1 + 1 == 2 // This is some code
/*
* This is still code
*/
// Now this is some prose
becomes
1 + 1 == 2 // This is some code
/*
* This is still code
*/
Now this is some prose
You can use this to your advantage when you want to control which comments become paragraphs of prose vs which should remain in the source code:
while (true) {
// do something
}
would render as the confusing
while (true) {
do something
}
so instead you could write
// This is easier to read
while (true) {
/* do something */
}
to get
This is easier to read
while (true) {
/* do something */
}
Blocks
Marcco groups consecutive comment lines into a single prose block, and consecutive lines of code into a single code block. When switching from one type of block to another, it adds a newline:
Code 1
// Prose A
Code 2
Code 3
// Prose B
// Prose C
becomes
Code 1
Prose A
Code 2
Code 3
Prose B
Prose C
Empty or blank lines don't cause a block to end, even if they're in the middle of a block of prose. They're just output as-is:
// This is prose.
// This is still the same prose block; notice the lack of extra newline.
if (a > max) {
max = a
continue // still same code block
}
gets you this markdown:
This is prose.
This is still the same prose block; notice the lack of extra newline.
if (a > max) {
max = a
continue // still same code block
}
Indentation
Marcco preserves the indentation you use in your prose blocks by removing only the prefix common to all non-blank lines in the block. So for example the following are three different ways to write the same prose block:
// Things to do today
//
// - ship
// - ship
// Oh and don't forget to ship!
or
// Things to do today
//
// - ship
// - ship
// Oh and don't forget to ship!
or
// Things to do today
//
// - ship
// - ship
// Oh and don't forget to ship!
all render as
Things to do today
- ship
- ship
Oh and don't forget to ship!
Custom comment markers
You can set the commentMarker
option to match the language you're using.
For instance, you could use /^\s*(\/\/|#)\s*/
for PHP:
// PHP supports
/* multiple */
# comment styles
to get
PHP supports
/* multiple */
comment styles
or /^\s*--\s*/
for SQL:
-- How many users registered in the last 30 days?
SELECT COUNT(*) FROM users
WHERE registered_at > CURRENT_DATE - INTERVAL '30 days';
which becomes
How many users registered in the last 30 days?
SELECT COUNT(*) FROM users
WHERE registered_at > CURRENT_DATE - INTERVAL '30 days';
Custom code prefixes
To benefit from the syntax highlighting provided by some markdown renderers,
you can set the codePrefix
option to a code fence with an info string. The above example with
codePrefix
set to '~~~sql'
would render like so:
How many users registered in the last 30 days?
~~~sql
SELECT COUNT(*) FROM users
WHERE registered_at > CURRENT_DATE - INTERVAL '30 days';
~~~
The rule is this: if codePrefix
looks like a code fence, optionally with
an info string, then Marcco will fence your code with it. Otherwise, it will
prefix every line of code with codePrefix
. So you could use e.g. '\t'
if
you would like your code prefixed with tabs rather than the default four
spaces. It doesn't make a difference to Markdown. Or you can put any string
in there, e.g. '> '
:
How many users registered in the last 30 days?
> SELECT COUNT(*) FROM users
> WHERE registered_at > CURRENT_DATE - INTERVAL '30 days';
API
Marcco gives you two ways to turn your code into Markdown: a function that works with strings, and a transform for working with streams.
code2doc(sourceCode, options = {})
sourceCode
String the source code to convertoptions
ObjectcommentMarker
RegExp lines that match this regex count as comments. Default:/^\s*\/\/\s*/
codePrefix
String the indentation or code fence to use for sections of code. Default:' '
- Returns: String
Returns the Markdown representation of the given source code.
new DocTx(options = {}, streamOptions = {})
options
Object same as the options passed tocode2doc
streamOptions
Object options to pass to the constructor of the parent class, stream.Transform
Treats its input as source code, and transforms it to markdown.
Example
const { code2doc, DocTx } = require('.')
tap.test('Example: convert a shell script to Markdown', t => {
const script =
'# Take a screenshot of a region of your screen\n' +
'maim -s ~/screenshots/$(date -Is | sed "s/:/-/g").png\n'
const markdown =
'Take a screenshot of a region of your screen\n' +
'\n maim -s ~/screenshots/$(date -Is | sed "s/:/-/g").png\n'
/* Convert a string by calling code2doc */
t.equals(code2doc(script, { commentMarker: /^\s*#\s*/ }), markdown)
/* Convert a stream by piping it to DocTx */
const tx = new DocTx({ commentMarker: /^\s*#\s*/ })
let md = ''
tx.on('data', chunk => { md += chunk })
tx.on('end', () => {
t.equals(md, markdown)
t.end()
})
tx.end(script)
})
Contributing
You're welcome to contribute to this project following the C4 process.
All patches must follow standard style and have 100% test coverage. You can make sure of this by adding
./.pre-commit
to your git pre-commit hook.