123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- var _ = require("underscore");
- function symmetricMarkdownElement(end) {
- return markdownElement(end, end);
- }
- function markdownElement(start, end) {
- return function() {
- return {start: start, end: end};
- };
- }
- function markdownLink(attributes) {
- var href = attributes.href || "";
- if (href) {
- return {
- start: "[",
- end: "](" + href + ")",
- anchorPosition: "before"
- };
- } else {
- return {};
- }
- }
- function markdownImage(attributes) {
- var src = attributes.src || "";
- var altText = attributes.alt || "";
- if (src || altText) {
- return {start: ""};
- } else {
- return {};
- }
- }
- function markdownList(options) {
- return function(attributes, list) {
- return {
- start: list ? "\n" : "",
- end: list ? "" : "\n",
- list: {
- isOrdered: options.isOrdered,
- indent: list ? list.indent + 1 : 0,
- count: 0
- }
- };
- };
- }
- function markdownListItem(attributes, list, listItem) {
- list = list || {indent: 0, isOrdered: false, count: 0};
- list.count++;
- listItem.hasClosed = false;
-
- var bullet = list.isOrdered ? list.count + "." : "-";
- var start = repeatString("\t", list.indent) + bullet + " ";
-
- return {
- start: start,
- end: function() {
- if (!listItem.hasClosed) {
- listItem.hasClosed = true;
- return "\n";
- }
- }
- };
- }
- var htmlToMarkdown = {
- "p": markdownElement("", "\n\n"),
- "br": markdownElement("", " \n"),
- "ul": markdownList({isOrdered: false}),
- "ol": markdownList({isOrdered: true}),
- "li": markdownListItem,
- "strong": symmetricMarkdownElement("__"),
- "em": symmetricMarkdownElement("*"),
- "a": markdownLink,
- "img": markdownImage
- };
- (function() {
- for (var i = 1; i <= 6; i++) {
- htmlToMarkdown["h" + i] = markdownElement(repeatString("#", i) + " ", "\n\n");
- }
- })();
- function repeatString(value, count) {
- return new Array(count + 1).join(value);
- }
- function markdownWriter() {
- var fragments = [];
- var elementStack = [];
- var list = null;
- var listItem = {};
-
- function open(tagName, attributes) {
- attributes = attributes || {};
-
- var createElement = htmlToMarkdown[tagName] || function() {
- return {};
- };
- var element = createElement(attributes, list, listItem);
- elementStack.push({end: element.end, list: list});
-
- if (element.list) {
- list = element.list;
- }
-
- var anchorBeforeStart = element.anchorPosition === "before";
- if (anchorBeforeStart) {
- writeAnchor(attributes);
- }
- fragments.push(element.start || "");
- if (!anchorBeforeStart) {
- writeAnchor(attributes);
- }
- }
-
- function writeAnchor(attributes) {
- if (attributes.id) {
- fragments.push('<a id="' + attributes.id + '"></a>');
- }
- }
-
- function close(tagName) {
- var element = elementStack.pop();
- list = element.list;
- var end = _.isFunction(element.end) ? element.end() : element.end;
- fragments.push(end || "");
- }
-
- function selfClosing(tagName, attributes) {
- open(tagName, attributes);
- close(tagName);
- }
-
- function text(value) {
- fragments.push(escapeMarkdown(value));
- }
-
- function asString() {
- return fragments.join("");
- }
- return {
- asString: asString,
- open: open,
- close: close,
- text: text,
- selfClosing: selfClosing
- };
- }
- exports.writer = markdownWriter;
- function escapeMarkdown(value) {
- return value
- .replace(/\\/g, '\\\\')
- .replace(/([\`\*_\{\}\[\]\(\)\#\+\-\.\!])/g, '\\$1');
- }
|