/* remarkable 1.0.0 https://github.com//jonschlinkert/remarkable */!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Remarkable=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o`\x00-\x20]+/; var single_quoted = /'[^']*'/; var double_quoted = /"[^"]*"/; /*eslint no-spaced-func:0*/ var attr_value = replace(/(?:unquoted|single_quoted|double_quoted)/) ('unquoted', unquoted) ('single_quoted', single_quoted) ('double_quoted', double_quoted) (); var attribute = replace(/(?:\s+attr_name(?:\s*=\s*attr_value)?)/) ('attr_name', attr_name) ('attr_value', attr_value) (); var open_tag = replace(/<[A-Za-z][A-Za-z0-9]*attribute*\s*\/?>/) ('attribute', attribute) (); var close_tag = /<\/[A-Za-z][A-Za-z0-9]*\s*>/; var comment = //; var processing = /<[?].*?[?]>/; var declaration = /]*>/; var cdata = /])*\]\]>/; var HTML_TAG_RE = replace(/^(?:open_tag|close_tag|comment|processing|declaration|cdata)/) ('open_tag', open_tag) ('close_tag', close_tag) ('comment', comment) ('processing', processing) ('declaration', declaration) ('cdata', cdata) (); module.exports.HTML_TAG_RE = HTML_TAG_RE; },{}],4:[function(require,module,exports){ // List of valid url schemas, accorting to stmd spec // http://jgm.github.io/stmd/spec.html#autolinks 'use strict'; module.exports = [ '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' ]; },{}],5:[function(require,module,exports){ // Default options 'use strict'; module.exports = { html: false, xhtml: false, breaks: false, langprefix: 'language-' }; },{}],6:[function(require,module,exports){ // Common functions for lexers 'use strict'; function isWhiteSpace(ch) { return ch === 0x20; } // Check if line has zero length or contains spaces only function isEmpty(state, line) { return state.bMarks[line] + state.tShift[line] >= state.eMarks[line]; } // Scan lines from given one and return first not empty function skipEmptyLines(state, from) { for (var max = state.lineMax; from < max; from++) { if (state.bMarks[from] + state.tShift[from] < state.eMarks[from]) { break; } } return from; } // Skip spaces from given position. function skipSpaces(state, pos) { for (var max = state.src.length; pos < max; pos++) { if (!isWhiteSpace(state.src.charCodeAt(pos))) { break; } } return pos; } // Skip char codes from given position function skipChars(state, pos, code) { for (var max = state.src.length; pos < max; pos++) { if (state.src.charCodeAt(pos) !== code) { break; } } return pos; } // Skip char codes reverse from given position - 1 function skipCharsBack(state, pos, code, min) { if (pos <= min) { return pos; } while (pos > min) { if (code !== state.src.charCodeAt(--pos)) { return pos + 1; } } return pos; } // cut lines range from source. function getLines(state, begin, end, indent, keepLastLF) { var i, first, last, queue, line = begin; if (begin >= end) { return ''; } // Opt: don't use push queue for single line; if (line + 1 === end) { first = state.bMarks[line] + Math.min(state.tShift[line], indent); last = keepLastLF ? state.bMarks[end] : state.eMarks[end - 1]; return state.src.slice(first, last); } queue = new Array(end - begin); for (i = 0; line < end; line++, i++) { first = state.bMarks[line] + Math.min(state.tShift[line], indent); if (line + 1 < end || keepLastLF) { // TODO: boundary check? last = state.eMarks[line] + 1; } else { last = state.eMarks[line]; } queue[i] = state.src.slice(first, last); } 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; } var UNESCAPE_MD_RE = /\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g; function unescapeMd(str) { if (str.indexOf('\\') < 0) { return str; } return str.replace(UNESCAPE_MD_RE, '$1'); } function isValidEntityCode(c) { /*eslint no-bitwise:0*/ // broken sequence if (c >= 0xD800 && c <= 0xDFFF) { return false; } if (c >= 0xF5 && c <= 0xFF) { return false; } if (c === 0xC0 || c === 0xC1) { return false; } // never used if (c >= 0xFDD0 && c <= 0xFDEF) { return false; } if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false; } // control codes if (c <= 0x1F) { return false; } if (c >= 0x7F && c <= 0x9F) { return false; } // out of range if (c > 0x10FFFF) { return false; } return true; } function fromCodePoint(c) { /*eslint no-bitwise:0*/ if (c > 0xffff) { c -= 0x10000; var surrogate1 = 0xd800 + (c >> 10), surrogate2 = 0xdc00 + (c & 0x3ff); return String.fromCharCode(surrogate1, surrogate2); } return String.fromCharCode(c); } var NAMED_ENTITY_RE = /&([a-z][a-z0-9]{1,31});/gi; var entities = require('./common/entities'); function replaceEntities(str) { if (str.indexOf('&') < 0) { return str; } return str.replace(NAMED_ENTITY_RE, function(match, name) { if (entities.hasOwnProperty(name)) { return entities[name]; } return match; }); } exports.isWhiteSpace = isWhiteSpace; exports.isEmpty = isEmpty; exports.skipEmptyLines = skipEmptyLines; exports.skipSpaces = skipSpaces; exports.skipChars = skipChars; exports.getLines = getLines; exports.skipCharsBack = skipCharsBack; exports.escapeHtml = escapeHtml; exports.unescapeMd = unescapeMd; exports.isValidEntityCode = isValidEntityCode; exports.fromCodePoint = fromCodePoint; exports.replaceEntities = replaceEntities; },{"./common/entities":1}],7:[function(require,module,exports){ // Block lexer 'use strict'; var State = require('./lexer_block/state_block'); var skipEmptyLines = require('./helpers').skipEmptyLines; var isEmpty = require('./helpers').isEmpty; var rules = []; // `list` should be after `hr`, but before `heading` rules.push(require('./lexer_block/code')); rules.push(require('./lexer_block/fences')); rules.push(require('./lexer_block/blockquote')); rules.push(require('./lexer_block/hr')); rules.push(require('./lexer_block/list')); rules.push(require('./lexer_block/heading')); rules.push(require('./lexer_block/lheading')); rules.push(require('./lexer_block/htmlblock')); rules.push(require('./lexer_block/table')); rules.push(require('./lexer_block/paragraph')); function functionName(fn) { var ret = fn.toString(); ret = ret.substr('function '.length); ret = ret.substr(0, ret.indexOf('(')); return ret; } function findByName(self, name) { for (var i = 0; i < self.rules.length; i++) { if (functionName(self.rules[i]) === name) { return i; } } return -1; } // Block Lexer class // function LexerBlock() { this.rules = []; this.rules_named = {}; for (var i = 0; i < rules.length; i++) { this.after(null, rules[i]); } } // Replace/delete lexer function // LexerBlock.prototype.at = function (name, fn) { var index = findByName(name); if (index === -1) { throw new Error('Lexer rule not found: ' + name); } if (fn) { this.rules[index] = fn; } else { this.rules = this.rules.slice(0, index).concat(this.rules.slice(index + 1)); } this.rules_named[functionName(fn)] = fn; }; // Add function to lexer chain before one with given name. // Or add to start, if name not defined // LexerBlock.prototype.before = function (name, fn) { if (!name) { this.rules.unshift(fn); this.rules_named[functionName(fn)] = fn; return; } var index = findByName(name); if (index === -1) { throw new Error('Lexer rule not found: ' + name); } this.rules.splice(index, 0, fn); this.rules_named[functionName(fn)] = fn; }; // Add function to lexer chain after one with given name. // Or add to end, if name not defined // LexerBlock.prototype.after = function (name, fn) { if (!name) { this.rules.push(fn); this.rules_named[functionName(fn)] = fn; return; } var index = findByName(name); if (index === -1) { throw new Error('Lexer rule not found: ' + name); } this.rules.splice(index + 1, 0, fn); this.rules_named[functionName(fn)] = fn; }; // Generate tokens for input range // LexerBlock.prototype.tokenize = function (state, startLine, endLine) { var ok, i, rules = this.rules, len = this.rules.length, line = startLine, hasEmptyLines = false; while (line < endLine) { state.line = line = skipEmptyLines(state, line, endLine); if (line >= endLine) { break; } if (state.tShift[line] < state.blkIndent) { break; } if (state.bqMarks[line] < state.bqLevel) { break; } // Try all possible rules. // On success, rule should: // // - update `state.line` // - update `state.tokens` // - return true for (i = 0; i < len; i++) { ok = rules[i](state, line, endLine, false); if (ok) { break; } } if (!ok) { throw new Error('No matching rules found'); } if (line === state.line) { throw new Error('None of rules updated state.line'); } // set state.tight iff we had an empty line before current tag // i.e. latest empty line should not count state.tight = !hasEmptyLines; // paragraph might "eat" one newline after it in nested lists if (isEmpty(state, state.line - 1)) { hasEmptyLines = true; } line = state.line; if (line < endLine && isEmpty(state, line)) { hasEmptyLines = true; line++; // two empty lines should stop the parser in list mode if (line < endLine && state.listMode && isEmpty(state, line)) { break; } state.line = line; } } }; LexerBlock.prototype.parse = function (src, options, env) { var state, lineStart = 0, lastTabPos = 0; if (!src) { return ''; } if (src.indexOf('\r') >= 0) { src = src.replace(/\r/, ''); } if (src.indexOf('\u00a0') >= 0) { src = src.replace(/\u00a0/g, ' '); } if (src.indexOf('\u2424') >= 0) { src = src.replace(/\u2424/g, '\n'); } // TODO: benchmark it // Replace tabs with proper number of spaces (1..4) if (src.indexOf('\t') >= 0) { src = src.replace(/[\n\t]/g, function (match, offset) { var result; if (src.charCodeAt(offset) === 0x0A) { lineStart = offset + 1; lastTabPos = 0; return match; } result = ' '.slice((offset - lineStart - lastTabPos) % 4); lastTabPos = offset - lineStart + 1; return result; }); } state = new State( src, this, [], options, env ); this.tokenize(state, state.line, state.lineMax); return state.tokens; }; module.exports = LexerBlock; },{"./helpers":6,"./lexer_block/blockquote":8,"./lexer_block/code":9,"./lexer_block/fences":10,"./lexer_block/heading":11,"./lexer_block/hr":12,"./lexer_block/htmlblock":13,"./lexer_block/lheading":14,"./lexer_block/list":15,"./lexer_block/paragraph":16,"./lexer_block/state_block":17,"./lexer_block/table":18}],8:[function(require,module,exports){ // Block quotes 'use strict'; var skipSpaces = require('../helpers').skipSpaces; module.exports = function blockquote(state, startLine, endLine, silent) { var nextLine, lastLineEmpty, oldTShift, oldBMarks, i, oldIndent, oldListMode, rules_named = state.lexer.rules_named, pos = state.bMarks[startLine] + state.tShift[startLine], max = state.eMarks[startLine]; if (pos > max) { return false; } // check the block quote marker if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; } // we know that it's going to be a valid blockquote, // so no point trying to find the end of it in silent mode if (silent) { return true; } // skip one optional space after '>' if (state.src.charCodeAt(pos) === 0x20) { pos++; } state.bqMarks[startLine]++; state.bqLevel++; oldIndent = state.blkIndent; state.blkIndent = 0; oldBMarks = [ state.bMarks[startLine] ]; state.bMarks[startLine] = pos; // check if we have an empty blockquote pos = pos < max ? skipSpaces(state, pos) : pos; lastLineEmpty = pos >= max; oldTShift = [ state.tShift[startLine] ]; state.tShift[startLine] = pos - state.bMarks[startLine]; // Search the end of the block // // Block ends with either: // 1. an empty line outside: // ``` // > test // // ``` // 2. an empty line inside: // ``` // > // test // ``` // 3. another tag // ``` // > test // - - - // ``` for (nextLine = startLine + 1; nextLine < endLine; nextLine++) { pos = state.bMarks[nextLine] + state.tShift[nextLine]; max = state.eMarks[nextLine]; if (pos >= max) { // Case 1: line is not inside the blockquote, and this line is empty. break; } if (state.src.charCodeAt(pos++) === 0x3E/* > */) { state.bqMarks[nextLine]++; // This line is inside the blockquote. // skip one optional space after '>' if (state.src.charCodeAt(pos) === 0x20) { pos++; } oldBMarks.push(state.bMarks[nextLine]); state.bMarks[nextLine] = pos; pos = pos < max ? skipSpaces(state, pos) : pos; lastLineEmpty = pos >= max; oldTShift.push(state.tShift[nextLine]); state.tShift[nextLine] = pos - state.bMarks[nextLine]; continue; } // Case 2: line is not inside the blockquote, and the last line was empty. if (lastLineEmpty) { break; } // Case 3: another tag found. if (rules_named.fences(state, nextLine, endLine, true)) { break; } if (rules_named.hr(state, nextLine, endLine, true)) { break; } if (rules_named.list(state, nextLine, endLine, true)) { break; } if (rules_named.heading(state, nextLine, endLine, true)) { break; } // setex header can't interrupt paragraph // if (rules_named.lheading(state, nextLine, endLine, true)) { break; } if (rules_named.blockquote(state, nextLine, endLine, true)) { break; } if (rules_named.table(state, nextLine, endLine, true)) { break; } //if (rules_named.tag(state, nextLine, endLine, true)) { break; } //if (rules_named.def(state, nextLine, endLine, true)) { break; } oldBMarks.push(state.bMarks[nextLine]); oldTShift.push(state.tShift[nextLine]); } oldListMode = state.listMode; state.listMode = false; state.tokens.push({ type: 'blockquote_open' }); state.lexer.tokenize(state, startLine, nextLine); state.tokens.push({ type: 'blockquote_close' }); state.listMode = oldListMode; // Restore original tShift; this might not be necessary since the parser // has already been here, but just to make sure we can do that. for (i = 0; i < oldTShift.length; i++) { state.bMarks[i + startLine] = oldBMarks[i]; state.tShift[i + startLine] = oldTShift[i]; } state.bqLevel--; state.blkIndent = oldIndent; return true; }; },{"../helpers":6}],9:[function(require,module,exports){ // Code block (4 spaces padded) 'use strict'; var isEmpty = require('../helpers').isEmpty; var getLines = require('../helpers').getLines; module.exports = function code(state, startLine, endLine, silent) { var nextLine, last; if (state.tShift[startLine] - state.blkIndent < 4) { return false; } last = nextLine = startLine + 1; while (nextLine < endLine) { if (state.bqMarks[nextLine] < state.bqLevel) { break; } if (isEmpty(state, nextLine)) { nextLine++; if (state.options.pedantic) { last = nextLine; } continue; } if (state.tShift[nextLine] - state.blkIndent >= 4) { nextLine++; last = nextLine; continue; } break; } if (silent) { return true; } state.tokens.push({ type: 'code', content: getLines(state, startLine, last, 4 + state.blkIndent, true), block: true }); state.line = nextLine; return true; }; },{"../helpers":6}],10:[function(require,module,exports){ // fences (``` lang, ~~~ lang) 'use strict'; var skipSpaces = require('../helpers').skipSpaces; var skipChars = require('../helpers').skipChars; var getLines = require('../helpers').getLines; module.exports = function fences(state, startLine, endLine, silent) { var marker, len, params, nextLine, mem, haveEndMarker = false, pos = state.bMarks[startLine] + state.tShift[startLine], max = state.eMarks[startLine]; if (pos + 3 > max) { return false; } marker = state.src.charCodeAt(pos); if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) { return false; } // scan marker length mem = pos; pos = skipChars(state, pos, marker); len = pos - mem; if (len < 3) { return false; } params = state.src.slice(pos, max).trim(); if (params.indexOf('`') >= 0) { return false; } // Since start is found, we can report success here in validation mode if (silent) { return true; } // search end of block nextLine = startLine; for (;;) { nextLine++; if (nextLine >= endLine) { // unclosed block should be autoclosed by end of document. // also block seems to be autoclosed by end of parent /*if (state.blkLevel === 0) { break; } return false;*/ break; } pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]; max = state.eMarks[nextLine]; if (pos < max && state.tShift[nextLine] < state.blkIndent) { // non-empty line with negative indent should stop the list: // - ``` // test break; } if (pos < max && state.bqMarks[nextLine] < state.bqLevel) { break; } if (state.src.charCodeAt(pos) !== marker) { continue; } pos = skipChars(state, pos, marker); // closing code fence must be at least as long as the opening one if (pos - mem < len) { continue; } // make sure tail has spaces only pos = skipSpaces(state, pos); if (pos < max) { continue; } haveEndMarker = true; // found! break; } // If a fence has heading spaces, they should be removed from its inner block len = state.tShift[startLine]; state.tokens.push({ type: 'fence', params: params, content: getLines(state, startLine + 1, nextLine, len, true) }); state.line = nextLine + (haveEndMarker ? 1 : 0); return true; }; },{"../helpers":6}],11:[function(require,module,exports){ // heading (#, ##, ...) 'use strict'; var isWhiteSpace = require('../helpers').isWhiteSpace; var skipSpaces = require('../helpers').skipSpaces; var skipCharsBack = require('../helpers').skipCharsBack; module.exports = function heading(state, startLine, endLine, silent) { var ch, level, pos = state.bMarks[startLine] + state.tShift[startLine], max = state.eMarks[startLine]; if (pos >= max) { return false; } ch = state.src.charCodeAt(pos); if (ch !== 0x23/* # */ || pos >= max) { return false; } // count heading level level = 1; ch = state.src.charCodeAt(++pos); while (ch === 0x23/* # */ && pos < max && level <= 6) { level++; ch = state.src.charCodeAt(++pos); } if (level > 6 || (pos < max && !isWhiteSpace(ch))) { return false; } // skip spaces before heading text pos = skipSpaces(state, pos); // Now pos contains offset of first heared char // Let's cut tails like ' ### ' from the end of string max = skipCharsBack(state, max, 0x20/* space */, pos); max = skipCharsBack(state, max, 0x23/* # */, pos); if (max < state.eMarks[startLine] && state.src.charCodeAt(max) === 0x23/* # */ && state.src.charCodeAt(max - 1) === 0x5C/* \ */) { max++; } // ## Foo #### // ^^^ max = skipCharsBack(state, max, 0x20/* space */, pos); if (silent) { return true; } state.tokens.push({ type: 'heading_open', level: level }); // only if header is not empty if (pos < max) { state.tokens.push({ type: 'inline', content: state.src.slice(pos, max).trim() }); } state.tokens.push({ type: 'heading_close', level: level }); state.line = startLine + 1; return true; }; },{"../helpers":6}],12:[function(require,module,exports){ // Horizontal rule 'use strict'; var isWhiteSpace = require('../helpers').isWhiteSpace; module.exports = function hr(state, startLine, endLine, silent) { var marker, cnt, ch, pos = state.bMarks[startLine], max = state.eMarks[startLine]; pos += state.tShift[startLine]; if (pos > max) { return false; } marker = state.src.charCodeAt(pos++); // Check hr marker if (marker !== 0x2A/* * */ && marker !== 0x2D/* - */ && marker !== 0x5F/* _ */) { return false; } // markers can be mixed with spaces, but there should be at least 3 one cnt = 1; while (pos < max) { ch = state.src.charCodeAt(pos++); if (ch !== marker && !isWhiteSpace(ch)) { return false; } if (ch === marker) { cnt++; } } if (cnt < 3) { return false; } if (silent) { return true; } state.tokens.push({ type: 'hr' }); state.line = startLine + 1; return true; }; },{"../helpers":6}],13:[function(require,module,exports){ // HTML block 'use strict'; var isEmpty = require('../helpers').isEmpty; var getLines = require('../helpers').getLines; var block_names = require('../common/html_blocks'); var HTML_TAG_OPEN_RE = /^<([a-zA-Z]{1,15})[\s\/>]/; var HTML_TAG_CLOSE_RE = /^<\/([a-zA-Z]{1,15})[\s>]/; function isLetter(ch) { /*eslint no-bitwise:0*/ var lc = ch | 0x20; // to lower case return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */); } module.exports = function htmlblock(state, startLine, endLine, silent) { var ch, match, nextLine, pos = state.bMarks[startLine], max = state.eMarks[startLine], shift = state.tShift[startLine]; pos += shift; if (!state.options.html) { return false; } if (shift > 3 || pos + 2 >= max || state.blkLevel > 0) { return false; } if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; } ch = state.src.charCodeAt(pos + 1); if (ch === 0x21/* ! */ || ch === 0x3F/* ? */) { // Directive start / comment start / processing instruction start if (silent) { return true; } } else if (ch === 0x2F/* / */ || isLetter(ch)) { // Probably start or end of tag if (ch === 0x2F/* \ */) { // closing tag match = state.src.slice(pos, max).match(HTML_TAG_CLOSE_RE); if (!match) { return false; } } else { // opening tag match = state.src.slice(pos, max).match(HTML_TAG_OPEN_RE); if (!match) { return false; } } // Make sure tag name is valid if (block_names.indexOf(match[1].toLowerCase()) < 0) { return false; } if (silent) { return true; } } else { return false; } // If we are here - we detected HTML block. // Let's roll down till empty line (block end). nextLine = startLine + 1; while (nextLine < state.lineMax && !isEmpty(state, nextLine)) { nextLine++; } state.tokens.push({ type: 'htmlblock', content: getLines(state, startLine, nextLine, 0, true) }); state.line = nextLine; return true; }; },{"../common/html_blocks":2,"../helpers":6}],14:[function(require,module,exports){ // lheading (---, ===) 'use strict'; var skipSpaces = require('../helpers').skipSpaces; var skipChars = require('../helpers').skipChars; var skipCharsBack = require('../helpers').skipCharsBack; module.exports = function lheading(state, startLine, endLine, silent) { var marker, pos, max, next = startLine + 1; if (next >= endLine) { return false; } if (state.tShift[next] < state.blkIndent) { return false; } if (state.bqMarks[next] < state.bqLevel) { return false; } // Scan next line if (state.tShift[next] - state.blkIndent > 3) { return false; } pos = state.bMarks[next] + state.tShift[next]; max = state.eMarks[next]; marker = state.src.charCodeAt(pos); if (marker !== 0x2D/* - */ && marker !== 0x3D/* = */) { return false; } pos = skipChars(state, pos, marker); pos = skipSpaces(state, pos); if (pos < max) { return false; } if (silent) { return true; } pos = state.bMarks[startLine] + state.tShift[startLine]; max = skipCharsBack(state, state.eMarks[startLine], 0x20/* space */, pos); state.tokens.push({ type: 'heading_open', level: marker === 0x3D/* = */ ? 1 : 2 }); state.tokens.push({ type: 'inline', content: state.src.slice(pos, max).trim() }); state.tokens.push({ type: 'heading_close', level: marker === 0x3D/* = */ ? 1 : 2 }); state.line = next + 1; return true; }; },{"../helpers":6}],15:[function(require,module,exports){ // Lists 'use strict'; var isEmpty = require('../helpers').isEmpty; var skipSpaces = require('../helpers').skipSpaces; // Search `[-+*][\n ]`, returns next pos arter marker on success // or -1 on fail. function skipBulletListMarker(state, startLine) { var marker, pos, max; pos = state.bMarks[startLine] + state.tShift[startLine]; max = state.eMarks[startLine]; if (pos >= max) { return -1; } marker = state.src.charCodeAt(pos++); // Check bullet if (marker !== 0x2A/* * */ && marker !== 0x2D/* - */ && marker !== 0x2B/* + */) { return -1; } if (pos < max && state.src.charCodeAt(pos) !== 0x20) { // " 1.test " - is not a list item return -1; } return pos; } // Search `\d+[.)][\n ]`, returns next pos arter marker on success // or -1 on fail. function skipOrderedListMarker(state, startLine) { var ch, pos = state.bMarks[startLine] + state.tShift[startLine], max = state.eMarks[startLine]; if (pos + 1 >= max) { return -1; } ch = state.src.charCodeAt(pos++); if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1; } for (;;) { // EOL -> fail if (pos >= max) { return -1; } ch = state.src.charCodeAt(pos++); if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) { continue; } // found valid marker if (ch === 0x29/* ) */ || ch === 0x2e/* . */) { break; } return -1; } if (pos < max && state.src.charCodeAt(pos) !== 0x20/* space */) { // " 1.test " - is not a list item return -1; } return pos; } module.exports = function list(state, startLine, endLine, silent) { var nextLine, indent, oldTShift, oldIndent, oldTight, oldListMode, start, posAfterMarker, max, indentAfterMarker, markerValue, markerCharCode, isOrdered, contentStart, listTokIdx, prevEmptyEnd, rules_named = state.lexer.rules_named; // Detect list type and position after marker if ((posAfterMarker = skipOrderedListMarker(state, startLine)) >= 0) { isOrdered = true; } else if ((posAfterMarker = skipBulletListMarker(state, startLine)) >= 0) { isOrdered = false; } else { return false; } // We should terminate list on style change. Remember first one to compare. markerCharCode = state.src.charCodeAt(posAfterMarker - 1); // For validation mode we can terminate immediately if (silent) { return true; } // Start list listTokIdx = state.tokens.length; if (isOrdered) { start = state.bMarks[startLine] + state.tShift[startLine]; markerValue = Number(state.src.substr(start, posAfterMarker - start - 1)); state.tokens.push({ type: 'ordered_list_open', order: markerValue, tight: true }); } else { state.tokens.push({ type: 'bullet_list_open', tight: true }); } // // Iterate list items // nextLine = startLine; prevEmptyEnd = false; while (nextLine < endLine) { contentStart = skipSpaces(state, posAfterMarker); max = state.eMarks[nextLine]; if (contentStart >= max) { // trimming space in "- \n 3" case, indent is 1 here indentAfterMarker = 1; } else { indentAfterMarker = contentStart - posAfterMarker; } // If we have more than 4 spaces, the indent is 1 // (the rest is just indented code block) if (indentAfterMarker > 4) { indentAfterMarker = 1; } // If indent is less than 1, assume that it's one, example: // "-\n test" if (indentAfterMarker < 1) { indentAfterMarker = 1; } // " - test" // ^^^^^ - calculating total length of this thing indent = (posAfterMarker - state.bMarks[nextLine]) + indentAfterMarker; // Run sublexer & write tokens state.tokens.push({ type: 'list_item_open' }); //nextLine++; oldIndent = state.blkIndent; oldTight = state.tight; oldTShift = state.tShift[startLine]; oldListMode = state.listMode; state.tShift[startLine] = contentStart - state.bMarks[startLine]; state.blkIndent = indent; state.tight = true; state.listMode = true; state.lexer.tokenize(state, startLine, endLine, true); // If any of list item is tight, mark list as tight if (!state.tight || prevEmptyEnd) { state.tokens[listTokIdx].tight = false; } // Item become loose if finish with empty line, // but we should filter last element, because it means list finish prevEmptyEnd = (state.line - startLine) > 1 && isEmpty(state, state.line - 1); state.blkIndent = oldIndent; state.tShift[startLine] = oldTShift; state.tight = oldTight; state.listMode = oldListMode; state.tokens.push({ type: 'list_item_close' }); nextLine = startLine = state.line; contentStart = state.bMarks[startLine]; if (nextLine >= endLine) { break; } if (isEmpty(state, nextLine)) { if (nextLine >= endLine || isEmpty(state, nextLine)) { // two newlines end the list break; } else { nextLine++; } } // // Try to check if list is terminated or continued. // if (state.tShift[nextLine] < state.blkIndent) { break; } if (state.bqMarks[nextLine] < state.bqLevel) { break; } // fail if terminating block found if (rules_named.fences(state, nextLine, endLine, true)) { break; } if (rules_named.blockquote(state, nextLine, endLine, true)) { break; } if (rules_named.hr(state, nextLine, endLine, true)) { break; } // fail if list has another type if (isOrdered) { posAfterMarker = skipOrderedListMarker(state, nextLine); if (posAfterMarker < 0) { break; } } else { posAfterMarker = skipBulletListMarker(state, nextLine); if (posAfterMarker < 0) { break; } } if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break; } } // Finilize list if (isOrdered) { state.tokens.push({ type: 'ordered_list_close' }); } else { state.tokens.push({ type: 'bullet_list_close' }); } state.line = nextLine; return true; }; },{"../helpers":6}],16:[function(require,module,exports){ // Paragraph 'use strict'; var isEmpty = require('../helpers').isEmpty; var getLines = require('../helpers').getLines; module.exports = function paragraph(state, startLine/*, endLine*/) { var endLine, content, ref, t, nextLine = startLine + 1, rules_named = state.lexer.rules_named; endLine = state.lineMax; // jump line-by-line until empty one or EOF for (; nextLine < endLine && !isEmpty(state, nextLine); nextLine++) { // this would be a code block normally, but after paragraph // it's considered a lazy continuation regardless of what's there if (state.tShift[nextLine] - state.blkIndent > 3) { continue; } // Some tags can terminate paragraph without empty line. if (rules_named.fences(state, nextLine, endLine, true)) { break; } if (rules_named.hr(state, nextLine, endLine, true)) { break; } if (rules_named.list(state, nextLine, endLine, true)) { break; } if (rules_named.heading(state, nextLine, endLine, true)) { break; } // setex header can't interrupt paragraph // if (rules_named.lheading(state, nextLine, endLine, true)) { break; } if (rules_named.blockquote(state, nextLine, endLine, true)) { break; } if (rules_named.htmlblock(state, nextLine, endLine, true)) { break; } if (rules_named.table(state, nextLine, endLine, true)) { break; } //if (rules_named.tag(state, nextLine, endLine, true)) { break; } //if (rules_named.def(state, nextLine, endLine, true)) { break; } } content = getLines(state, startLine, nextLine, state.blkIndent, false).trim(); while ((ref = state.lexer.inline.parse_reference(content, state.options, state.env))) { t = state.env.references; t[ref.label] = t[ref.label] || { title: ref.title, href: ref.href }; content = ref.remaining.trim(); } if (content) { state.tokens.push({ type: 'paragraph_open' }); state.tokens.push({ type: 'inline', content: content }); state.tokens.push({ type: 'paragraph_close' }); } state.line = nextLine; return true; }; },{"../helpers":6}],17:[function(require,module,exports){ // Parser state class 'use strict'; function State(src, lexer, tokens, options, env) { var ch, s, start, pos, len, indent, indent_found; // TODO: check if we can move string replaces to parser, to avoid // unnesessary call on shadow clone creation. Or check if we can do // cloning more effectively. Profile first. // Prepare string to parse: // // - replace tabs with spaces // - remove `\r` to simplify newlines check (???) this.src = src; // Shortcuts to simplify nested calls this.lexer = lexer; // TODO: (?) set directly for faster access. this.options = options; this.env = env; // // Internal state vartiables // this.tokens = tokens; this.bMarks = []; // line begin offsets for fast jumps this.eMarks = []; // line end offsets for fast jumps this.tShift = []; // indent for each line // Generate markers. s = this.src; indent = 0; indent_found = false; for (start = pos = indent = 0, len = s.length; pos < len; pos++) { ch = s.charCodeAt(pos); // TODO: check other spaces and tabs too or keep existing regexp replace ?? if (!indent_found && ch === 0x20/* space */) { indent++; } if (!indent_found && ch !== 0x20/* space */) { this.tShift.push(indent); indent_found = true; } if (ch === 0x0D || ch === 0x0A) { this.bMarks.push(start); this.eMarks.push(pos); indent_found = false; indent = 0; start = pos + 1; } if (ch === 0x0D && pos < len && s.charCodeAt(pos) === 0x0A) { pos++; start++; } } if (ch !== 0x0D || ch !== 0x0A) { this.bMarks.push(start); this.eMarks.push(len); this.tShift.push(indent); } // Push fake entry to simplify cache bounds checks this.bMarks.push(s.length); this.eMarks.push(s.length); this.tShift.push(0); // inline lexer variables this.pos = 0; // char index in src // block lexer variables this.blkLevel = 0; this.blkIndent = 0; this.line = 0; // line index in src this.lineMax = this.bMarks.length - 1; // don't count last fake line this.tight = false; // loose/tight mode for lists this.listMode = false; // if true, block parser stops on two newlines // Stuff for blockquotes this.bqLevel = 0; this.bqMarks = []; for (start = 0; start < this.bMarks.length; start++) { this.bqMarks.push(0); } // renderer this.result = ''; } // Create shadow clone of curent state with new input data State.prototype.clone = function clone(src) { return new State( src, this.lexer, this.tokens, this.options ); }; module.exports = State; },{}],18:[function(require,module,exports){ // GFM table, non-standard 'use strict'; function lineMatch(state, line, reg) { var pos = state.bMarks[line], max = state.eMarks[line]; return state.src.substr(pos, max - pos).match(reg); } module.exports = function table(state, startLine, endLine, silent) { var ch, firstLineMatch, secondLineMatch, i, nextLine, m, rows, aligns, t; // should have at least three lines if (startLine + 2 > endLine) { return false; } // first character of the second line should be '|' or '-' ch = state.src.charCodeAt(state.bMarks[startLine + 1] + state.tShift[startLine + 1]); if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */) { return false; } secondLineMatch = lineMatch(state, startLine + 1, /^ *\|?(( *[:-]-+[:-] *\|)+( *[:-]-+[:-] *))\|? *$/); if (!secondLineMatch) { return false; } rows = secondLineMatch[1].split('|'); aligns = []; for (i = 0; i < rows.length; i++) { t = rows[i].trim(); if (t[t.length - 1] === ':') { aligns[i] = t[0] === ':' ? 'center' : 'right'; } else if (t[0] === ':') { aligns[i] = 'left'; } else { aligns[i] = ''; } } firstLineMatch = lineMatch(state, startLine, /^ *\|?(.*?\|.*?)\|? *$/); if (!firstLineMatch) { return false; } rows = firstLineMatch[1].split('|'); if (aligns.length !== rows.length) { return false; } if (silent) { return true; } state.tokens.push({ type: 'table_open' }); state.tokens.push({ type: 'tr_open' }); for (i = 0; i < rows.length; i++) { state.tokens.push({ type: 'th_open', align: aligns[i] }); state.tokens.push({ type: 'inline', content: rows[i].trim() }); state.tokens.push({ type: 'th_close' }); } state.tokens.push({ type: 'tr_close' }); for (nextLine = startLine + 2; nextLine < endLine; nextLine++) { m = lineMatch(state, nextLine, /^ *\|?(.*?\|.*?)\|? *$/); if (!m) { break; } rows = m[1].split('|'); state.tokens.push({ type: 'tr_open' }); for (i = 0; i < rows.length; i++) { state.tokens.push({ type: 'td_open', align: aligns[i] }); state.tokens.push({ type: 'inline', content: rows[i].replace(/^\|? *| *\|?$/g, '') }); state.tokens.push({ type: 'td_close' }); } state.tokens.push({ type: 'tr_close' }); } state.tokens.push({ type: 'table_close' }); state.line = nextLine; return true; }; },{}],19:[function(require,module,exports){ // Inline lexer 'use strict'; var StateInline = require('./lexer_inline/state_inline'); var links = require('./lexer_inline/links'); var skipSpaces = require('./helpers').skipSpaces; //////////////////////////////////////////////////////////////////////////////// // Lexer rules var rules = []; // Pure text rules.push(require('./lexer_inline/text')); rules.push(require('./lexer_inline/newline')); rules.push(require('./lexer_inline/escape')); rules.push(require('./lexer_inline/backticks')); // // rules.push(require('./lexer_inline/emphasis')); rules.push(require('./lexer_inline/links')); rules.push(require('./lexer_inline/autolink')); rules.push(require('./lexer_inline/htmltag')); rules.push(require('./lexer_inline/entity')); rules.push(require('./lexer_inline/escape_html_char')); //////////////////////////////////////////////////////////////////////////////// // Lexer class function functionName(fn) { var ret = fn.toString(); ret = ret.substr('function '.length); ret = ret.substr(0, ret.indexOf('(')); return ret; } function findByName(self, name) { for (var i = 0; i < self.rules.length; i++) { if (functionName(self.rules[i]) === name) { return i; } } return -1; } // Block Lexer class // function LexerInline() { this.rules = []; // Rule to skip pure text // - '{$%@}' reserved for extentions // - '<>"' added for internal html escaping this.textMatch = /^[^\n\\`*_\[\]!&{}$%@<>"]+/; for (var i = 0; i < rules.length; i++) { this.after(null, rules[i]); } } // Replace/delete lexer function // LexerInline.prototype.at = function (name, fn) { var index = findByName(name); if (index === -1) { throw new Error('Lexer rule not found: ' + name); } if (fn) { this.rules[index] = fn; } else { this.rules = this.rules.slice(0, index).concat(this.rules.slice(index + 1)); } }; // Add function to lexer chain before one with given name. // Or add to start, if name not defined // LexerInline.prototype.before = function (name, fn) { if (!name) { this.rules.unshift(fn); return; } var index = findByName(name); if (index === -1) { throw new Error('Lexer rule not found: ' + name); } this.rules.splice(index, 0, fn); }; // Add function to lexer chain after one with given name. // Or add to end, if name not defined // LexerInline.prototype.after = function (name, fn) { if (!name) { this.rules.push(fn); return; } var index = findByName(name); if (index === -1) { throw new Error('Lexer rule not found: ' + name); } this.rules.splice(index + 1, 0, fn); }; // Generate tokens for input range // LexerInline.prototype.tokenize = function (state) { var ok, i, rules = this.rules, len = this.rules.length, end = state.posMax; while (state.pos < end) { // Try all possible rules. // On success, rule should: // // - update `state.pos` // - update `state.tokens` // - return true for (i = 0; i < len; i++) { ok = rules[i](state); if (ok) { break; } } if (ok) { if (state.pos >= end) { break; } continue; } state.pending += state.src[state.pos++]; } if (state.pending) { state.pushPending(); } return state.tokens; }; // Parse input string. // LexerInline.prototype.parse = function (str, options, env) { var state = new StateInline(str, this, options, env); this.tokenize(state); return state.tokens; }; // Parse link reference definition. // LexerInline.prototype.parse_reference = function (str, options) { var state, labelEnd, pos, max, code, start, href, title; if (str.charCodeAt(0) !== 0x5B/* [ */) { return null; } state = new StateInline(str, this, options); labelEnd = links.parseLinkLabel(state, 0); if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return null; } max = state.posMax; // [label]: destination 'title' // ^^^ skip optional whitespace here for (pos = labelEnd + 2; pos < max; pos++) { code = state.src.charCodeAt(pos); if (code !== 0x20 && code !== 0x0A) { break; } } // [label]: destination 'title' // ^^^^^^^^^^^ parse this href = links.parseLinkDestination(state, pos); if (href === null) { return null; } pos = state.pos; // [label]: destination 'title' // ^^^ skipping those spaces start = pos; for (pos = pos + 1; pos < max; pos++) { code = state.src.charCodeAt(pos); if (code !== 0x20 && code !== 0x0A) { break; } } // [label]: destination 'title' // ^^^^^^^ parse this if (pos < max && start !== pos && (title = links.parseLinkTitle(state, pos)) !== null) { pos = state.pos; } else { title = ''; pos = start; } // ensure that the end of the line is empty pos = skipSpaces(state, pos); if (pos < max && state.src.charCodeAt(pos) !== 0x0A) { return null; } return { label: links.normalizeReference(str.slice(1, labelEnd)), title: title, href: href, remaining: str.slice(pos) }; }; module.exports = LexerInline; },{"./helpers":6,"./lexer_inline/autolink":20,"./lexer_inline/backticks":21,"./lexer_inline/emphasis":22,"./lexer_inline/entity":23,"./lexer_inline/escape":24,"./lexer_inline/escape_html_char":25,"./lexer_inline/htmltag":26,"./lexer_inline/links":27,"./lexer_inline/newline":28,"./lexer_inline/state_inline":29,"./lexer_inline/text":30}],20:[function(require,module,exports){ // Process autolinks '' var escapeHtml = require('../helpers').escapeHtml; var url_schemas = require('../common/url_schemas'); /*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,25}):([^<>\x00-\x20]*)>/; 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 (url_schemas.indexOf(linkMatch[1].toLowerCase()) < 0) { return false; } state.push({ type: 'link_open', href: linkMatch[0].slice(1, -1) }); state.push({ type: 'text', content: escapeHtml(linkMatch[0].slice(1, -1)) }); state.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:' + emailMatch[0].slice(1, -1) }); state.tokens.push({ type: 'text', content: escapeHtml(emailMatch[0].slice(1, -1)) }); state.tokens.push({ type: 'link_close' }); state.pos += emailMatch[0].length; return true; } return false; }; },{"../common/url_schemas":4,"../helpers":6}],21:[function(require,module,exports){ // Parse backticks var END_RE = /`+/g; module.exports = function backticks(state) { var start, code, max, marker, match, pos = state.pos, ch = state.src.charCodeAt(pos); if (ch !== 0x60/* ` */) { return false; } start = pos; pos++; max = state.posMax; while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++; } marker = state.src.slice(start, pos); END_RE = /`+/g; END_RE.lastIndex = pos; while ((match = END_RE.exec(state.src)) !== null) { if (match[0].length === marker.length) { code = state.src.slice(pos, END_RE.lastIndex - marker.length); state.push({ type: 'code', content: code .replace(/[ \n]+/g,' ') .trim(), block: false }); state.pos += marker.length * 2 + code.length; return true; } } state.pending += marker; state.pos += marker.length; return true; }; },{}],22:[function(require,module,exports){ // Process *this* and _that_ 'use strict'; function isAlphaNum(code) { return (code >= 0x30 /* 0 */ && code <= 0x39 /* 9 */) || (code >= 0x41 /* A */ && code <= 0x5A /* Z */) || (code >= 0x61 /* a */ && code <= 0x7A /* z */); } // returns the amount of markers (1, 2, 3, 4+), or -1 on failure; // "start" should point at a valid marker // // note: in case if 4+ markers it is still not a valid emphasis, // should be treated as a special case function parseStart(state, start) { var pos = start, lastChar, count, max = Math.min(state.posMax, pos + 4), marker = state.src.charCodeAt(start); lastChar = state.pending.length !== 0 ? state.pending.charCodeAt(state.pending.length - 1) : -1; if (lastChar === marker) { return -1; } while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } if (pos >= max) { return -1; } count = pos - start; // Quoting spec: // // Character can open emphasis iff // 1. it is not part of a sequence of four or more unescaped markers, // 2. it is not followed by whitespace, // 3. it is "_" and it is not preceded by an ASCII alphanumeric character, and // 4. either it is not followed by a marker or it is followed immediately by strong emphasis. if (count >= 4) { // check condition 1 // sequence of four or more unescaped markers can't start an emphasis return count; } // check condition 2, marker followed by whitespace if (state.src.charCodeAt(pos) === 0x20) { return -1; } if (marker === 0x5F /* _ */) { // check condition 3, if it's the beginning of the word // we need to look back for this if (isAlphaNum(lastChar)) { return -1; } } return count; } // returns the amount of markers (1, 2, 3, 4+), or -1 on failure; // "start" should point at a valid marker // // note: in case if 4+ markers it is still not a valid emphasis, // should be treated as a special case function parseEnd(state, start) { var pos = start, lastChar, count, max = Math.min(state.posMax, pos + 4), marker = state.src.charCodeAt(start); lastChar = state.pending.length !== 0 ? state.pending.charCodeAt(state.pending.length - 1) : -1; while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } count = pos - start; // Quoting spec: // // Character can close emphasis iff // 1. it is not part of a sequence of four or more unescaped markers, // 2. it is not preceded by whitespace, // 3. it is not "_" or it is not followed by an ASCII alphanumeric character if (count >= 4) { // check condition 1 // sequence of four or more unescaped markers can't start an emphasis return count; } // check condition 2, marker preceded by whitespace if (lastChar === 0x20) { return -1; } if (marker === 0x5F) { // check condition 3, if it's the end of the word if (pos < max && isAlphaNum(state.src.charCodeAt(pos))) { return -1; } } return count; } module.exports = function emphasis(state/*, silent*/) { var startCount, count, oldLength, oldPending, found, ok, i, oldCount, newCount, len, rules, stack, breakOutOfOuterLoop, max = state.posMax, start = state.pos, haveLiteralAsterisk, marker = state.src.charCodeAt(start); if (marker !== 0x5F/* _ */ && marker !== 0x2A /* * */) { return false; } startCount = parseStart(state, start); if (startCount < 0) { return false; } if (startCount >= 4) { state.pos += startCount; state.pending += state.src.slice(start, startCount); return true; } oldLength = state.tokens.length; oldPending = state.pending; state.pos = start + startCount; stack = [ startCount ]; rules = state.lexer.rules; len = rules.length; while (state.pos < max) { if (state.src.charCodeAt(state.pos) === marker && !haveLiteralAsterisk) { count = parseEnd(state, state.pos); if (count >= 1 && count < 4) { oldCount = stack.pop(); newCount = count; while (oldCount !== newCount) { if (oldCount === 3) { // e.g. `***foo*` stack.push(3 - newCount); break; } if (newCount < oldCount) { // assert(oldCount == 2 && newCount == 1) // i.e. `**foo* bar*` // not valid for now, but might be in the future // eslint is misconfigured, so it doesn't accept "break MAIN;" // here is a crappy workaround breakOutOfOuterLoop = true; break; } // assert(newCount > oldCount) newCount -= oldCount; if (stack.length === 0) { break; } state.pos += oldCount; oldCount = stack.pop(); } if (breakOutOfOuterLoop) { break; } if (stack.length === 0) { startCount = oldCount; found = true; break; } state.pos += count; continue; } count = parseStart(state, state.pos); if (count >= 1) { stack.push(count); state.pos += count; continue; } } for (i = 0; i < len; i++) { if (rules[i] !== emphasis) { ok = rules[i](state); } if (ok) { break; } } if (ok) { haveLiteralAsterisk = false; } else { haveLiteralAsterisk = state.src.charCodeAt(state.pos) === marker; state.pending += state.src[state.pos]; state.pos++; } } // restore old state state.tokens.length = oldLength; state.pending = oldPending; if (!found) { // parser failed to find ending tag, so it's not valid emphasis state.pos = start; return false; } // found! state.posMax = state.pos; state.pos = start + startCount; if (state.pending) { state.pushPending(); } if (startCount === 2 || startCount === 3) { state.push({ type: 'strong_open' }); } if (startCount === 1 || startCount === 3) { state.push({ type: 'em_open' }); } state.lexer.tokenize(state); if (startCount === 1 || startCount === 3) { state.push({ type: 'em_close' }); } if (startCount === 2 || startCount === 3) { state.push({ type: 'strong_close' }); } state.pos = state.posMax + startCount; state.posMax = max; return true; }; },{}],23:[function(require,module,exports){ // Proceess html entity - {, ¯, ", ... 'use strict'; var entities = require('../common/entities'); var escapeHtml = require('../helpers').escapeHtml; var isValidEntityCode = require('../helpers').isValidEntityCode; var fromCodePoint = require('../helpers').fromCodePoint; var DIGITAL_RE = /^&#((?:x[a-f0-9]{1,8}|[0-9]{1,8}));/i; var NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i; module.exports = function entity(state) { var ch, code, match, pos = state.pos, max = state.posMax; if (state.src.charCodeAt(pos) !== 0x26/* & */) { return false; } if (pos + 1 < max) { ch = state.src.charCodeAt(pos + 1); if (ch === 0x23 /* # */) { match = state.src.slice(pos).match(DIGITAL_RE); if (match) { code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10); state.pending += isValidEntityCode(code) ? escapeHtml(fromCodePoint(code)) : fromCodePoint(0xFFFD); state.pos += match[0].length; return true; } } else { match = state.src.slice(pos).match(NAMED_RE); if (match) { if (entities.hasOwnProperty(match[1])) { state.pending += escapeHtml(entities[match[1]]); state.pos += match[0].length; return true; } } } } state.pending += '&'; state.pos++; return true; }; },{"../common/entities":1,"../helpers":6}],24:[function(require,module,exports){ // Proceess escaped chars and hardbreaks var ESCAPED = '\\!"#$%&\'()*+,./:;<=>?@[]^_`{|}~-' .split('') .map(function(ch) { return ch.charCodeAt(0); }); module.exports = function escape(state) { var ch, pos = state.pos, max = state.posMax; if (state.src.charCodeAt(pos) !== 0x5C/* \ */) { return false; } pos++; if (pos < max) { ch = state.src.charCodeAt(pos); if (ESCAPED.indexOf(ch) >= 0) { // escape html chars if needed if (ch === 0x26/* & */) { state.pending += '&'; } else if (ch === 0x3C/* < */) { state.pending += '<'; } else if (ch === 0x3E/* > */) { state.pending += '>'; } else if (ch === 0x22/* " */) { state.pending += '"'; } else { state.pending += state.src[pos]; } state.pos += 2; return true; } if (ch === 0x0A) { state.push({ type: 'hardbreak' }); pos++; // skip leading whitespaces from next line while (pos < max && state.src.charCodeAt(pos) === 0x20) { pos++; } state.pos = pos; return true; } } state.pending += '\\'; state.pos++; return true; }; },{}],25:[function(require,module,exports){ // Process < > " (& was processed in markdown escape) module.exports = function escape_html_char(state) { var ch = state.src.charCodeAt(state.pos); if (ch === 0x3C/* < */) { state.pending += '<'; } else if (ch === 0x3E/* > */) { state.pending += '>'; } else if (ch === 0x22/* " */) { state.pending += '"'; } else { return false; } state.pos++; return true; }; },{}],26:[function(require,module,exports){ // Process html tags 'use strict'; var HTML_TAG_RE = require('../common/html_re').HTML_TAG_RE; function isLetter(ch) { /*eslint no-bitwise:0*/ var lc = ch | 0x20; // to lower case return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */); } module.exports = function htmltag(state) { var ch, match, max, pos = state.pos; if (!state.options.html) { return false; } // Check start max = state.posMax; if (state.src.charCodeAt(pos) !== 0x3C/* < */ || pos + 2 >= max) { return false; } // Quick fail on second char ch = state.src.charCodeAt(pos + 1); if (ch !== 0x21/* ! */ && ch !== 0x3F/* ? */ && ch !== 0x2F/* / */ && !isLetter(ch)) { return false; } match = state.src.slice(pos).match(HTML_TAG_RE); if (!match) { return false; } state.push({ type: 'htmltag', content: state.src.slice(pos, pos + match[0].length) }); //console.log(state.tokens) state.pos += match[0].length; return true; }; },{"../common/html_re":3}],27:[function(require,module,exports){ // Process [links]( "stuff") 'use strict'; // // Parse link label // // this function assumes that first character ("[") already matches; // returns the end of the label function parseLinkLabel(state, start) { var level, rules, len, found, marker, i, ok, labelEnd = -1, max = state.posMax, oldPos = state.pos, oldLength = state.tokens.length, oldPending = state.pending; state.pos = start + 1; level = 1; rules = state.lexer.rules; len = rules.length; while (state.pos < max) { marker = state.src.charCodeAt(state.pos); if (marker === 0x5B /* [ */) { level++; } else if (marker === 0x5D /* ] */) { level--; if (level === 0) { found = true; break; } } for (i = 0; i < len; i++) { // skip emphasis because it has lower priority, compare: // [foo *bar]()* // [foo `bar]()` if (rules[i].name !== 'emphasis' && rules[i].name !== 'links') { ok = rules[i](state); } if (ok) { break; } } if (!ok) { state.pending += state.src[state.pos++]; } } if (found) { labelEnd = state.pos; } // restore old state state.pos = oldPos; state.tokens.length = oldLength; state.pending = oldPending; return labelEnd; } // // Parse link destination // // on success it returns a string and updates state.pos; // on failure it returns null function parseLinkDestination(state, pos) { var code, level, max = state.posMax, href = ''; if (state.src.charCodeAt(pos) === 0x3C /* < */) { pos++; while (pos < max) { code = state.src.charCodeAt(pos); if (code === 0x0A /* \n */) { return null; } if (code === 0x3E /* > */) { state.pos = pos + 1; return href; } if (code === 0x5C /* \ */ && pos + 1 < max) { pos++; href += state.src[pos++]; continue; } href += state.src[pos++]; } // no closing '>' return null; } // this should be ... } else { ... branch level = 0; while (pos < max) { code = state.src.charCodeAt(pos); if (code === 0x20) { break; } // ascii control characters if (code < 0x20 || code === 0x7F) { break; } if (code === 0x5C /* \ */ && pos + 1 < max) { pos++; href += state.src[pos++]; continue; } if (code === 0x28 /* ( */) { level++; if (level > 1) { break; } } if (code === 0x29 /* ) */) { level--; if (level < 0) { break; } } href += state.src[pos++]; } if (!href.length) { return null; } state.pos = pos; return href; } // // Parse link title // // on success it returns a string and updates state.pos; // on failure it returns null function parseLinkTitle(state, pos) { var title, code, max = state.posMax, marker = state.src.charCodeAt(pos); if (marker !== 0x22 /* " */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return null; } pos++; title = ''; // if opening marker is "(", switch it to closing marker ")" if (marker === 0x28) { marker = 0x29; } while (pos < max) { code = state.src.charCodeAt(pos); if (code === marker) { state.pos = pos + 1; return title; } if (code === 0x5C /* \ */ && pos + 1 < max) { pos++; title += state.src[pos++]; continue; } title += state.src[pos++]; } return null; } function normalizeReference(str) { return str.trim().replace(/\s+/g, ' ').toLowerCase(); } function links(state) { var labelStart, labelEnd, label, href, title, pos, ref, code, isImage = false, max = state.posMax, start = state.pos, marker = state.src.charCodeAt(start); if (marker === 0x21/* ! */) { isImage = true; marker = state.src.charCodeAt(++start); } if (marker !== 0x5B/* [ */) { return false; } labelStart = start + 1; labelEnd = parseLinkLabel(state, start); // parser failed to find ']', so it's not a valid link if (pos < 0) { return false; } pos = labelEnd + 1; if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) { // // Inline link // // [link]( "title" ) // ^^ skipping these spaces pos++; for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (code !== 0x20 && code !== 0x0A) { break; } } if (pos >= max) { return false; } // [link]( "title" ) // ^^^^^^ parsing link destination start = pos; href = parseLinkDestination(state, pos); if (href !== null) { pos = state.pos; } else { href = ''; } // [link]( "title" ) // ^^ skipping these spaces start = pos; for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (code !== 0x20 && code !== 0x0A) { break; } } // [link]( "title" ) // ^^^^^^^ parsing link title if (pos < max && start !== pos && (title = parseLinkTitle(state, pos)) !== null) { pos = state.pos; // [link]( "title" ) // ^^ skipping these spaces for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (code !== 0x20 && code !== 0x0A) { break; } } } else { title = ''; } if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) { state.pos = labelStart - 1; return false; } pos++; } else { // // Link reference // // [foo] [bar] // ^^ optional whitespace (can include newlines) for (; pos < max; pos++) { code = state.src.charCodeAt(pos); if (code !== 0x20 && code !== 0x0A) { break; } } if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) { start = pos + 1; pos = parseLinkLabel(state, pos); if (pos >= 0) { label = state.src.slice(start, pos++); } else { pos = start - 1; } } // covers label === '' and label === undefined // (collapsed reference link and shortcut reference link respectively) if (!label) { label = state.src.slice(labelStart, labelEnd); } ref = state.env.references[normalizeReference(label)]; if (!ref) { state.pos = labelStart - 1; return false; } href = ref.href; title = ref.title; } // // We found the end of the link, and know for a fact it's a valid link; // so all that's left to do is to call tokenizer. // state.pos = labelStart; state.posMax = labelEnd; if (state.pending) { state.pushPending(); } if (isImage) { state.push({ type: 'image', src: href, title: title, alt: state.src.substr(labelStart, labelEnd - labelStart) }); } else { state.push({ type: 'link_open', href: href, title: title }); state.lexer.tokenize(state); state.push({ type: 'link_close' }); } state.pos = pos; state.posMax = max; return true; } module.exports = links; module.exports.parseLinkLabel = parseLinkLabel; module.exports.parseLinkDestination = parseLinkDestination; module.exports.parseLinkTitle = parseLinkTitle; module.exports.normalizeReference = normalizeReference; },{}],28:[function(require,module,exports){ // Proceess '\n' module.exports = function escape(state) { var pmax, max, pos = state.pos; if (state.src.charCodeAt(pos) !== 0x0A/* \n */) { return false; } pmax = state.pending.length - 1; max = state.posMax; // ' \n' -> hardbreak // Lookup in pending chars is bad practice! Don't copy to other rules! // Pending string is stored in concat mode, indexed lookups will cause // convertion to flat mode. if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) { if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) { state.pending = state.pending.replace(/ +$/, ''); state.push({ type: 'hardbreak' }); } else { state.pending = state.pending.slice(0, -1); state.push({ type: 'softbreak' }); } } else { state.push({ type: 'softbreak' }); } pos++; // skip heading spaces for next line while (pos < max && state.src.charCodeAt(pos) === 0x20) { pos++; } state.pos = pos; return true; }; },{}],29:[function(require,module,exports){ // Inline parser state 'use strict'; function StateInline(src, lexer, options, env) { this.src = src; this.env = env; this.options = options; this.lexer = lexer; this.tokens = []; this.pos = 0; this.pending = ''; this.posMax = this.src.length; } StateInline.prototype.pushPending = function () { var pending = this.pending; this.tokens.push({ type: 'text', content: pending }); this.pending = ''; }; StateInline.prototype.push = function (token) { if (this.pending) { this.pushPending(); } this.tokens.push(token); }; module.exports = StateInline; },{}],30:[function(require,module,exports){ // Skip text characters for text token, place those to pendibg buffer // and increment current pos module.exports = function text(state) { var match = state.src.slice(state.pos).match(state.lexer.textMatch); if (!match) { return false; } state.pending += match[0]; state.pos += match[0].length; return true; }; },{}],31:[function(require,module,exports){ // Main perser class 'use strict'; var assign = require('object-assign'); var Renderer = require('./renderer'); var LexerBlock = require('./lexer_block'); var LexerInline = require('./lexer_inline'); var defaults = require('./defaults'); // Main class // function Parser(options) { this.options = assign({}, defaults); this.state = null; this.inline = new LexerInline(); this.block = new LexerBlock(); this.renderer = new Renderer(); // a bunch of cross-references between parsers // used for link reference definitions this.block.inline = this.inline; if (options) { this.set(options); } } Parser.prototype.set = function (options) { assign(this.options, options); }; Parser.prototype.render = function (src) { var tokens, tok, i, l, env = { references: Object.create(null) }; // Parse blocks tokens = this.block.parse(src, this.options, env); // Parse inlines for (i = 0, l = tokens.length; i < l; i++) { tok = tokens[i]; if (tok.type === 'inline') { tok.children = this.inline.parse(tok.content, this.options, env); } } // Render return this.renderer.render(tokens, this.options, env); }; module.exports = Parser; },{"./defaults":5,"./lexer_block":7,"./lexer_inline":19,"./renderer":32,"object-assign":33}],32:[function(require,module,exports){ 'use strict'; var assign = require('object-assign'); var escapeHtml = require('./helpers').escapeHtml; var unescapeMd = require('./helpers').unescapeMd; var replaceEntities = require('./helpers').replaceEntities; function escapeUrl(str) { try { return encodeURI(str); } catch (__) {} return ''; } function unescapeUrl(str) { try { return decodeURI(str); } catch (__) {} return ''; } // check if we need to hide '\n' before next token function getBreak(tokens, idx) { if (++idx < tokens.length && tokens[idx].type === 'list_item_close') { return ''; } return '\n'; } var rules = {}; rules.blockquote_open = function (/*tokens, idx, options*/) { return '
\n'; }; rules.blockquote_close = function (tokens, idx /*, options*/) { return '
' + getBreak(tokens, idx); }; rules.code = function (tokens, idx /*, options*/) { if (tokens[idx].block) { return '
' + escapeHtml(tokens[idx].content) + '
' + getBreak(tokens, idx); } return '' + escapeHtml(tokens[idx].content) + ''; }; rules.fence = function (tokens, idx, options) { var token = tokens[idx]; var langMark = ''; var langPrefix = options.langprefix || ''; var params; if (token.params) { params = token.params.split(/ +/g); langMark = ' class="' + langPrefix + escapeHtml(replaceEntities(unescapeMd(params[0]))) + '"'; } return '
'
        + escapeHtml(token.content)
        + '
