marked 0.7.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/helpers.js ADDED
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Helpers
3
+ */
4
+ const escapeTest = /[&<>"']/;
5
+ const escapeReplace = /[&<>"']/g;
6
+ const escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
7
+ const escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
8
+ const escapeReplacements = {
9
+ '&': '&amp;',
10
+ '<': '&lt;',
11
+ '>': '&gt;',
12
+ '"': '&quot;',
13
+ "'": '&#39;'
14
+ };
15
+ const getEscapeReplacement = (ch) => escapeReplacements[ch];
16
+ function escape(html, encode) {
17
+ if (encode) {
18
+ if (escapeTest.test(html)) {
19
+ return html.replace(escapeReplace, getEscapeReplacement);
20
+ }
21
+ } else {
22
+ if (escapeTestNoEncode.test(html)) {
23
+ return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
24
+ }
25
+ }
26
+
27
+ return html;
28
+ }
29
+
30
+ const unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
31
+
32
+ function unescape(html) {
33
+ // explicitly match decimal, hex, and named HTML entities
34
+ return html.replace(unescapeTest, (_, n) => {
35
+ n = n.toLowerCase();
36
+ if (n === 'colon') return ':';
37
+ if (n.charAt(0) === '#') {
38
+ return n.charAt(1) === 'x'
39
+ ? String.fromCharCode(parseInt(n.substring(2), 16))
40
+ : String.fromCharCode(+n.substring(1));
41
+ }
42
+ return '';
43
+ });
44
+ }
45
+
46
+ const caret = /(^|[^\[])\^/g;
47
+ function edit(regex, opt) {
48
+ regex = regex.source || regex;
49
+ opt = opt || '';
50
+ const obj = {
51
+ replace: (name, val) => {
52
+ val = val.source || val;
53
+ val = val.replace(caret, '$1');
54
+ regex = regex.replace(name, val);
55
+ return obj;
56
+ },
57
+ getRegex: () => {
58
+ return new RegExp(regex, opt);
59
+ }
60
+ };
61
+ return obj;
62
+ }
63
+
64
+ const nonWordAndColonTest = /[^\w:]/g;
65
+ const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
66
+ function cleanUrl(sanitize, base, href) {
67
+ if (sanitize) {
68
+ let prot;
69
+ try {
70
+ prot = decodeURIComponent(unescape(href))
71
+ .replace(nonWordAndColonTest, '')
72
+ .toLowerCase();
73
+ } catch (e) {
74
+ return null;
75
+ }
76
+ if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
77
+ return null;
78
+ }
79
+ }
80
+ if (base && !originIndependentUrl.test(href)) {
81
+ href = resolveUrl(base, href);
82
+ }
83
+ try {
84
+ href = encodeURI(href).replace(/%25/g, '%');
85
+ } catch (e) {
86
+ return null;
87
+ }
88
+ return href;
89
+ }
90
+
91
+ const baseUrls = {};
92
+ const justDomain = /^[^:]+:\/*[^/]*$/;
93
+ const protocol = /^([^:]+:)[\s\S]*$/;
94
+ const domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
95
+
96
+ function resolveUrl(base, href) {
97
+ if (!baseUrls[' ' + base]) {
98
+ // we can ignore everything in base after the last slash of its path component,
99
+ // but we might need to add _that_
100
+ // https://tools.ietf.org/html/rfc3986#section-3
101
+ if (justDomain.test(base)) {
102
+ baseUrls[' ' + base] = base + '/';
103
+ } else {
104
+ baseUrls[' ' + base] = rtrim(base, '/', true);
105
+ }
106
+ }
107
+ base = baseUrls[' ' + base];
108
+ const relativeBase = base.indexOf(':') === -1;
109
+
110
+ if (href.substring(0, 2) === '//') {
111
+ if (relativeBase) {
112
+ return href;
113
+ }
114
+ return base.replace(protocol, '$1') + href;
115
+ } else if (href.charAt(0) === '/') {
116
+ if (relativeBase) {
117
+ return href;
118
+ }
119
+ return base.replace(domain, '$1') + href;
120
+ } else {
121
+ return base + href;
122
+ }
123
+ }
124
+
125
+ const noopTest = { exec: function noopTest() {} };
126
+
127
+ function merge(obj) {
128
+ let i = 1,
129
+ target,
130
+ key;
131
+
132
+ for (; i < arguments.length; i++) {
133
+ target = arguments[i];
134
+ for (key in target) {
135
+ if (Object.prototype.hasOwnProperty.call(target, key)) {
136
+ obj[key] = target[key];
137
+ }
138
+ }
139
+ }
140
+
141
+ return obj;
142
+ }
143
+
144
+ function splitCells(tableRow, count) {
145
+ // ensure that every cell-delimiting pipe has a space
146
+ // before it to distinguish it from an escaped pipe
147
+ const row = tableRow.replace(/\|/g, (match, offset, str) => {
148
+ let escaped = false,
149
+ curr = offset;
150
+ while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
151
+ if (escaped) {
152
+ // odd number of slashes means | is escaped
153
+ // so we leave it alone
154
+ return '|';
155
+ } else {
156
+ // add space before unescaped |
157
+ return ' |';
158
+ }
159
+ }),
160
+ cells = row.split(/ \|/);
161
+ let i = 0;
162
+
163
+ if (cells.length > count) {
164
+ cells.splice(count);
165
+ } else {
166
+ while (cells.length < count) cells.push('');
167
+ }
168
+
169
+ for (; i < cells.length; i++) {
170
+ // leading or trailing whitespace is ignored per the gfm spec
171
+ cells[i] = cells[i].trim().replace(/\\\|/g, '|');
172
+ }
173
+ return cells;
174
+ }
175
+
176
+ // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
177
+ // /c*$/ is vulnerable to REDOS.
178
+ // invert: Remove suffix of non-c chars instead. Default falsey.
179
+ function rtrim(str, c, invert) {
180
+ const l = str.length;
181
+ if (l === 0) {
182
+ return '';
183
+ }
184
+
185
+ // Length of suffix matching the invert condition.
186
+ let suffLen = 0;
187
+
188
+ // Step left until we fail to match the invert condition.
189
+ while (suffLen < l) {
190
+ const currChar = str.charAt(l - suffLen - 1);
191
+ if (currChar === c && !invert) {
192
+ suffLen++;
193
+ } else if (currChar !== c && invert) {
194
+ suffLen++;
195
+ } else {
196
+ break;
197
+ }
198
+ }
199
+
200
+ return str.substr(0, l - suffLen);
201
+ }
202
+
203
+ function findClosingBracket(str, b) {
204
+ if (str.indexOf(b[1]) === -1) {
205
+ return -1;
206
+ }
207
+ const l = str.length;
208
+ let level = 0,
209
+ i = 0;
210
+ for (; i < l; i++) {
211
+ if (str[i] === '\\') {
212
+ i++;
213
+ } else if (str[i] === b[0]) {
214
+ level++;
215
+ } else if (str[i] === b[1]) {
216
+ level--;
217
+ if (level < 0) {
218
+ return i;
219
+ }
220
+ }
221
+ }
222
+ return -1;
223
+ }
224
+
225
+ function checkSanitizeDeprecation(opt) {
226
+ if (opt && opt.sanitize && !opt.silent) {
227
+ console.warn('marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options');
228
+ }
229
+ }
230
+
231
+ module.exports = {
232
+ escape,
233
+ unescape,
234
+ edit,
235
+ cleanUrl,
236
+ resolveUrl,
237
+ noopTest,
238
+ merge,
239
+ splitCells,
240
+ rtrim,
241
+ findClosingBracket,
242
+ checkSanitizeDeprecation
243
+ };
package/src/marked.js ADDED
@@ -0,0 +1,186 @@
1
+ const Lexer = require('./Lexer.js');
2
+ const Parser = require('./Parser.js');
3
+ const Tokenizer = require('./Tokenizer.js');
4
+ const Renderer = require('./Renderer.js');
5
+ const TextRenderer = require('./TextRenderer.js');
6
+ const Slugger = require('./Slugger.js');
7
+ const {
8
+ merge,
9
+ checkSanitizeDeprecation,
10
+ escape
11
+ } = require('./helpers.js');
12
+ const {
13
+ getDefaults,
14
+ changeDefaults,
15
+ defaults
16
+ } = require('./defaults.js');
17
+
18
+ /**
19
+ * Marked
20
+ */
21
+ function marked(src, opt, callback) {
22
+ // throw error in case of non string input
23
+ if (typeof src === 'undefined' || src === null) {
24
+ throw new Error('marked(): input parameter is undefined or null');
25
+ }
26
+ if (typeof src !== 'string') {
27
+ throw new Error('marked(): input parameter is of type '
28
+ + Object.prototype.toString.call(src) + ', string expected');
29
+ }
30
+
31
+ if (callback || typeof opt === 'function') {
32
+ if (!callback) {
33
+ callback = opt;
34
+ opt = null;
35
+ }
36
+
37
+ opt = merge({}, marked.defaults, opt || {});
38
+ checkSanitizeDeprecation(opt);
39
+ const highlight = opt.highlight;
40
+ let tokens,
41
+ pending,
42
+ i = 0;
43
+
44
+ try {
45
+ tokens = Lexer.lex(src, opt);
46
+ } catch (e) {
47
+ return callback(e);
48
+ }
49
+
50
+ pending = tokens.length;
51
+
52
+ const done = function(err) {
53
+ if (err) {
54
+ opt.highlight = highlight;
55
+ return callback(err);
56
+ }
57
+
58
+ let out;
59
+
60
+ try {
61
+ out = Parser.parse(tokens, opt);
62
+ } catch (e) {
63
+ err = e;
64
+ }
65
+
66
+ opt.highlight = highlight;
67
+
68
+ return err
69
+ ? callback(err)
70
+ : callback(null, out);
71
+ };
72
+
73
+ if (!highlight || highlight.length < 3) {
74
+ return done();
75
+ }
76
+
77
+ delete opt.highlight;
78
+
79
+ if (!pending) return done();
80
+
81
+ for (; i < tokens.length; i++) {
82
+ (function(token) {
83
+ if (token.type !== 'code') {
84
+ return --pending || done();
85
+ }
86
+ return highlight(token.text, token.lang, function(err, code) {
87
+ if (err) return done(err);
88
+ if (code == null || code === token.text) {
89
+ return --pending || done();
90
+ }
91
+ token.text = code;
92
+ token.escaped = true;
93
+ --pending || done();
94
+ });
95
+ })(tokens[i]);
96
+ }
97
+
98
+ return;
99
+ }
100
+ try {
101
+ opt = merge({}, marked.defaults, opt || {});
102
+ checkSanitizeDeprecation(opt);
103
+ return Parser.parse(Lexer.lex(src, opt), opt);
104
+ } catch (e) {
105
+ e.message += '\nPlease report this to https://github.com/markedjs/marked.';
106
+ if ((opt || marked.defaults).silent) {
107
+ return '<p>An error occurred:</p><pre>'
108
+ + escape(e.message + '', true)
109
+ + '</pre>';
110
+ }
111
+ throw e;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Options
117
+ */
118
+
119
+ marked.options =
120
+ marked.setOptions = function(opt) {
121
+ merge(marked.defaults, opt);
122
+ changeDefaults(marked.defaults);
123
+ return marked;
124
+ };
125
+
126
+ marked.getDefaults = getDefaults;
127
+
128
+ marked.defaults = defaults;
129
+
130
+ /**
131
+ * Use Extension
132
+ */
133
+
134
+ marked.use = function(extension) {
135
+ const opts = merge({}, extension);
136
+ if (extension.renderer) {
137
+ const renderer = marked.defaults.renderer || new Renderer();
138
+ for (const prop in extension.renderer) {
139
+ const prevRenderer = renderer[prop];
140
+ renderer[prop] = (...args) => {
141
+ let ret = extension.renderer[prop].apply(renderer, args);
142
+ if (ret === false) {
143
+ ret = prevRenderer.apply(renderer, args);
144
+ }
145
+ return ret;
146
+ };
147
+ }
148
+ opts.renderer = renderer;
149
+ }
150
+ if (extension.tokenizer) {
151
+ const tokenizer = marked.defaults.tokenizer || new Tokenizer();
152
+ for (const prop in extension.tokenizer) {
153
+ const prevTokenizer = tokenizer[prop];
154
+ tokenizer[prop] = (...args) => {
155
+ let ret = extension.tokenizer[prop].apply(tokenizer, args);
156
+ if (ret === false) {
157
+ ret = prevTokenizer.apply(tokenizer, args);
158
+ }
159
+ return ret;
160
+ };
161
+ }
162
+ opts.tokenizer = tokenizer;
163
+ }
164
+ marked.setOptions(opts);
165
+ };
166
+
167
+ /**
168
+ * Expose
169
+ */
170
+
171
+ marked.Parser = Parser;
172
+ marked.parser = Parser.parse;
173
+
174
+ marked.Renderer = Renderer;
175
+ marked.TextRenderer = TextRenderer;
176
+
177
+ marked.Lexer = Lexer;
178
+ marked.lexer = Lexer.lex;
179
+
180
+ marked.Tokenizer = Tokenizer;
181
+
182
+ marked.Slugger = Slugger;
183
+
184
+ marked.parse = marked;
185
+
186
+ module.exports = marked;
package/src/rules.js ADDED
@@ -0,0 +1,266 @@
1
+ const {
2
+ noopTest,
3
+ edit,
4
+ merge
5
+ } = require('./helpers.js');
6
+
7
+ /**
8
+ * Block-Level Grammar
9
+ */
10
+ const block = {
11
+ newline: /^\n+/,
12
+ code: /^( {4}[^\n]+\n*)+/,
13
+ fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
14
+ hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
15
+ heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
16
+ blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
17
+ list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18
+ html: '^ {0,3}(?:' // optional indentation
19
+ + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
20
+ + '|comment[^\\n]*(\\n+|$)' // (2)
21
+ + '|<\\?[\\s\\S]*?\\?>\\n*' // (3)
22
+ + '|<![A-Z][\\s\\S]*?>\\n*' // (4)
23
+ + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' // (5)
24
+ + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
25
+ + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
26
+ + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
27
+ + ')',
28
+ def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
29
+ nptable: noopTest,
30
+ table: noopTest,
31
+ lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
32
+ // regex template, placeholders will be replaced according to different paragraph
33
+ // interruption rules of commonmark and the original markdown spec:
34
+ _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,
35
+ text: /^[^\n]+/
36
+ };
37
+
38
+ block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
39
+ block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
40
+ block.def = edit(block.def)
41
+ .replace('label', block._label)
42
+ .replace('title', block._title)
43
+ .getRegex();
44
+
45
+ block.bullet = /(?:[*+-]|\d{1,9}\.)/;
46
+ block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/;
47
+ block.item = edit(block.item, 'gm')
48
+ .replace(/bull/g, block.bullet)
49
+ .getRegex();
50
+
51
+ block.list = edit(block.list)
52
+ .replace(/bull/g, block.bullet)
53
+ .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
54
+ .replace('def', '\\n+(?=' + block.def.source + ')')
55
+ .getRegex();
56
+
57
+ block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
58
+ + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
59
+ + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
60
+ + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
61
+ + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
62
+ + '|track|ul';
63
+ block._comment = /<!--(?!-?>)[\s\S]*?-->/;
64
+ block.html = edit(block.html, 'i')
65
+ .replace('comment', block._comment)
66
+ .replace('tag', block._tag)
67
+ .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
68
+ .getRegex();
69
+
70
+ block.paragraph = edit(block._paragraph)
71
+ .replace('hr', block.hr)
72
+ .replace('heading', ' {0,3}#{1,6} ')
73
+ .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
74
+ .replace('blockquote', ' {0,3}>')
75
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
76
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
77
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)')
78
+ .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
79
+ .getRegex();
80
+
81
+ block.blockquote = edit(block.blockquote)
82
+ .replace('paragraph', block.paragraph)
83
+ .getRegex();
84
+
85
+ /**
86
+ * Normal Block Grammar
87
+ */
88
+
89
+ block.normal = merge({}, block);
90
+
91
+ /**
92
+ * GFM Block Grammar
93
+ */
94
+
95
+ block.gfm = merge({}, block.normal, {
96
+ nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
97
+ + ' *([-:]+ *\\|[-| :]*)' // Align
98
+ + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)', // Cells
99
+ table: '^ *\\|(.+)\\n' // Header
100
+ + ' *\\|?( *[-:]+[-| :]*)' // Align
101
+ + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
102
+ });
103
+
104
+ block.gfm.nptable = edit(block.gfm.nptable)
105
+ .replace('hr', block.hr)
106
+ .replace('heading', ' {0,3}#{1,6} ')
107
+ .replace('blockquote', ' {0,3}>')
108
+ .replace('code', ' {4}[^\\n]')
109
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
110
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
111
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)')
112
+ .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
113
+ .getRegex();
114
+
115
+ block.gfm.table = edit(block.gfm.table)
116
+ .replace('hr', block.hr)
117
+ .replace('heading', ' {0,3}#{1,6} ')
118
+ .replace('blockquote', ' {0,3}>')
119
+ .replace('code', ' {4}[^\\n]')
120
+ .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
121
+ .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
122
+ .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)')
123
+ .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
124
+ .getRegex();
125
+
126
+ /**
127
+ * Pedantic grammar (original John Gruber's loose markdown specification)
128
+ */
129
+
130
+ block.pedantic = merge({}, block.normal, {
131
+ html: edit(
132
+ '^ *(?:comment *(?:\\n|\\s*$)'
133
+ + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
134
+ + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
135
+ .replace('comment', block._comment)
136
+ .replace(/tag/g, '(?!(?:'
137
+ + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
138
+ + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
139
+ + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
140
+ .getRegex(),
141
+ def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
142
+ heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
143
+ fences: noopTest, // fences not supported
144
+ paragraph: edit(block.normal._paragraph)
145
+ .replace('hr', block.hr)
146
+ .replace('heading', ' *#{1,6} *[^\n]')
147
+ .replace('lheading', block.lheading)
148
+ .replace('blockquote', ' {0,3}>')
149
+ .replace('|fences', '')
150
+ .replace('|list', '')
151
+ .replace('|html', '')
152
+ .getRegex()
153
+ });
154
+
155
+ /**
156
+ * Inline-Level Grammar
157
+ */
158
+ const inline = {
159
+ escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
160
+ autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
161
+ url: noopTest,
162
+ tag: '^comment'
163
+ + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
164
+ + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
165
+ + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
166
+ + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
167
+ + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>', // CDATA section
168
+ link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
169
+ reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
170
+ nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
171
+ strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
172
+ em: /^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/,
173
+ code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
174
+ br: /^( {2,}|\\)\n(?!\s*$)/,
175
+ del: noopTest,
176
+ text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n))|(?= {2,}\n))/
177
+ };
178
+
179
+ // list of punctuation marks from common mark spec
180
+ // without ` and ] to workaround Rule 17 (inline code blocks/links)
181
+ inline._punctuation = '!"#$%&\'()*+\\-./:;<=>?@\\[^_{|}~';
182
+ inline.em = edit(inline.em).replace(/punctuation/g, inline._punctuation).getRegex();
183
+
184
+ inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
185
+
186
+ inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
187
+ inline._email = /[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])?)+(?![-_])/;
188
+ inline.autolink = edit(inline.autolink)
189
+ .replace('scheme', inline._scheme)
190
+ .replace('email', inline._email)
191
+ .getRegex();
192
+
193
+ inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
194
+
195
+ inline.tag = edit(inline.tag)
196
+ .replace('comment', block._comment)
197
+ .replace('attribute', inline._attribute)
198
+ .getRegex();
199
+
200
+ inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
201
+ inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
202
+ inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
203
+
204
+ inline.link = edit(inline.link)
205
+ .replace('label', inline._label)
206
+ .replace('href', inline._href)
207
+ .replace('title', inline._title)
208
+ .getRegex();
209
+
210
+ inline.reflink = edit(inline.reflink)
211
+ .replace('label', inline._label)
212
+ .getRegex();
213
+
214
+ /**
215
+ * Normal Inline Grammar
216
+ */
217
+
218
+ inline.normal = merge({}, inline);
219
+
220
+ /**
221
+ * Pedantic Inline Grammar
222
+ */
223
+
224
+ inline.pedantic = merge({}, inline.normal, {
225
+ strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
226
+ em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
227
+ link: edit(/^!?\[(label)\]\((.*?)\)/)
228
+ .replace('label', inline._label)
229
+ .getRegex(),
230
+ reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
231
+ .replace('label', inline._label)
232
+ .getRegex()
233
+ });
234
+
235
+ /**
236
+ * GFM Inline Grammar
237
+ */
238
+
239
+ inline.gfm = merge({}, inline.normal, {
240
+ escape: edit(inline.escape).replace('])', '~|])').getRegex(),
241
+ _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
242
+ url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
243
+ _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
244
+ del: /^~+(?=\S)([\s\S]*?\S)~+/,
245
+ text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?= {2,}\n|[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
246
+ });
247
+
248
+ inline.gfm.url = edit(inline.gfm.url, 'i')
249
+ .replace('email', inline.gfm._extended_email)
250
+ .getRegex();
251
+ /**
252
+ * GFM + Line Breaks Inline Grammar
253
+ */
254
+
255
+ inline.breaks = merge({}, inline.gfm, {
256
+ br: edit(inline.br).replace('{2,}', '*').getRegex(),
257
+ text: edit(inline.gfm.text)
258
+ .replace('\\b_', '\\b_| {2,}\\n')
259
+ .replace(/\{2,\}/g, '*')
260
+ .getRegex()
261
+ });
262
+
263
+ module.exports = {
264
+ block,
265
+ inline
266
+ };