From a1bc760fef3ae9e98f039fa50f31fc2d5eb877a2 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 9 Jan 2015 19:10:24 -0800 Subject: Added options to render, implemented sourcepos option. This adds data-sourcepos attributes on block-level tags in the HTML output. Also added `--sourcepos` command-line option to `js/bin/commonmark`. --- js/bin/commonmark | 27 +++++++++++++++++---------- js/lib/html.js | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/js/bin/commonmark b/js/bin/commonmark index ac53e6e..72ad344 100755 --- a/js/bin/commonmark +++ b/js/bin/commonmark @@ -6,19 +6,26 @@ var util = require('util'); var commonmark = require('../lib/index.js'); var parser = new commonmark.DocParser(); -var renderer; +var renderer = new commonmark.HtmlRenderer(); var inps = []; var file; var files = []; +var options = { sourcepos: false, }; -if (process.argv[2] === '--ast') { - files = process.argv.slice(3); - renderer = { render: function(x) { - return util.inspect(x.toAST(), null, Infinity, true) + '\n'; - } }; -} else { - files = process.argv.slice(2); - renderer = new commonmark.HtmlRenderer(); +for (var i = 2; i < process.argv.length; i++) { + var arg = process.argv[i]; + if (arg == '--ast') { + renderer = { render: function(x) { + return util.inspect(x.toAST(), null, Infinity, true) + '\n'; + } }; + } else if (arg == '--sourcepos') { + options.sourcepos = true; + } else if (/^--/.test(arg)) { + process.stderr.write('Unknown option ' + arg + '\n'); + process.exit(1); + } else { + files.push(arg); + } } if (files.length === 0) { @@ -30,4 +37,4 @@ for (var i = 0; i < files.length; i++) { inps.push(fs.readFileSync(file, 'utf8')); } -process.stdout.write(renderer.render(parser.parse(inps.join('\n')))); +process.stdout.write(renderer.render(parser.parse(inps.join('\n')), options)); diff --git a/js/lib/html.js b/js/lib/html.js index 57f87e5..ca5b477 100644 --- a/js/lib/html.js +++ b/js/lib/html.js @@ -1,12 +1,12 @@ "use strict"; // Helper function to produce an HTML tag. -var tag = function(name, attribs, selfclosing) { +var tag = function(name, attrs, selfclosing) { var result = '<' + name; - if (attribs) { + if (attrs && attrs.length > 0) { var i = 0; var attrib; - while ((attrib = attribs[i]) !== undefined) { + while ((attrib = attrs[i]) !== undefined) { result = result.concat(' ', attrib[0], '="', attrib[1], '"'); i++; } @@ -19,7 +19,7 @@ var tag = function(name, attribs, selfclosing) { return result; }; -var renderNodes = function(block) { +var renderNodes = function(block, options) { var attrs; var info_words; @@ -43,10 +43,22 @@ var renderNodes = function(block) { } }; + options = options || {}; + while ((event = walker.next())) { entering = event.entering; node = event.node; + attrs = []; + if (options.sourcepos) { + var pos = node.sourcepos; + if (pos) { + attrs.push(['data-sourcepos', String(pos[0][0]) + ':' + + String(pos[0][1]) + '-' + String(pos[1][0]) + ':' + + String(pos[1][1])]); + } + } + switch (node.t) { case 'Text': out(esc(node.c)); @@ -79,7 +91,7 @@ var renderNodes = function(block) { case 'Link': if (entering) { - attrs = [['href', esc(node.destination, true)]]; + attrs.push(['href', esc(node.destination, true)]); if (node.title) { attrs.push(['title', esc(node.title, true)]); } @@ -124,7 +136,7 @@ var renderNodes = function(block) { } if (entering) { cr(); - out(tag('p')); + out(tag('p', attrs)); } else { out(tag('/p')); cr(); @@ -134,7 +146,7 @@ var renderNodes = function(block) { case 'BlockQuote': if (entering) { cr(); - out(tag('blockquote')); + out(tag('blockquote', attrs)); cr(); } else { cr(); @@ -145,7 +157,7 @@ var renderNodes = function(block) { case 'ListItem': if (entering) { - out(tag('li')); + out(tag('li', attrs)); } else { out(tag('/li')); cr(); @@ -155,8 +167,9 @@ var renderNodes = function(block) { case 'List': tagname = node.list_data.type === 'Bullet' ? 'ul' : 'ol'; if (entering) { - attrs = (!node.list_data.start || node.list_data.start === 1) ? - [] : [['start', node.list_data.start.toString()]]; + if (node.list_data.start && node.list_data.start > 1) { + attrs.push(['start', node.list_data.start.toString()]); + } cr(); out(tag(tagname, attrs)); cr(); @@ -171,7 +184,7 @@ var renderNodes = function(block) { tagname = 'h' + node.level; if (entering) { cr(); - out(tag(tagname)); + out(tag(tagname, attrs)); } else { out(tag('/' + tagname)); cr(); @@ -180,8 +193,9 @@ var renderNodes = function(block) { case 'CodeBlock': info_words = node.info ? node.info.split(/ +/) : []; - attrs = (info_words.length === 0 || info_words[0].length === 0) - ? [] : [['class', 'language-' + esc(info_words[0], true)]]; + if (info_words.length > 0 && info_words[0].length > 0) { + attrs.push(['class', 'language-' + esc(info_words[0], true)]); + } cr(); out(tag('pre') + tag('code', attrs)); out(this.escape(node.c)); @@ -197,7 +211,7 @@ var renderNodes = function(block) { case 'HorizontalRule': cr(); - out(tag('hr', [], true)); + out(tag('hr', attrs, true)); cr(); break; -- cgit v1.2.3