' + getBreak(tokens, idx); }; rules.heading_open = function (tokens, idx /*, options*/) { return ''; }; rules.heading_close = function (tokens, idx /*, options*/) { return '\n'; }; rules.hr = function (tokens, idx, options) { return (options.xhtml ? '
' : '
') + getBreak(tokens, idx); }; rules.bullet_list_open = function (/*tokens, idx, options*/) { return '
    \n'; }; rules.bullet_list_close = function (tokens, idx /*, options*/) { return '
' + getBreak(tokens, idx); }; rules.list_item_open = function (/*tokens, idx, options*/) { return '
  • '; }; rules.list_item_close = function (/*tokens, idx, options*/) { return '
  • \n'; }; rules.ordered_list_open = function (tokens, idx /*, options*/) { var token = tokens[idx]; return ' 1 ? ' start="' + token.order + '"' : '') + '>\n'; }; rules.ordered_list_close = function (tokens, idx /*, options*/) { return '' + getBreak(tokens, idx); }; rules.paragraph_open = function (/*tokens, idx, options*/) { return '

    '; }; rules.paragraph_close = function (tokens, idx /*, options*/) { return '

    ' + getBreak(tokens, idx); }; rules.link_open = function (tokens, idx /*, options*/) { var title = tokens[idx].title ? (' title="' + escapeHtml(replaceEntities(tokens[idx].title)) + '"') : ''; return ''; }; rules.link_close = function (/*tokens, idx, options*/) { return ''; }; rules.image = function (tokens, idx, options) { var src = ' src="' + escapeHtml(escapeUrl(tokens[idx].src)) + '"'; var title = tokens[idx].title ? (' title="' + escapeHtml(replaceEntities(tokens[idx].title)) + '"') : ''; var alt = ' alt="' + (tokens[idx].alt ? escapeHtml(replaceEntities(tokens[idx].alt)) : '') + '"'; var suffix = options.xhtml ? ' /' : ''; return ''; }; rules.table_open = function (/*tokens, idx, options*/) { return '\n'; }; rules.table_close = function (/*tokens, idx, options*/) { return '
    \n'; }; rules.tr_open = function (/*tokens, idx, options*/) { return '\n'; }; rules.tr_close = function (/*tokens, idx, options*/) { return '\n'; }; rules.th_open = function (tokens, idx /*, options*/) { var token = tokens[idx]; return ''; }; rules.th_close = function (/*tokens, idx, options*/) { return '\n'; }; rules.td_open = function (tokens, idx /*, options*/) { var token = tokens[idx]; return ''; }; rules.td_close = function (/*tokens, idx, options*/) { return '\n'; }; rules.strong_open = function(/*tokens, idx, options*/) { return ''; }; rules.strong_close = function(/*tokens, idx, options*/) { return ''; }; rules.em_open = function(/*tokens, idx, options*/) { return ''; }; rules.em_close = function(/*tokens, idx, options*/) { return ''; }; rules.hardbreak = function (tokens, idx, options) { return options.xhtml ? '
    \n' : '
    \n'; }; rules.softbreak = function (tokens, idx, options) { return options.breaks ? (options.xhtml ? '
    \n' : '
    \n') : '\n'; }; rules.text = function (tokens, idx /*, options*/) { return tokens[idx].content; }; rules.htmlblock = function (tokens, idx /*, options*/) { return tokens[idx].content; }; rules.htmltag = function (tokens, idx /*, options*/) { return tokens[idx].content; }; // Renderer class function Renderer() { // Clone rules object to allow local modifications this.rules = assign({}, rules); } Renderer.prototype.render = function (tokens, options) { var i, len, rule, name, next, result = '', rules = this.rules, tightStack = []; // wrap paragraphs on top level by default var tight = false; for (i = 0, len = tokens.length; i < len; i++) { name = tokens[i].type; rule = rules[name]; // Dirty stack machine to track lists style (loose/tight) if (name === 'ordered_list_open' || name === 'bullet_list_open') { tightStack.push(tight); tight = tokens[i].tight; } if (name === 'ordered_list_close' || name === 'bullet_list_close') { tight = tightStack.pop(); } if (name === 'blockquote_open') { tightStack.push(tight); tight = false; } if (name === 'blockquote_close') { tight = tightStack.pop(); } // in tight mode just ignore paragraphs for lists // TODO - track right nesting to blockquotes if (name === 'paragraph_open' && tight) { continue; } if (name === 'paragraph_close' && tight) { // Quick hack - texts should have LF if followed by blocks if (i + 1 < tokens.length) { next = tokens[i + 1].type; if (next === 'bullet_list_open' || next === 'ordered_list_open' || next === 'blockquote_open') { result += '\n'; } } continue; } if (tokens[i].type === 'inline') { result += this.render(tokens[i].children, options); } else { // TODO: temporary check if (!rule) { throw new Error('Renderer error: unknown token ' + name); } result += rule(tokens, i, options); } } return result; }; module.exports = Renderer; },{"./helpers":6,"object-assign":33}],33:[function(require,module,exports){ 'use strict'; function ToObject(val) { if (val == null) { throw new TypeError('Object.assign cannot be called with null or undefined'); } return Object(val); } module.exports = Object.assign || function (target, source) { var pendingException; var from; var keys; var to = ToObject(target); for (var s = 1; s < arguments.length; s++) { from = arguments[s]; keys = Object.keys(Object(from)); for (var i = 0; i < keys.length; i++) { try { to[keys[i]] = from[keys[i]]; } catch (err) { if (pendingException === undefined) { pendingException = err; } } } } if (pendingException) { throw pendingException; } return to; }; },{}]},{},[])("./") });