cmark

My personal build of CMark ✏️

Commit
a1bc760fef3ae9e98f039fa50f31fc2d5eb877a2
Parent
7bfb5dd6915fd455e93086fc2b546802bdd77027
Author
John MacFarlane <jgm@berkeley.edu>
Date

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`.

Diffstat

2 files changed, 45 insertions, 24 deletions

Status File Name N° Changes Insertions Deletions
Modified js/bin/commonmark 27 17 10
Modified js/lib/html.js 42 28 14
diff --git 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
@@ -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;