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 ++++++++++++++++ tests/html-writer.tests.js | 106 ---------- tests/markdown-writer.tests.js | 365 -------------------------------- tests/writers/html-writer.tests.js | 106 ++++++++++ tests/writers/markdown-writer.tests.js | 366 +++++++++++++++++++++++++++++++++ 10 files changed, 806 insertions(+), 804 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 delete mode 100644 tests/html-writer.tests.js delete mode 100644 tests/markdown-writer.tests.js create mode 100644 tests/writers/html-writer.tests.js create mode 100644 tests/writers/markdown-writer.tests.js 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 diff --git a/tests/html-writer.tests.js b/tests/html-writer.tests.js deleted file mode 100644 index 64c9ea0..0000000 --- a/tests/html-writer.tests.js +++ /dev/null @@ -1,106 +0,0 @@ -var assert = require("assert"); -var test = require("./testing").test; - -var htmlWriter = require("../lib/html-writer"); - - -describe('html-writer', function() { - test('can generate simple paragraph', function() { - var writer = htmlWriter.writer(); - writer.open("p"); - writer.text("Hello"); - writer.close("p"); - return assert.equal(writer.asString(), "

Hello

"); - }); - - test('can nest elements', function() { - var writer = htmlWriter.writer(); - writer.open("ul"); - writer.open("li"); - writer.text("One"); - writer.close("li"); - writer.open("li"); - writer.text("Two"); - writer.close("li"); - writer.close("ul"); - return assert.equal(writer.asString(), ""); - }); - - test('indents text if prettyPrint is true', function() { - var writer = htmlWriter.writer({prettyPrint: true}); - writer.open("p"); - writer.text("One"); - writer.close("p"); - writer.open("p"); - writer.text("Two"); - writer.close("p"); - return assert.equal(writer.asString(), "

\n One\n

\n

\n Two\n

"); - }); - - test('indents element if prettyPrint is true', function() { - var writer = htmlWriter.writer({prettyPrint: true}); - writer.open("ul"); - writer.open("li"); - writer.text("One"); - writer.close("li"); - writer.open("li"); - writer.text("Two"); - writer.close("li"); - writer.close("ul"); - return assert.equal(writer.asString(), ""); - }); - - test('indents closing element correctly when nested inside another indented element', function() { - var writer = htmlWriter.writer({prettyPrint: true}); - writer.open("div"); - writer.open("div"); - writer.open("div"); - writer.text("Hello"); - writer.close("div"); - writer.close("div"); - writer.close("div"); - return assert.equal(writer.asString(), "
\n
\n
\n Hello\n
\n
\n
"); - }); - - test('newlines in text are indented', function() { - var writer = htmlWriter.writer({prettyPrint: true}); - writer.open("p"); - writer.text("One\nTwo"); - writer.close("p"); - return assert.equal(writer.asString(), "

\n One\n Two\n

"); - }); - - test('run of text has only one new line', function() { - var writer = htmlWriter.writer({prettyPrint: true}); - writer.open("p"); - writer.text("One"); - writer.text("Two"); - writer.close("p"); - return assert.equal(writer.asString(), "

\n OneTwo\n

"); - }); - - test('run of html has only one new line', function() { - var writer = htmlWriter.writer({prettyPrint: true}); - writer.open("p"); - writer.append("One"); - writer.append("Two"); - writer.close("p"); - return assert.equal(writer.asString(), "

\n OneTwo\n

"); - }); - - test('self closing elements are indented', function() { - var writer = htmlWriter.writer({prettyPrint: true}); - writer.open("p"); - writer.selfClosing("br"); - writer.close("p"); - return assert.equal(writer.asString(), "

\n
\n

"); - }); - - test('newlines in appended HTML are indented', function() { - var writer = htmlWriter.writer({prettyPrint: true}); - writer.open("p"); - writer.append("One\nTwo"); - writer.close("p"); - return assert.equal(writer.asString(), "

\n One\n Two\n

"); - }); -}); diff --git a/tests/markdown-writer.tests.js b/tests/markdown-writer.tests.js deleted file mode 100644 index bf3df1b..0000000 --- a/tests/markdown-writer.tests.js +++ /dev/null @@ -1,365 +0,0 @@ -var assert = require("assert"); -var test = require("./testing").test; -var mdWriter = require("../lib/markdown-writer"); - -describe('markdown-writer', function() { - test('can generate a paragraph', function() { - var writer = mdWriter.writer(); - writer.open("p"); - writer.text("Hello"); - writer.close("p"); - return assert.equal(writer.asString(), "Hello\n\n"); - }); - - test('can generate a level 1 heading', function() { - var writer = mdWriter.writer(); - writer.open("h1"); - writer.text("Hello"); - writer.close("h1"); - return assert.equal(writer.asString(), "# Hello\n\n"); - }); - - test('can generate a level 2 heading', function() { - var writer = mdWriter.writer(); - writer.open("h2"); - writer.text("Hello"); - writer.close("h2"); - return assert.equal(writer.asString(), "## Hello\n\n"); - }); - - test('can generate a level 3 heading', function() { - var writer = mdWriter.writer(); - writer.open("h3"); - writer.text("Hello"); - writer.close("h3"); - return assert.equal(writer.asString(), "### Hello\n\n"); - }); - - test('can generate a level 4 heading', function() { - var writer = mdWriter.writer(); - writer.open("h4"); - writer.text("Hello"); - writer.close("h4"); - return assert.equal(writer.asString(), "#### Hello\n\n"); - }); - - test('can generate a level 5 heading', function() { - var writer = mdWriter.writer(); - writer.open("h5"); - writer.text("Hello"); - writer.close("h5"); - return assert.equal(writer.asString(), "##### Hello\n\n"); - }); - - test('can generate a level 6 heading', function() { - var writer = mdWriter.writer(); - writer.open("h6"); - writer.text("Hello"); - writer.close("h6"); - return assert.equal(writer.asString(), "###### Hello\n\n"); - }); - - test('can generate a new line', function() { - var writer = mdWriter.writer(); - writer.text("Hello World"); - writer.selfClosing("br"); - return assert.equal(writer.asString(), "Hello World \n"); - }); - - test('can generate strong text', function() { - var writer = mdWriter.writer(); - writer.text("Hello "); - writer.open("strong"); - writer.text("World"); - writer.close("strong"); - return assert.equal(writer.asString(), "Hello **World**"); - }); - - test('can generate emphasis text', function() { - var writer = mdWriter.writer(); - writer.text("Hello "); - writer.open("em"); - writer.text("World"); - writer.close("em"); - return assert.equal(writer.asString(), "Hello *World*"); - }); - - test('can generate hyperlinks', function() { - var writer = mdWriter.writer(); - writer.open("a", { "href": "http://example.com" }); - writer.text("Hello"); - writer.close("a"); - return assert.equal(writer.asString(), "[Hello](http://example.com)"); - }); - - test('can generate hyperlinks with missing href attribute', function() { - var writer = mdWriter.writer(); - writer.open("a", {}); - writer.text("Hello"); - writer.close("a"); - return assert.equal(writer.asString(), "[Hello]()"); - }); - - test('can generate hyperlinks with empty attributes', function() { - var writer = mdWriter.writer(); - writer.open("a"); - writer.text("Hello"); - writer.close("a"); - return assert.equal(writer.asString(), "[Hello]()"); - }); - - test('can generate images', function() { - var writer = mdWriter.writer(); - writer.selfClosing("img", { "src": "http://example.com/image.jpg", "alt": "Alt Text" }); - return assert.equal(writer.asString(), "[Alt Text](http://example.com/image.jpg)"); - }); - - test('can generate images with missing alt attribute', function() { - var writer = mdWriter.writer(); - writer.selfClosing("img", { "src": "http://example.com/image.jpg" }); - return assert.equal(writer.asString(), "[](http://example.com/image.jpg)"); - }); - - test('can generate images with misssing src attribute', function() { - var writer = mdWriter.writer(); - writer.selfClosing("img", { "alt": "Alt Text" }); - return assert.equal(writer.asString(), "[Alt Text]()"); - }); - - test("doesn't display empty images", function() { - var writer = mdWriter.writer(); - writer.selfClosing("img"); - return assert.equal(writer.asString(), ""); - }); - - test('can generate an ordered list', function() { - var writer = mdWriter.writer(); - writer.open("ol"); - writer.open("li"); - writer.text("Hello"); - writer.close("li"); - writer.open("li"); - writer.text("World"); - writer.close("li"); - writer.close("ol"); - return assert.equal(writer.asString(), "1. Hello\n2. World\n\n"); - }); - - test('can generate an unordered list', function() { - var writer = mdWriter.writer(); - writer.open("ul"); - writer.open("li"); - writer.text("Hello"); - writer.close("li"); - writer.open("li"); - writer.text("World"); - writer.close("li"); - writer.close("ul"); - return assert.equal(writer.asString(), "- Hello\n- World\n\n"); - }); - - test('can generate a nested ordered list with correct numbering', function() { - var writer = mdWriter.writer(); - writer.open("ol"); - writer.open("li"); - writer.text("Outer One"); - writer.close("li"); - writer.open("li"); - writer.text("Outer Two"); - - writer.open("ol"); - writer.open("li"); - writer.text("Nested One"); - writer.close("li"); - writer.open("li"); - writer.text("Nested Two"); - writer.close("li"); - writer.open("li"); - writer.text("Nested Three"); - writer.close("li"); - writer.close("ol"); - - writer.close("li"); - writer.open("li"); - writer.text("Outer Three"); - writer.close("li"); - writer.close("ol"); - return assert.equal(writer.asString(), "1. Outer One\n2. Outer Two\n\t1. Nested One\n\t2. Nested Two\n\t3. Nested Three\n3. Outer Three\n\n"); - }); - - test('can generate a multi-level nested ordered list with correct numbering', function() { - var writer = mdWriter.writer(); - writer.open("ol"); - writer.open("li"); - writer.text("Outer One"); - writer.close("li"); - writer.open("li"); - writer.text("Outer Two"); - - writer.open("ol"); - writer.open("li"); - writer.text("Nested One"); - writer.close("li"); - writer.open("li"); - writer.text("Nested Two"); - writer.close("li"); - writer.open("li"); - writer.text("Nested Three"); - - writer.open("ol"); - writer.open("li"); - writer.text("Inner One"); - writer.close("li"); - writer.open("li"); - writer.text("Inner Two"); - writer.close("li"); - writer.open("li"); - writer.text("Inner Three"); - writer.close("li"); - writer.open("li"); - writer.text("Inner Four"); - writer.close("li"); - writer.close("ol"); - - writer.close("li"); - writer.open("li"); - writer.text("Nested Four"); - writer.close("li"); - writer.close("ol"); - - writer.close("li"); - writer.open("li"); - writer.text("Outer Three"); - writer.close("li"); - writer.close("ol"); - return assert.equal(writer.asString(), "1. Outer One\n2. Outer Two\n\t1. Nested One\n\t2. Nested Two\n\t3. Nested Three\n\t\t1. Inner One\n\t\t2. Inner Two\n\t\t3. Inner Three\n\t\t4. Inner Four\n\t4. Nested Four\n3. Outer Three\n\n"); - }); - - test('can generate sequential ordered lists with correct numbering', function() { - var writer = mdWriter.writer(); - writer.open("ol"); - writer.open("li"); - writer.text("First One"); - writer.close("li"); - writer.open("li"); - writer.text("First Two"); - writer.close("li"); - writer.close("ol"); - - writer.open("ol"); - writer.open("li"); - writer.text("Second One"); - writer.close("li"); - writer.open("li"); - writer.text("Second Two"); - writer.close("li"); - writer.open("li"); - writer.text("Second Three"); - writer.close("li"); - writer.close("ol"); - - return assert.equal(writer.asString(), "1. First One\n2. First Two\n\n1. Second One\n2. Second Two\n3. Second Three\n\n"); - }); - - test('can generate a nested unordered list', function() { - var writer = mdWriter.writer(); - writer.open("ul"); - writer.open("li"); - writer.text("Outer One"); - writer.close("li"); - writer.open("li"); - writer.text("Outer Two"); - - writer.open("ul"); - writer.open("li"); - writer.text("Nested One"); - writer.close("li"); - writer.open("li"); - writer.text("Nested Two"); - writer.close("li"); - writer.open("li"); - writer.text("Nested Three"); - writer.close("li"); - writer.close("ul"); - - writer.close("li"); - writer.open("li"); - writer.text("Outer Three"); - writer.close("li"); - writer.close("ul"); - return assert.equal(writer.asString(), "- Outer One\n- Outer Two\n\t- Nested One\n\t- Nested Two\n\t- Nested Three\n- Outer Three\n\n"); - }); - - test('can nest inline elements', function() { - var writer = mdWriter.writer(); - writer.open("p"); - writer.text("Lorem "); - writer.open("strong"); - writer.text("ipsum "); - writer.open("em"); - writer.text("dolor"); - writer.close("em"); - writer.text(" sit"); - writer.close("strong"); - writer.text(" amet"); - writer.close("p"); - return assert.equal(writer.asString(), "Lorem **ipsum *dolor* sit** amet\n\n"); - }); - - test('can emphasise list text', function() { - var writer = mdWriter.writer(); - writer.open("ol"); - writer.open("li"); - writer.text("Hello "); - writer.open("strong"); - writer.text("Strong"); - writer.close("strong"); - writer.text(" World"); - writer.close("li"); - writer.open("li"); - writer.text("Hello "); - writer.open("em"); - writer.text("Emphasis"); - writer.close("em"); - writer.text(" World"); - writer.close("li"); - writer.close("ol"); - return assert.equal(writer.asString(), "1. Hello **Strong** World\n2. Hello *Emphasis* World\n\n"); - }); - - test('blank paragraphs are removed', function() { - var writer = mdWriter.writer(); - writer.open("p"); - writer.text("Hello"); - writer.close("p"); - writer.open("p"); - writer.text(""); - writer.close("p"); - writer.open("p"); - writer.text(""); - writer.close("p"); - writer.open("p"); - writer.text("World"); - writer.close("p"); - return assert.equal(writer.asString(), "Hello\n\nWorld\n\n"); - }); - - test('generates correct spacing between paragraphs and lists', function() { - var writer = mdWriter.writer(); - writer.open("p"); - writer.text("Hello World"); - writer.close("p"); - writer.open("ul"); - writer.open("li"); - writer.text("First Item"); - writer.close("li"); - writer.open("li"); - writer.text("Second Item"); - writer.close("li"); - writer.close("ul"); - writer.open("p"); - writer.text("Hello World"); - writer.close("p"); - return assert.equal(writer.asString(), "Hello World\n\n- First Item\n- Second Item\n\nHello World\n\n"); - }); -}); diff --git a/tests/writers/html-writer.tests.js b/tests/writers/html-writer.tests.js new file mode 100644 index 0000000..5e398e8 --- /dev/null +++ b/tests/writers/html-writer.tests.js @@ -0,0 +1,106 @@ +var assert = require("assert"); +var test = require("../testing").test; + +var htmlWriter = require("../../lib/writers/html-writer"); + + +describe('html-writer', function() { + test('can generate simple paragraph', function() { + var writer = htmlWriter.writer(); + writer.open("p"); + writer.text("Hello"); + writer.close("p"); + return assert.equal(writer.asString(), "

Hello

"); + }); + + test('can nest elements', function() { + var writer = htmlWriter.writer(); + writer.open("ul"); + writer.open("li"); + writer.text("One"); + writer.close("li"); + writer.open("li"); + writer.text("Two"); + writer.close("li"); + writer.close("ul"); + return assert.equal(writer.asString(), ""); + }); + + test('indents text if prettyPrint is true', function() { + var writer = htmlWriter.writer({prettyPrint: true}); + writer.open("p"); + writer.text("One"); + writer.close("p"); + writer.open("p"); + writer.text("Two"); + writer.close("p"); + return assert.equal(writer.asString(), "

\n One\n

\n

\n Two\n

"); + }); + + test('indents element if prettyPrint is true', function() { + var writer = htmlWriter.writer({prettyPrint: true}); + writer.open("ul"); + writer.open("li"); + writer.text("One"); + writer.close("li"); + writer.open("li"); + writer.text("Two"); + writer.close("li"); + writer.close("ul"); + return assert.equal(writer.asString(), ""); + }); + + test('indents closing element correctly when nested inside another indented element', function() { + var writer = htmlWriter.writer({prettyPrint: true}); + writer.open("div"); + writer.open("div"); + writer.open("div"); + writer.text("Hello"); + writer.close("div"); + writer.close("div"); + writer.close("div"); + return assert.equal(writer.asString(), "
\n
\n
\n Hello\n
\n
\n
"); + }); + + test('newlines in text are indented', function() { + var writer = htmlWriter.writer({prettyPrint: true}); + writer.open("p"); + writer.text("One\nTwo"); + writer.close("p"); + return assert.equal(writer.asString(), "

\n One\n Two\n

"); + }); + + test('run of text has only one new line', function() { + var writer = htmlWriter.writer({prettyPrint: true}); + writer.open("p"); + writer.text("One"); + writer.text("Two"); + writer.close("p"); + return assert.equal(writer.asString(), "

\n OneTwo\n

"); + }); + + test('run of html has only one new line', function() { + var writer = htmlWriter.writer({prettyPrint: true}); + writer.open("p"); + writer.append("One"); + writer.append("Two"); + writer.close("p"); + return assert.equal(writer.asString(), "

\n OneTwo\n

"); + }); + + test('self closing elements are indented', function() { + var writer = htmlWriter.writer({prettyPrint: true}); + writer.open("p"); + writer.selfClosing("br"); + writer.close("p"); + return assert.equal(writer.asString(), "

\n
\n

"); + }); + + test('newlines in appended HTML are indented', function() { + var writer = htmlWriter.writer({prettyPrint: true}); + writer.open("p"); + writer.append("One\nTwo"); + writer.close("p"); + return assert.equal(writer.asString(), "

\n One\n Two\n

"); + }); +}); diff --git a/tests/writers/markdown-writer.tests.js b/tests/writers/markdown-writer.tests.js new file mode 100644 index 0000000..b295d45 --- /dev/null +++ b/tests/writers/markdown-writer.tests.js @@ -0,0 +1,366 @@ +var assert = require("assert"); +var test = require("../testing").test; + +var mdWriter = require("../../lib/writers/markdown-writer"); + +describe('markdown-writer', function() { + test('can generate a paragraph', function() { + var writer = mdWriter.writer(); + writer.open("p"); + writer.text("Hello"); + writer.close("p"); + return assert.equal(writer.asString(), "Hello\n\n"); + }); + + test('can generate a level 1 heading', function() { + var writer = mdWriter.writer(); + writer.open("h1"); + writer.text("Hello"); + writer.close("h1"); + return assert.equal(writer.asString(), "# Hello\n\n"); + }); + + test('can generate a level 2 heading', function() { + var writer = mdWriter.writer(); + writer.open("h2"); + writer.text("Hello"); + writer.close("h2"); + return assert.equal(writer.asString(), "## Hello\n\n"); + }); + + test('can generate a level 3 heading', function() { + var writer = mdWriter.writer(); + writer.open("h3"); + writer.text("Hello"); + writer.close("h3"); + return assert.equal(writer.asString(), "### Hello\n\n"); + }); + + test('can generate a level 4 heading', function() { + var writer = mdWriter.writer(); + writer.open("h4"); + writer.text("Hello"); + writer.close("h4"); + return assert.equal(writer.asString(), "#### Hello\n\n"); + }); + + test('can generate a level 5 heading', function() { + var writer = mdWriter.writer(); + writer.open("h5"); + writer.text("Hello"); + writer.close("h5"); + return assert.equal(writer.asString(), "##### Hello\n\n"); + }); + + test('can generate a level 6 heading', function() { + var writer = mdWriter.writer(); + writer.open("h6"); + writer.text("Hello"); + writer.close("h6"); + return assert.equal(writer.asString(), "###### Hello\n\n"); + }); + + test('can generate a new line', function() { + var writer = mdWriter.writer(); + writer.text("Hello World"); + writer.selfClosing("br"); + return assert.equal(writer.asString(), "Hello World \n"); + }); + + test('can generate strong text', function() { + var writer = mdWriter.writer(); + writer.text("Hello "); + writer.open("strong"); + writer.text("World"); + writer.close("strong"); + return assert.equal(writer.asString(), "Hello **World**"); + }); + + test('can generate emphasis text', function() { + var writer = mdWriter.writer(); + writer.text("Hello "); + writer.open("em"); + writer.text("World"); + writer.close("em"); + return assert.equal(writer.asString(), "Hello *World*"); + }); + + test('can generate hyperlinks', function() { + var writer = mdWriter.writer(); + writer.open("a", { "href": "http://example.com" }); + writer.text("Hello"); + writer.close("a"); + return assert.equal(writer.asString(), "[Hello](http://example.com)"); + }); + + test('can generate hyperlinks with missing href attribute', function() { + var writer = mdWriter.writer(); + writer.open("a", {}); + writer.text("Hello"); + writer.close("a"); + return assert.equal(writer.asString(), "[Hello]()"); + }); + + test('can generate hyperlinks with empty attributes', function() { + var writer = mdWriter.writer(); + writer.open("a"); + writer.text("Hello"); + writer.close("a"); + return assert.equal(writer.asString(), "[Hello]()"); + }); + + test('can generate images', function() { + var writer = mdWriter.writer(); + writer.selfClosing("img", { "src": "http://example.com/image.jpg", "alt": "Alt Text" }); + return assert.equal(writer.asString(), "[Alt Text](http://example.com/image.jpg)"); + }); + + test('can generate images with missing alt attribute', function() { + var writer = mdWriter.writer(); + writer.selfClosing("img", { "src": "http://example.com/image.jpg" }); + return assert.equal(writer.asString(), "[](http://example.com/image.jpg)"); + }); + + test('can generate images with misssing src attribute', function() { + var writer = mdWriter.writer(); + writer.selfClosing("img", { "alt": "Alt Text" }); + return assert.equal(writer.asString(), "[Alt Text]()"); + }); + + test("doesn't display empty images", function() { + var writer = mdWriter.writer(); + writer.selfClosing("img"); + return assert.equal(writer.asString(), ""); + }); + + test('can generate an ordered list', function() { + var writer = mdWriter.writer(); + writer.open("ol"); + writer.open("li"); + writer.text("Hello"); + writer.close("li"); + writer.open("li"); + writer.text("World"); + writer.close("li"); + writer.close("ol"); + return assert.equal(writer.asString(), "1. Hello\n2. World\n\n"); + }); + + test('can generate an unordered list', function() { + var writer = mdWriter.writer(); + writer.open("ul"); + writer.open("li"); + writer.text("Hello"); + writer.close("li"); + writer.open("li"); + writer.text("World"); + writer.close("li"); + writer.close("ul"); + return assert.equal(writer.asString(), "- Hello\n- World\n\n"); + }); + + test('can generate a nested ordered list with correct numbering', function() { + var writer = mdWriter.writer(); + writer.open("ol"); + writer.open("li"); + writer.text("Outer One"); + writer.close("li"); + writer.open("li"); + writer.text("Outer Two"); + + writer.open("ol"); + writer.open("li"); + writer.text("Nested One"); + writer.close("li"); + writer.open("li"); + writer.text("Nested Two"); + writer.close("li"); + writer.open("li"); + writer.text("Nested Three"); + writer.close("li"); + writer.close("ol"); + + writer.close("li"); + writer.open("li"); + writer.text("Outer Three"); + writer.close("li"); + writer.close("ol"); + return assert.equal(writer.asString(), "1. Outer One\n2. Outer Two\n\t1. Nested One\n\t2. Nested Two\n\t3. Nested Three\n3. Outer Three\n\n"); + }); + + test('can generate a multi-level nested ordered list with correct numbering', function() { + var writer = mdWriter.writer(); + writer.open("ol"); + writer.open("li"); + writer.text("Outer One"); + writer.close("li"); + writer.open("li"); + writer.text("Outer Two"); + + writer.open("ol"); + writer.open("li"); + writer.text("Nested One"); + writer.close("li"); + writer.open("li"); + writer.text("Nested Two"); + writer.close("li"); + writer.open("li"); + writer.text("Nested Three"); + + writer.open("ol"); + writer.open("li"); + writer.text("Inner One"); + writer.close("li"); + writer.open("li"); + writer.text("Inner Two"); + writer.close("li"); + writer.open("li"); + writer.text("Inner Three"); + writer.close("li"); + writer.open("li"); + writer.text("Inner Four"); + writer.close("li"); + writer.close("ol"); + + writer.close("li"); + writer.open("li"); + writer.text("Nested Four"); + writer.close("li"); + writer.close("ol"); + + writer.close("li"); + writer.open("li"); + writer.text("Outer Three"); + writer.close("li"); + writer.close("ol"); + return assert.equal(writer.asString(), "1. Outer One\n2. Outer Two\n\t1. Nested One\n\t2. Nested Two\n\t3. Nested Three\n\t\t1. Inner One\n\t\t2. Inner Two\n\t\t3. Inner Three\n\t\t4. Inner Four\n\t4. Nested Four\n3. Outer Three\n\n"); + }); + + test('can generate sequential ordered lists with correct numbering', function() { + var writer = mdWriter.writer(); + writer.open("ol"); + writer.open("li"); + writer.text("First One"); + writer.close("li"); + writer.open("li"); + writer.text("First Two"); + writer.close("li"); + writer.close("ol"); + + writer.open("ol"); + writer.open("li"); + writer.text("Second One"); + writer.close("li"); + writer.open("li"); + writer.text("Second Two"); + writer.close("li"); + writer.open("li"); + writer.text("Second Three"); + writer.close("li"); + writer.close("ol"); + + return assert.equal(writer.asString(), "1. First One\n2. First Two\n\n1. Second One\n2. Second Two\n3. Second Three\n\n"); + }); + + test('can generate a nested unordered list', function() { + var writer = mdWriter.writer(); + writer.open("ul"); + writer.open("li"); + writer.text("Outer One"); + writer.close("li"); + writer.open("li"); + writer.text("Outer Two"); + + writer.open("ul"); + writer.open("li"); + writer.text("Nested One"); + writer.close("li"); + writer.open("li"); + writer.text("Nested Two"); + writer.close("li"); + writer.open("li"); + writer.text("Nested Three"); + writer.close("li"); + writer.close("ul"); + + writer.close("li"); + writer.open("li"); + writer.text("Outer Three"); + writer.close("li"); + writer.close("ul"); + return assert.equal(writer.asString(), "- Outer One\n- Outer Two\n\t- Nested One\n\t- Nested Two\n\t- Nested Three\n- Outer Three\n\n"); + }); + + test('can nest inline elements', function() { + var writer = mdWriter.writer(); + writer.open("p"); + writer.text("Lorem "); + writer.open("strong"); + writer.text("ipsum "); + writer.open("em"); + writer.text("dolor"); + writer.close("em"); + writer.text(" sit"); + writer.close("strong"); + writer.text(" amet"); + writer.close("p"); + return assert.equal(writer.asString(), "Lorem **ipsum *dolor* sit** amet\n\n"); + }); + + test('can emphasise list text', function() { + var writer = mdWriter.writer(); + writer.open("ol"); + writer.open("li"); + writer.text("Hello "); + writer.open("strong"); + writer.text("Strong"); + writer.close("strong"); + writer.text(" World"); + writer.close("li"); + writer.open("li"); + writer.text("Hello "); + writer.open("em"); + writer.text("Emphasis"); + writer.close("em"); + writer.text(" World"); + writer.close("li"); + writer.close("ol"); + return assert.equal(writer.asString(), "1. Hello **Strong** World\n2. Hello *Emphasis* World\n\n"); + }); + + test('blank paragraphs are removed', function() { + var writer = mdWriter.writer(); + writer.open("p"); + writer.text("Hello"); + writer.close("p"); + writer.open("p"); + writer.text(""); + writer.close("p"); + writer.open("p"); + writer.text(""); + writer.close("p"); + writer.open("p"); + writer.text("World"); + writer.close("p"); + return assert.equal(writer.asString(), "Hello\n\nWorld\n\n"); + }); + + test('generates correct spacing between paragraphs and lists', function() { + var writer = mdWriter.writer(); + writer.open("p"); + writer.text("Hello World"); + writer.close("p"); + writer.open("ul"); + writer.open("li"); + writer.text("First Item"); + writer.close("li"); + writer.open("li"); + writer.text("Second Item"); + writer.close("li"); + writer.close("ul"); + writer.open("p"); + writer.text("Hello World"); + writer.close("p"); + return assert.equal(writer.asString(), "Hello World\n\n- First Item\n- Second Item\n\nHello World\n\n"); + }); +}); -- cgit v1.2.3