From b2ccfa5cc2cd4d7f8f80f0555e2586387375a98e Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 4 Feb 2015 18:41:12 +0000 Subject: Move writers into a separate directory --- lib/html-generator.js | 2 +- lib/html-writer.js | 156 ------------------------------------ lib/markdown-writer.js | 176 ----------------------------------------- lib/writers/html-writer.js | 156 ++++++++++++++++++++++++++++++++++++ lib/writers/index.js | 1 + lib/writers/markdown-writer.js | 176 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 334 insertions(+), 333 deletions(-) delete mode 100644 lib/html-writer.js delete mode 100644 lib/markdown-writer.js create mode 100644 lib/writers/html-writer.js create mode 100644 lib/writers/index.js create mode 100644 lib/writers/markdown-writer.js (limited to 'lib') diff --git a/lib/html-generator.js b/lib/html-generator.js index f23d777..cea33e0 100644 --- a/lib/html-generator.js +++ b/lib/html-generator.js @@ -1,4 +1,4 @@ -var htmlWriter = require("./html-writer"); +var htmlWriter = require("./writers/html-writer"); exports.HtmlGenerator = HtmlGenerator; diff --git a/lib/html-writer.js b/lib/html-writer.js deleted file mode 100644 index 33441cb..0000000 --- a/lib/html-writer.js +++ /dev/null @@ -1,156 +0,0 @@ -var util = require("util"); -var _ = require("underscore"); - -exports.writer = writer; - -function writer(options) { - options = options || {}; - if(options.prettyPrint) { - return prettyWriter(); - } - else if(options.markdown) { - var markdown = require("./markdown-writer"); - - return markdown.writer(); - } - else { - return simpleWriter(); - } -} - - -var indentedElements = { - div: true, - p: true, - ul: true -}; - - -function prettyWriter() { - var indentationLevel = 0; - var indentation = " "; - var stack = []; - var start = true; - var inText = false; - - var writer = simpleWriter(); - - function open(tagName, attributes) { - indent(); - stack.push(tagName); - writer.open(tagName, attributes); - if (indentedElements[tagName]) { - indentationLevel++; - } - start = false; - } - - function close(tagName) { - if (indentedElements[tagName]) { - indentationLevel--; - } - indent(); - stack.pop(); - writer.close(tagName); - } - - function text(value) { - startText(); - writer.text(value.replace("\n", "\n" + indentation)); - } - - function selfClosing(tagName, attributes) { - indent(); - writer.selfClosing(tagName, attributes); - } - - function append(html) { - startText(); - writer.append(html.replace("\n", "\n" + indentation)); - } - - function insideIndentedElement() { - return stack.length === 0 || indentedElements[stack[stack.length - 1]]; - } - - function startText() { - if (!inText) { - indent(); - inText = true; - } - } - - function indent() { - inText = false; - if (!start && insideIndentedElement()) { - writer.append("\n"); - for (var i = 0; i < indentationLevel; i++) { - writer.append(indentation); - } - } - } - - return { - asString: writer.asString, - open: open, - close: close, - text: text, - selfClosing: selfClosing, - append: append - }; -} - - -function simpleWriter() { - var fragments = []; - - function open(tagName, attributes) { - var attributeString = generateAttributeString(attributes); - fragments.push(util.format("<%s%s>", tagName, attributeString)); - } - - function close(tagName) { - fragments.push(util.format("", tagName)); - } - - function selfClosing(tagName, attributes) { - var attributeString = generateAttributeString(attributes); - fragments.push(util.format("<%s%s />", tagName, attributeString)); - } - - function generateAttributeString(attributes) { - return _.map(attributes, function(value, key) { - return util.format(' %s="%s"', key, escapeHtml(value)); - }).join(""); - } - - function text(value) { - fragments.push(escapeHtml(value)); - } - - function append(html) { - fragments.push(html); - } - - function asString() { - return fragments.join(""); - } - - return { - asString: asString, - open: open, - close: close, - text: text, - selfClosing: selfClosing, - append: append - }; -} - - -function escapeHtml(value) { - return value - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(//g, '>'); -} diff --git a/lib/markdown-writer.js b/lib/markdown-writer.js deleted file mode 100644 index b63d104..0000000 --- a/lib/markdown-writer.js +++ /dev/null @@ -1,176 +0,0 @@ - -var _ = require("underscore"); - -function mdElement(start, end) { - if (end === undefined) - end = start; - - this.open = function(attrs) { - return start; - }; - - this.close = function() { - return end; - }; - - this.empty = function(attrs) { - return this.open(attrs) + this.close(); - }; -} -function mdLink(link, text) { - var attrs = {}; - - this.open = function(attributes) { - attrs = attributes || {}; - - return "["; - }; - - this.close = function() { - return (attrs[text] || "") + "](" + (attrs[link] || "") + ")"; - }; - - this.empty = function(attrs) { - // don't display empty content (this is mainly to remove images with no src data) - var content = this.open(attrs) + this.close(); - - if(content === "[]()") { - return ""; - } - - return content; - }; -} -function mdList() { - this.open = function(attrs) { - return attrs.indent > -1 ? "\n" : ""; - }; - - this.close = function(attrs) { - return attrs.indent > -1 ? "" : "\n"; - }; - - this.empty = function(attrs) { - return this.open(attrs) + this.close(); - }; -} -function mdListItem() { - this.open = function(attrs) { - var output = ""; - - for(var i = 0; i < attrs.indent; ++i) { - output += "\t"; - } - - return output + (attrs.type === "ul" ? "-" : attrs.count + ".") + " "; - }; - - this.close = function() { - return "\n"; - }; - - this.empty = function(attrs) { - return this.open(attrs) + this.close(); - }; -} - -// map HTML tags to Markdown syntax -var htmlmd = { - // paragraphs elements use three line feeds to close - // this prevents them being caught by collapsing list elements in `asString` - // while still allowing them to be collapsed when multiple empty lines are removed - "h1": new mdElement("# ", "\n\n\n"), - "h2": new mdElement("## ", "\n\n\n"), - "h3": new mdElement("### ", "\n\n\n"), - "h4": new mdElement("#### ", "\n\n\n"), - "h5": new mdElement("##### ", "\n\n\n"), - "h6": new mdElement("###### ", "\n\n\n"), - "p": new mdElement("", "\n\n\n"), - "br": new mdElement("", " \n"), - "ul": new mdList(), - "ol": new mdList(), - "li": new mdListItem(), - "strong": new mdElement("**"), - "em": new mdElement("*"), - "a": new mdLink("href"), - "img": new mdLink("src", "alt"), -}; - -function mdWriter() { - var fragments = []; - var listStack = []; - var list = { - indent: -1, - type: "ul", - count: 0 - }; - - function isList(tagName) { - return tagName === "ul" || tagName === "ol"; - } - - function open(tagName, attributes) { - if(htmlmd[tagName]) { - attributes = attributes || {}; - - if(tagName === "li") { - attributes.indent = list.indent; - attributes.type = list.type; - attributes.count = ++list.count; - } - else if(isList(tagName)) { - attributes.indent = list.indent; - } - - fragments.push(htmlmd[tagName].open(attributes)); - - if(isList(tagName)) { - listStack.push(_.clone(list)); - - list.type = tagName; - list.indent++; - list.count = 0; - } - } - } - - function close(tagName) { - if(htmlmd[tagName]) { - if(isList(tagName)) { - list = listStack.pop(); - } - - fragments.push(htmlmd[tagName].close(list)); - } - } - - function selfClosing(tagName, attributes) { - if(htmlmd[tagName]) { - fragments.push(htmlmd[tagName].empty(attributes)); - } - } - - function text(value) { - fragments.push(value); - } - - function append(html) { - fragments.push(html); - } - - function asString() { - // massage the output to collapse mulitple empty lines and empty lines between nested lists - return fragments.join("").replace(/\n{2}(\t*)([2-9]\d*\.|- )/g, "\n$1$2").replace(/\n{3,}/g, "\n\n"); - } - - return { - asString: asString, - open: open, - close: close, - text: text, - selfClosing: selfClosing, - append: append - }; -} - -exports.writer = mdWriter; \ No newline at end of file diff --git a/lib/writers/html-writer.js b/lib/writers/html-writer.js new file mode 100644 index 0000000..33441cb --- /dev/null +++ b/lib/writers/html-writer.js @@ -0,0 +1,156 @@ +var util = require("util"); +var _ = require("underscore"); + +exports.writer = writer; + +function writer(options) { + options = options || {}; + if(options.prettyPrint) { + return prettyWriter(); + } + else if(options.markdown) { + var markdown = require("./markdown-writer"); + + return markdown.writer(); + } + else { + return simpleWriter(); + } +} + + +var indentedElements = { + div: true, + p: true, + ul: true +}; + + +function prettyWriter() { + var indentationLevel = 0; + var indentation = " "; + var stack = []; + var start = true; + var inText = false; + + var writer = simpleWriter(); + + function open(tagName, attributes) { + indent(); + stack.push(tagName); + writer.open(tagName, attributes); + if (indentedElements[tagName]) { + indentationLevel++; + } + start = false; + } + + function close(tagName) { + if (indentedElements[tagName]) { + indentationLevel--; + } + indent(); + stack.pop(); + writer.close(tagName); + } + + function text(value) { + startText(); + writer.text(value.replace("\n", "\n" + indentation)); + } + + function selfClosing(tagName, attributes) { + indent(); + writer.selfClosing(tagName, attributes); + } + + function append(html) { + startText(); + writer.append(html.replace("\n", "\n" + indentation)); + } + + function insideIndentedElement() { + return stack.length === 0 || indentedElements[stack[stack.length - 1]]; + } + + function startText() { + if (!inText) { + indent(); + inText = true; + } + } + + function indent() { + inText = false; + if (!start && insideIndentedElement()) { + writer.append("\n"); + for (var i = 0; i < indentationLevel; i++) { + writer.append(indentation); + } + } + } + + return { + asString: writer.asString, + open: open, + close: close, + text: text, + selfClosing: selfClosing, + append: append + }; +} + + +function simpleWriter() { + var fragments = []; + + function open(tagName, attributes) { + var attributeString = generateAttributeString(attributes); + fragments.push(util.format("<%s%s>", tagName, attributeString)); + } + + function close(tagName) { + fragments.push(util.format("", tagName)); + } + + function selfClosing(tagName, attributes) { + var attributeString = generateAttributeString(attributes); + fragments.push(util.format("<%s%s />", tagName, attributeString)); + } + + function generateAttributeString(attributes) { + return _.map(attributes, function(value, key) { + return util.format(' %s="%s"', key, escapeHtml(value)); + }).join(""); + } + + function text(value) { + fragments.push(escapeHtml(value)); + } + + function append(html) { + fragments.push(html); + } + + function asString() { + return fragments.join(""); + } + + return { + asString: asString, + open: open, + close: close, + text: text, + selfClosing: selfClosing, + append: append + }; +} + + +function escapeHtml(value) { + return value + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +} diff --git a/lib/writers/index.js b/lib/writers/index.js new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/writers/index.js @@ -0,0 +1 @@ + diff --git a/lib/writers/markdown-writer.js b/lib/writers/markdown-writer.js new file mode 100644 index 0000000..b63d104 --- /dev/null +++ b/lib/writers/markdown-writer.js @@ -0,0 +1,176 @@ + +var _ = require("underscore"); + +function mdElement(start, end) { + if (end === undefined) + end = start; + + this.open = function(attrs) { + return start; + }; + + this.close = function() { + return end; + }; + + this.empty = function(attrs) { + return this.open(attrs) + this.close(); + }; +} +function mdLink(link, text) { + var attrs = {}; + + this.open = function(attributes) { + attrs = attributes || {}; + + return "["; + }; + + this.close = function() { + return (attrs[text] || "") + "](" + (attrs[link] || "") + ")"; + }; + + this.empty = function(attrs) { + // don't display empty content (this is mainly to remove images with no src data) + var content = this.open(attrs) + this.close(); + + if(content === "[]()") { + return ""; + } + + return content; + }; +} +function mdList() { + this.open = function(attrs) { + return attrs.indent > -1 ? "\n" : ""; + }; + + this.close = function(attrs) { + return attrs.indent > -1 ? "" : "\n"; + }; + + this.empty = function(attrs) { + return this.open(attrs) + this.close(); + }; +} +function mdListItem() { + this.open = function(attrs) { + var output = ""; + + for(var i = 0; i < attrs.indent; ++i) { + output += "\t"; + } + + return output + (attrs.type === "ul" ? "-" : attrs.count + ".") + " "; + }; + + this.close = function() { + return "\n"; + }; + + this.empty = function(attrs) { + return this.open(attrs) + this.close(); + }; +} + +// map HTML tags to Markdown syntax +var htmlmd = { + // paragraphs elements use three line feeds to close + // this prevents them being caught by collapsing list elements in `asString` + // while still allowing them to be collapsed when multiple empty lines are removed + "h1": new mdElement("# ", "\n\n\n"), + "h2": new mdElement("## ", "\n\n\n"), + "h3": new mdElement("### ", "\n\n\n"), + "h4": new mdElement("#### ", "\n\n\n"), + "h5": new mdElement("##### ", "\n\n\n"), + "h6": new mdElement("###### ", "\n\n\n"), + "p": new mdElement("", "\n\n\n"), + "br": new mdElement("", " \n"), + "ul": new mdList(), + "ol": new mdList(), + "li": new mdListItem(), + "strong": new mdElement("**"), + "em": new mdElement("*"), + "a": new mdLink("href"), + "img": new mdLink("src", "alt"), +}; + +function mdWriter() { + var fragments = []; + var listStack = []; + var list = { + indent: -1, + type: "ul", + count: 0 + }; + + function isList(tagName) { + return tagName === "ul" || tagName === "ol"; + } + + function open(tagName, attributes) { + if(htmlmd[tagName]) { + attributes = attributes || {}; + + if(tagName === "li") { + attributes.indent = list.indent; + attributes.type = list.type; + attributes.count = ++list.count; + } + else if(isList(tagName)) { + attributes.indent = list.indent; + } + + fragments.push(htmlmd[tagName].open(attributes)); + + if(isList(tagName)) { + listStack.push(_.clone(list)); + + list.type = tagName; + list.indent++; + list.count = 0; + } + } + } + + function close(tagName) { + if(htmlmd[tagName]) { + if(isList(tagName)) { + list = listStack.pop(); + } + + fragments.push(htmlmd[tagName].close(list)); + } + } + + function selfClosing(tagName, attributes) { + if(htmlmd[tagName]) { + fragments.push(htmlmd[tagName].empty(attributes)); + } + } + + function text(value) { + fragments.push(value); + } + + function append(html) { + fragments.push(html); + } + + function asString() { + // massage the output to collapse mulitple empty lines and empty lines between nested lists + return fragments.join("").replace(/\n{2}(\t*)([2-9]\d*\.|- )/g, "\n$1$2").replace(/\n{3,}/g, "\n\n"); + } + + return { + asString: asString, + open: open, + close: close, + text: text, + selfClosing: selfClosing, + append: append + }; +} + +exports.writer = mdWriter; \ No newline at end of file -- cgit v1.2.3