Skip to content
Commits on Source (1)
{
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 3
},
"env": {
"browser": true,
"node": true
},
"rules": {
"no-multi-spaces": 2,
"no-unused-expressions": 2,
"no-shadow": 2,
"no-trailing-spaces": 2
}
}
......@@ -3,3 +3,4 @@ test*
yarn*
.gitlab-ci.yml
.tickings
.eslintrc
......@@ -31,3 +31,5 @@
2018-07-09T19:24:52.915Z git:react 0:16:21
2018-07-10T17:37:24.092Z git:react Fix trimming on creating prev
2018-07-10T19:50:26.683Z git:react 0:29:16
2018-07-11T21:07:04.110Z git:master 23:25:21
2018-07-11T21:07:16.838Z git:master es3ing and linting
const TAGS = {
'' : [null, 'em'],
_ : [null, 'strong'],
'~' : [null, 's'],
'\n' : ['br', null],
' ' : ['br', null],
'-': ['hr', null]
};
"use strict";
/** Outdent a string based on the first indented line's leading whitespace
* @private
*/
function outdent(str) {
return str.replace(RegExp('^'+(str.match(/^(\t| )+/) || '')[0], 'gm'), '');
}
/** Encode special attribute characters to HTML entities in a String.
* @private
*/
function encodeAttr(str) {
return (str+'').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
// export default function parse(md, referenceLinks) {
/**
* Turn Markdown into react-like objects
*/
module.exports = function parse(md, options) {
var TAGS = {
'' : [null, 'em'],
_ : [null, 'strong'],
'~' : [null, 's'],
'\n' : ['br', null],
' ' : ['br', null],
'-': ['hr', null]
};
/** Outdent a string based on the first indented line's leading whitespace
* @private
*/
function outdent(str) {
return str.replace(RegExp('^'+(str.match(/^(\t| )+/) || '')[0], 'gm'), '');
}
/** Encode special attribute characters to HTML entities in a String.
* @private
*/
function encodeAttr(str) {
return (str+'').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
if (!options) {
options = {};
}
......@@ -36,9 +37,15 @@ module.exports = function parse(md, options) {
options.stripTags = [];
}
let e;
var e;
if (!options.createElement) {
e = (type, props, children) => ({ type, props, children });
e = function (type, props, children) {
return {
type: type,
props: props,
children: children
};
};
} else {
e = options.createElement;
}
......@@ -55,26 +62,26 @@ module.exports = function parse(md, options) {
// (!17! \n\n*|\n{2,}|__|\*\*|[_*]|~~)| - Formatters
// (?:{@(!18!\w+)(!19!(?:\s+(?:"(?:\\"|[^"])*"|[^"\s}]*))*)})| - Special MD Tag
// (?:<\s*(!20!\/)(!21!\w+)(!22! [^>]+)?>) - HTML Tag
let tokenizer = /((?:^|\n+)(?:\n---+|\* \*(?: \*)+)\n)|(?:^``` *(\w*)\n([\s\S]*?)\n```$)|((?:(?:^|\n+)(?:\t| {2,}).+)+\n*)|((?:(?:^|\n)([>*+-]|\d+\.)\s+.*)+)|(?:\!\[([^\]]*?)\]\(([^\)]+?)\))|(\[)|(\](?:\(([^\)]+?)\))?)|(?:(?:^|\n+)([^\s].*)\n(\-{3,}|={3,})(?:\n+|$))|(?:(?:^|\n+)(#{1,6})\s*(.+)(?:\n+|$))|(?:`([^`].*?)`)|( \n\n*|\n{2,}|__|\*\*|[_*]|~~)|(?:{@(\w+)((?:\s+(?:"(?:\\"|[^"])*"|[^"\s}]*))*)})|(?:<\s*(\/?)(\w+)( [^>]+)?>)/gm,
var tokenizer = /((?:^|\n+)(?:\n---+|\* \*(?: \*)+)\n)|(?:^``` *(\w*)\n([\s\S]*?)\n```$)|((?:(?:^|\n+)(?:\t| {2,}).+)+\n*)|((?:(?:^|\n)([>*+-]|\d+\.)\s+.*)+)|(?:!\[([^\]]*?)\]\(([^)]+?)\))|(\[)|(\](?:\(([^)]+?)\))?)|(?:(?:^|\n+)([^\s].*)\n(-{3,}|={3,})(?:\n+|$))|(?:(?:^|\n+)(#{1,6})\s*(.+)(?:\n+|$))|(?:`([^`].*?)`)|( {2}\n\n*|\n{2,}|__|\*\*|[_*]|~~)|(?:{@(\w+)((?:\s+(?:"(?:\\"|[^"])*"|[^"\s}]*))*)})|(?:<\s*(\/?)(\w+)( [^>]+)?>)/gm,
context = [],
out = [],
links = options.referenceLinks || {},
last = 0,
tags = [],
chunk, prev, token, inner, t;
chunk, prev, token, t;
function tag(token) {
var desc = TAGS[token.replace(/\*/g,'_')[1] || ''];
function tag(tagToken) {
var desc = TAGS[tagToken.replace(/\*/g,'_')[1] || ''];
if (desc[1] && tags.length && tags[tags.length - 1].tag === desc[1]
&& tags[tags.length - 1].token === token) {
&& tags[tags.length - 1].tagToken === tagToken) {
if (prev) {
out.push(prev);
prev = '';
}
const tag = tags.pop();
tag.out.push(e(tag.tag, null, out));
out = tag.out;
var currentTag = tags.pop();
currentTag.out.push(e(currentTag.tag, null, out));
out = currentTag.out;
} else {
if (prev) {
out.push(clean(prev));
......@@ -86,8 +93,8 @@ module.exports = function parse(md, options) {
flushTo('p');
tags.push({
tag: 'p',
token,
out
tagToken: tagToken,
out: out
});
out = [];
} else {
......@@ -98,8 +105,8 @@ module.exports = function parse(md, options) {
if (desc[1]) {
tags.push({
tag: desc[1],
token,
out
tagToken: tagToken,
out: out
});
out = [];
}
......@@ -107,21 +114,21 @@ module.exports = function parse(md, options) {
}
function flush() {
let str = '';
var str = '';
while (context.length) str += tag(context[context.length-1]);
return str;
}
function flushTo(tag, justAbove) {
function flushTo(tagType, justAbove) {
var target = 0;
if (!tags.length) {
return;
}
if (tag) {
if (tagType) {
for (target = tags.length - 1; target >= 0; target--) {
if (tags[target].tag === tag) {
if (tags[target].tag === tagType) {
break;
}
}
......@@ -177,7 +184,7 @@ module.exports = function parse(md, options) {
if (options.paragraphs && !tags.length) {
tags.push({
tag: 'p',
out
out: out
});
out = [];
}
......@@ -186,7 +193,7 @@ module.exports = function parse(md, options) {
}
}
md = md.replace(/^\[(.+?)\]:\s*(.+)$/gm, (s, name, url) => {
md = md.replace(/^\[(.+?)\]:\s*(.+)$/gm, function (s, name, url) {
links[name.toLowerCase()] = url;
return '';
}).replace(/^\n+|\n+$/g, '');
......@@ -231,17 +238,17 @@ module.exports = function parse(md, options) {
addPrev();
flushTo('p');
}
const parseOptions = Object.assign({}, options, { referenceLinks: links, paragraphs: false });
var parseOptions = Object.assign({}, options, { referenceLinks: links, paragraphs: false });
if (t === '>') {
chunk = e('blockquote', null, parse(outdent(token[5].replace(/^>\s*/gm, '')),
parseOptions));
} else {
t = t.match(/^\d+\./) ? 'ol' : 'ul';
// const listSplitter = /^(.*)(\n|$)/gm;
const listSplitter = /^[*+-.]\s(.*)/gm;
const items = [];
let item;
while (item = listSplitter.exec(token[5])) {
// var listSplitter = /^(.*)(\n|$)/gm;
var listSplitter = /^[*+-.]\s(.*)/gm;
var items = [];
var item;
while ((item = listSplitter.exec(token[5]))) {
items.push(e('li', null, parse(item[1], parseOptions)));
}
chunk = e(t, null, items);
......@@ -253,7 +260,7 @@ module.exports = function parse(md, options) {
if (options.paragraphs && !tags.length) {
tags.push({
tag: 'p',
out
out: out
});
out = [];
}
......@@ -278,7 +285,7 @@ module.exports = function parse(md, options) {
if (options.paragraphs && !tags.length) {
tags.push({
tag: 'p',
out
out: out
});
out = [];
}
......@@ -286,7 +293,7 @@ module.exports = function parse(md, options) {
tags.push({
index: token.index,
tag: 'a',
out
out: out
});
out = [];
chunk = '';
......@@ -313,7 +320,7 @@ module.exports = function parse(md, options) {
// Tags:
else if (token[18]) {
if (options.customTags && options.customTags[token[18]]) {
let tagTokenizer = /\s+(?:"((?:\\"|[^"])*)"|([^"\s}]+))/g,
var tagTokenizer = /\s+(?:"((?:\\"|[^"])*)"|([^"\s}]+))/g,
parameters = [],
parameter;
while ( (parameter = tagTokenizer.exec(token[19])) ) {
......@@ -343,7 +350,7 @@ module.exports = function parse(md, options) {
index: token.index,
tag: token[21],
attributes: token[22],
out
out: out
});
out = [];
......
"use strict";module.exports=function parse(md,options){var TAGS={"":[null,"em"],_:[null,"strong"],"~":[null,"s"],"\n":["br",null]," ":["br",null],"-":["hr",null]};function outdent(str){return str.replace(RegExp("^"+(str.match(/^(\t| )+/)||"")[0],"gm"),"")}function encodeAttr(str){return(str+"").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}if(!options){options={}}if(!options.removeTags){options.removeTags=["script"]}if(!options.stripTags){options.stripTags=[]}var e;if(!options.createElement){e=function(type,props,children){return{type:type,props:props,children:children}}}else{e=options.createElement}var tokenizer=/((?:^|\n+)(?:\n---+|\* \*(?: \*)+)\n)|(?:^``` *(\w*)\n([\s\S]*?)\n```$)|((?:(?:^|\n+)(?:\t| {2,}).+)+\n*)|((?:(?:^|\n)([>*+-]|\d+\.)\s+.*)+)|(?:!\[([^\]]*?)\]\(([^)]+?)\))|(\[)|(\](?:\(([^)]+?)\))?)|(?:(?:^|\n+)([^\s].*)\n(-{3,}|={3,})(?:\n+|$))|(?:(?:^|\n+)(#{1,6})\s*(.+)(?:\n+|$))|(?:`([^`].*?)`)|( {2}\n\n*|\n{2,}|__|\*\*|[_*]|~~)|(?:{@(\w+)((?:\s+(?:"(?:\\"|[^"])*"|[^"\s}]*))*)})|(?:<\s*(\/?)(\w+)( [^>]+)?>)/gm,context=[],out=[],links=options.referenceLinks||{},last=0,tags=[],chunk,prev,token,t;function tag(token){var desc=TAGS[token.replace(/\*/g,"_")[1]||""];if(desc[1]&&tags.length&&tags[tags.length-1].tag===desc[1]&&tags[tags.length-1].token===token){if(prev){out.push(prev);prev=""}var tag=tags.pop();tag.out.push(e(tag.tag,null,out));out=tag.out}else{if(prev){out.push(clean(prev));prev=""}if(desc[0]){if(options.paragraphs&&desc[0]==="br"&&tags.length&&tags[tags.length-1].tag==="p"){flushTo("p");tags.push({tag:"p",token:token,out:out});out=[]}else{out.push(e(desc[0]))}}if(desc[1]){tags.push({tag:desc[1],token:token,out:out});out=[]}}}function flush(){var str="";while(context.length)str+=tag(context[context.length-1]);return str}function flushTo(tag,justAbove){var target=0;if(!tags.length){return}if(tag){for(target=tags.length-1;target>=0;target--){if(tags[target].tag===tag){break}}if(justAbove){target++}if(target<0||target>=tags.length){return tags.length}}var i;for(i=tags.length-1;i>=target;i--){if(options.removeTags.indexOf(tags[i].tag.toLowerCase())!==-1){chunk=null}else{if(prev){out.push(prev)}if(options.stripTags.indexOf(tags[i].tag.toLowerCase())!==-1){chunk=null;tags[i].out=tags[i].out.concat(out)}else{tags[i].out.push(e(tags[i].tag,tags[i].attributes||null,out))}}prev=null;chunk=null;out=tags[i].out}chunk=null;if(target){tags=tags.slice(0,target)}else{tags=[]}return tags.length}function clean(string){return string.replace(/^\n/,"").replace("\n"," ").replace(/\s+/," ")}function addPrev(){if(prev){prev=clean(prev);if(options.paragraphs&&!tags.length){tags.push({tag:"p",out:out});out=[]}out.push(clean(prev));prev=""}}md=md.replace(/^\[(.+?)\]:\s*(.+)$/gm,function(s,name,url){links[name.toLowerCase()]=url;return""}).replace(/^\n+|\n+$/g,"");while(token=tokenizer.exec(md)){prev=md.substring(last,token.index);last=tokenizer.lastIndex;chunk=token[0];if(prev.match(/[^\\](\\\\)*\\$/)){}else if(token[3]){if(options.paragraphs){flushTo("p")}if(options.highlight){chunk=options.highlight(token[3],token[2])}else{chunk=e("pre",{className:"code"+(token[2]&&" "+token[2].toLowerCase())},[outdent(encodeAttr(token[3]).replace(/^\n+|\n+$/g,""))])}}else if(token[4]){if(options.paragraphs){flushTo("p")}chunk=e("pre",{className:"code poetry"},[outdent(encodeAttr(token[4]).replace(/^\n+|\n+$/g,""))])}else if(token[6]){t=token[6];if(t.match(/\./)){token[5]=token[5].replace(/^\d+/gm,"")}if(options.paragraphs){addPrev();flushTo("p")}var parseOptions=Object.assign({},options,{referenceLinks:links,paragraphs:false});if(t===">"){chunk=e("blockquote",null,parse(outdent(token[5].replace(/^>\s*/gm,"")),parseOptions))}else{t=t.match(/^\d+\./)?"ol":"ul";var listSplitter=/^[*+-.]\s(.*)/gm;var items=[];var item;while(item=listSplitter.exec(token[5])){items.push(e("li",null,parse(item[1],parseOptions)))}chunk=e(t,null,items)}}else if(token[8]){addPrev();if(options.paragraphs&&!tags.length){tags.push({tag:"p",out:out});out=[]}chunk=e("img",{src:encodeAttr(token[8]),alt:encodeAttr(token[7])})}else if(token[10]){flushTo("a",true);if(tags.length){tags[tags.length-1].attributes={href:encodeAttr(token[11]||links[prev.toLowerCase().trim()])};chunk=flush()}flushTo("a")}else if(token[9]){addPrev();if(options.paragraphs&&!tags.length){tags.push({tag:"p",out:out});out=[]}tags.push({index:token.index,tag:"a",out:out});out=[];chunk=""}else if(token[12]||token[14]){t="h"+(token[14]?token[14].length:token[13][0]==="="?1:2);if(options.paragraphs){addPrev();flushTo("p")}chunk=e(t,null,parse(token[12]||token[15],Object.assign({},options,{referenceLinks:links,paragraphs:false})))}else if(token[16]){chunk=e("code",null,[encodeAttr(token[16])])}else if(token[17]||token[1]){tag(token[17]||"--");chunk=null}else if(token[18]){if(options.customTags&&options.customTags[token[18]]){var tagTokenizer=/\s+(?:"((?:\\"|[^"])*)"|([^"\s}]+))/g,parameters=[],parameter;while(parameter=tagTokenizer.exec(token[19])){parameters.push(parameter[1]&&parameter[1].replace(/\\"/g,'"')||parameter[2])}if(parameters.length){chunk=options.customTags[token[18]](parameters)}else{chunk=options.customTags[token[18]]()}}else{chunk=null}}else if(token[21]){chunk="";if(token[20]){if(tags.length){flushTo(token[21])}}else{addPrev();tags.push({index:token.index,tag:token[21],attributes:token[22],out:out});out=[];prev=""}}addPrev();if(chunk){out.push(chunk)}}prev=md.substring(last);addPrev();flushTo();return out};
{
"name": "twitchdown",
"version": "1.0.0",
"version": "1.0.1",
"description": "Dead simple Markdown parser for react-like libraries",
"keywords": [ "react", "markdown", "highlight", "simple" ],
"keywords": [
"react",
"markdown",
"highlight",
"simple"
],
"main": "index.js",
"scripts": {
"test": "ava -v"
"test": "eslint index.js && ava -v",
"lint": "eslint index.js",
"squish": "uglifyjs index.js > index.min.js"
},
"repository": "https://gitlab.com/bytesnz/twitchdown.git",
"author": "Jack Farley <or4e3dsw@bytes.nz>",
"license": "GPL-3.0",
"devDependencies": {
"ava": "^0.25.0"
"ava": "^0.25.0",
"eslint": "^5.1.0",
"uglify-js": "^3.4.4"
}
}