A sensible Markdown parser for javascript
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Advanced markdown processing with full control over parsing stages, dialect customization, and block-level processing.
Create a new Markdown processor instance with specified dialect.
/**
* Create new Markdown processor instance
* @param {string|Object} dialect - Dialect name ("Gruber", "Maruku") or dialect object
* @constructor
* @throws {Error} When dialect is unknown
*/
function Markdown(dialect);Usage Examples:
var { Markdown } = require("markdown").markdown;
// Create with default Gruber dialect
var md = new Markdown();
// Create with specific dialect
var md = new Markdown("Maruku");
// Create with custom dialect object
var customDialect = {
block: { /* custom block rules */ },
inline: { /* custom inline rules */ }
};
var md = new Markdown(customDialect);
// Error handling
try {
var md = new Markdown("UnknownDialect");
} catch (e) {
console.log(e.message); // "Unknown Markdown dialect 'UnknownDialect'"
}Parse source into JsonML markdown tree with optional custom root node.
/**
* Parse source into JsonML markdown tree
* @param {string|Array} source - Markdown source text or block array from split_blocks()
* @param {Array} custom_root - Custom root node (optional, default: ["markdown"])
* @returns {Array} JsonML markdown tree
*/
Markdown.prototype.toTree = function(source, custom_root);Usage Examples:
var md = new Markdown();
// Basic parsing
var tree = md.toTree("Hello **World**!");
// Returns: ["markdown", {}, ["para", {}, "Hello ", ["strong", {}, "World"], "!"]]
// With custom root
var tree = md.toTree("Hello World", ["custom_root"]);
// Returns: ["custom_root", "Hello World"]
// Processing pre-split blocks
var blocks = md.split_blocks("# Header\n\nParagraph");
var tree = md.toTree(blocks);Process individual block element and return JsonML nodes.
/**
* Process individual block and return JsonML nodes
* @param {string} block - Block content to process (enhanced string with metadata)
* @param {Array} next - Array of following blocks for lookahead processing
* @returns {Array} Array of JsonML nodes representing the processed block
*/
Markdown.prototype.processBlock = function(block, next);Usage Examples:
var md = new Markdown();
// Process single block
var blocks = md.split_blocks("# Header\n\nParagraph");
var headerResult = md.processBlock(blocks[0], blocks.slice(1));
// Returns: [["header", { level: 1 }, "Header"]]
// Process with context (for lists, blockquotes, etc.)
var blocks = md.split_blocks("- Item 1\n- Item 2");
var listResult = md.processBlock(blocks[0], blocks.slice(1));
// Returns array with bulletlist JsonMLProcess inline content within a block using dialect inline rules.
/**
* Process inline content within a block
* @param {string} block - Block content to process for inline elements
* @returns {Array} Array of processed inline content (strings and JsonML nodes)
*/
Markdown.prototype.processInline = function(block);Usage Examples:
var md = new Markdown();
// Process inline elements
var result = md.processInline("Hello **bold** and *italic* text");
// Returns: ["Hello ", ["strong", {}, "bold"], " and ", ["em", {}, "italic"], " text"]
// Process links and images
var result = md.processInline("Visit [link](http://example.com) and see ");
// Returns: ["Visit ", ["link", { href: "http://example.com" }, "link"], " and see ", ["img", { alt: "image", href: "img.jpg" }]]Split input text into block-level chunks with metadata.
/**
* Split input into block-level chunks with metadata
* @param {string} input - Markdown input text
* @param {number} startLine - Starting line number for tracking (optional)
* @returns {Array} Array of enhanced block strings with trailing and lineNumber properties
*/
Markdown.prototype.split_blocks = function(input, startLine);Usage Examples:
var md = new Markdown();
// Split markdown into blocks
var blocks = md.split_blocks("# Header\n\nParagraph\n\n Code block");
console.log(blocks.length); // 3
// Each block has metadata
console.log(blocks[0].toString()); // "# Header"
console.log(blocks[0].trailing); // "\n\n"
console.log(blocks[0].lineNumber); // 1
console.log(blocks[1].toString()); // "Paragraph"
console.log(blocks[1].trailing); // "\n\n"
console.log(blocks[1].lineNumber); // 3Debug logging method for development and troubleshooting.
/**
* Debug logging method (noop by default)
* @param {...*} args - Variable arguments for logging
* @returns {undefined}
*/
Markdown.prototype.debug = function(/* ...args */);Usage Examples:
var md = new Markdown();
// Debug output (if print or console.log available)
md.debug("Processing block:", blockContent);
// Enable custom debug output
md.debug = function() {
var args = Array.prototype.slice.call(arguments);
console.log("MARKDOWN DEBUG:", args.join(" "));
};Apply regular expression repeatedly over block content with callback processing.
/**
* Apply regex repeatedly over block with callback
* @param {RegExp} re - Regular expression to apply (should not use /g flag)
* @param {string} block - Block content to process
* @param {Function} cb - Callback function called for each match
* @returns {string} Remaining block content after processing
*/
Markdown.prototype.loop_re_over_block = function(re, block, cb);Usage Examples:
var md = new Markdown();
// Extract all reference definitions
var references = [];
var remaining = md.loop_re_over_block(
/^\s*\[(.*?)\]:\s*(\S+)/,
"[ref1]: http://example.com\n[ref2]: http://test.com\nOther content",
function(match) {
references.push({ id: match[1], href: match[2] });
}
);
console.log(references); // [{ id: "ref1", href: "http://example.com" }, ...]
console.log(remaining); // "Other content"/**
* Markdown instance properties
* @property {Object} dialect - The dialect object containing block and inline rules
* @property {Array} em_state - State tracking for emphasis processing
* @property {Array} strong_state - State tracking for strong emphasis processing
* @property {string} debug_indent - Indentation string for debug output
* @property {Array} tree - Current markdown tree being built (during toTree processing)
*/var md = new Markdown();
// Override or extend block processing
var originalProcessBlock = md.processBlock;
md.processBlock = function(block, next) {
// Custom preprocessing
if (block.match(/^CUSTOM:/)) {
return [["custom_block", {}, block.substr(7)]];
}
// Fallback to original processing
return originalProcessBlock.call(this, block, next);
};
var tree = md.toTree("CUSTOM: Special content\n\nNormal paragraph");var md = new Markdown();
// Access internal state during processing
var originalProcessInline = md.processInline;
md.processInline = function(block) {
console.log("Em state:", this.em_state);
console.log("Strong state:", this.strong_state);
return originalProcessInline.call(this, block);
};
var result = md.processInline("**Bold *and italic* text**");