diff --git a/lib/helpers.js b/lib/helpers.js index 9f81a62..cf910f7 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -82,6 +82,16 @@ function getLines(state, begin, end, indent, keepLastLF) { return queue.join(''); } + +function escapeHtml(str) { + if (str.indexOf('&') >= 0) { str = str.replace(/&/g, '&'); } + if (str.indexOf('<') >= 0) { str = str.replace(/') >= 0) { str = str.replace(/>/g, '>'); } + if (str.indexOf('"') >= 0) { str = str.replace(/"/g, '"'); } + return str; +} + + exports.isWhiteSpace = isWhiteSpace; exports.isEmpty = isEmpty; exports.skipEmptyLines = skipEmptyLines; @@ -89,3 +99,4 @@ exports.skipSpaces = skipSpaces; exports.skipChars = skipChars; exports.getLines = getLines; exports.skipCharsBack = skipCharsBack; +exports.escapeHtml = escapeHtml; diff --git a/lib/lexer_inline.js b/lib/lexer_inline.js index 29d5a1f..77b6ed9 100644 --- a/lib/lexer_inline.js +++ b/lib/lexer_inline.js @@ -17,6 +17,7 @@ rules.push(require('./lexer_inline/newline')); rules.push(require('./lexer_inline/escape')); // // +rules.push(require('./lexer_inline/autolink')); rules.push(require('./lexer_inline/entity')); rules.push(require('./lexer_inline/escape_html_char')); diff --git a/lib/lexer_inline/autolink.js b/lib/lexer_inline/autolink.js new file mode 100644 index 0000000..59ecb9d --- /dev/null +++ b/lib/lexer_inline/autolink.js @@ -0,0 +1,57 @@ +// Process autolinks '' + + +var escape = require('../helpers').escapeHtml; + +/*eslint max-len:0*/ +var EMAIL_RE = /^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/; +var AUTOLINK_RE = /^<([a-zA-Z.\-]{1,15}):([^<>\x00-\x20]*)>/; +var linkPrefix = 'coap|doi|javascript|aaa|aaas|about|acap|cap|cid|crid|data|dav|dict|dns|file|ftp|geo|go|gopher|h323|http|https|iax|icap|im|imap|info|ipp|iris|iris.beep|iris.xpc|iris.xpcs|iris.lwz|ldap|mailto|mid|msrp|msrps|mtqp|mupdate|news|nfs|ni|nih|nntp|opaquelocktoken|pop|pres|rtsp|service|session|shttp|sieve|sip|sips|sms|snmp|soap.beep|soap.beeps|tag|tel|telnet|tftp|thismessage|tn3270|tip|tv|urn|vemmi|ws|wss|xcon|xcon-userid|xmlrpc.beep|xmlrpc.beeps|xmpp|z39.50r|z39.50s|adiumxtra|afp|afs|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|chrome|chrome-extension|com-eventbrite-attendee|content|cvs|dlna-playsingle|dlna-playcontainer|dtn|dvb|ed2k|facetime|feed|finger|fish|gg|git|gizmoproject|gtalk|hcp|icon|ipn|irc|irc6|ircs|itms|jar|jms|keyparc|lastfm|ldaps|magnet|maps|market|message|mms|ms-help|msnim|mumble|mvn|notes|oid|palm|paparazzi|platform|proxy|psyc|query|res|resource|rmi|rsync|rtmp|secondlife|sftp|sgn|skype|smb|soldat|spotify|ssh|steam|svn|teamspeak|things|udp|unreal|ut2004|ventrilo|view-source|webcal|wtai|wyciwyg|xfire|xri|ymsgr'.split('|'); + +module.exports = function autolink(state) { + var tail, linkMatch, emailMatch, pos = state.pos; + + if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; } + + tail = state.src.slice(pos); + + if (tail.indexOf('>') < 0) { return false; } + + linkMatch = tail.match(AUTOLINK_RE); + + if (linkMatch) { + if (linkPrefix.indexOf(linkMatch[1]) < 0) { return false; } + + state.tokens.push({ + type: 'link_open', + href: escape(linkMatch[0].slice(1, -1)) + }); + state.tokens.push({ + type: 'text', + content: escape(linkMatch[0].slice(1, -1)) + }); + state.tokens.push({ type: 'link_close' }); + + state.pos += linkMatch[0].length; + return true; + } + + emailMatch = tail.match(EMAIL_RE); + + if (emailMatch) { + state.tokens.push({ + type: 'link_open', + href: 'mailto:' + escape(emailMatch[0].slice(1, -1)) + }); + state.tokens.push({ + type: 'text', + content: escape(emailMatch[0].slice(1, -1)) + }); + state.tokens.push({ type: 'link_close' }); + + state.pos += emailMatch[0].length; + return true; + } + + return false; +}; diff --git a/lib/renderer.js b/lib/renderer.js index d66b9b4..35ff374 100644 --- a/lib/renderer.js +++ b/lib/renderer.js @@ -2,14 +2,7 @@ var assign = require('object-assign'); - - -function escapeHtml(str) { - return str.replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); -} +var escapeHtml = require('./helpers').escapeHtml; // check if we need to hide '\n' before next token @@ -98,6 +91,14 @@ rules.paragraph_close = function (tokens, idx /*, options*/) { }; +rules.link_open = function (tokens, idx /*, options*/) { + return ''; +}; +rules.link_close = function (/*tokens, idx, options*/) { + return ''; +}; + + rules.table_open = function (/*tokens, idx, options*/) { return '\n'; };