@subiz/widget-v4 4.0.96 → 4.0.98
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/assets/less/form.less +1 -1
- package/compiled_src/chatbox/Widget.js +111 -0
- package/package.json +1 -1
- package/src/chatbox/Widget.js +138 -0
- package/dist/132.js +0 -6541
- package/dist/178.js +0 -406
- package/dist/184b3f119b0.132.js +0 -1
- package/dist/184b3f119b0.178.js +0 -1
- package/dist/184b3f119b0.213.js +0 -1
- package/dist/184b3f119b0.335.js +0 -1
- package/dist/184b3f119b0.362.js +0 -1
- package/dist/184b3f119b0.441.js +0 -1
- package/dist/184b3f119b0.605.js +0 -1
- package/dist/184b3f119b0.678.js +0 -1
- package/dist/184b3f119b0.782.js +0 -1
- package/dist/184b3f119b0.app.js +0 -1
- package/dist/184b3f119b0.index.html +0 -26
- package/dist/184b3f119b0.library.html +0 -26
- package/dist/184b3f119b0.library.js +0 -1
- package/dist/184b3f119b0.preview.html +0 -759
- package/dist/184b3f119b0.preview.js +0 -1
- package/dist/184b3f119b0.screenshoot.js +0 -1
- package/dist/213.js +0 -2950
- package/dist/335.js +0 -376
- package/dist/362.js +0 -107
- package/dist/441.js +0 -2840
- package/dist/605.js +0 -297
- package/dist/678.js +0 -107
- package/dist/782.js +0 -107
- package/dist/HASH +0 -1
- package/dist/assets/img/Facebook.64607ec.png +0 -0
- package/dist/assets/img/Zalo.6845707.png +0 -0
- package/dist/assets/img/award1a.1a58e10.png +0 -0
- package/dist/assets/img/award3a.3b74423.png +0 -0
- package/dist/assets/img/award4a.ed6ccd4.png +0 -0
- package/dist/assets/img/award5.39eb7ae.png +0 -0
- package/dist/assets/img/bubble_default.7d5e4ab.svg +0 -20
- package/dist/assets/img/caret.998eb8f.svg +0 -1
- package/dist/assets/img/convos_empty.2353007.svg +0 -72
- package/dist/assets/img/default.06e6ee0.jpg +0 -0
- package/dist/assets/img/default_avatar.5b74dc1.png +0 -0
- package/dist/assets/img/done_gray.d7e8203.svg +0 -4
- package/dist/assets/img/done_green.b817fd4.svg +0 -4
- package/dist/assets/img/emoji/messenger/sub_23.529_58.824.d5faf14.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_23.529_60.784.1420241.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_25.490_0.000.1e6b2c0.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_25.490_45.098.3dfbc08.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_25.490_5.882.4b49e94.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_27.451_72.549.7114f58.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_27.451_84.314.231e2b7.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_27.451_96.078.ddbb008.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_29.412_5.882.61f3359.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_100.000.6df72bc.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_45.098.3d7a7ad.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_47.059.0f4d6e2.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_54.902.65724c1.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_64.706.9da3cba.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_72.549.edca5cf.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_78.431.f910f2a.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_88.235.def4e71.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_11.765.49c03d0.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_27.451.46b54e5.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_29.412.e36d284.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_3.922.bb191b0.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_35.294.af7b927.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_7.843.98f2a99.png +0 -0
- package/dist/assets/img/empty.29bed2d.svg +0 -23
- package/dist/assets/img/empty_1.0b98af0.svg +0 -11
- package/dist/assets/img/examplte_logo.f86535f.svg +0 -1
- package/dist/assets/img/external-link.90577cc.svg +0 -1
- package/dist/assets/img/fb_inverse_circle.36c2cfc.png +0 -0
- package/dist/assets/img/ghn.070f8e3.svg +0 -17
- package/dist/assets/img/ghtk.326eac1.svg +0 -18
- package/dist/assets/img/image_default.be0698b.png +0 -0
- package/dist/assets/img/info.ebce7ea.svg +0 -1
- package/dist/assets/img/loader.37000a7.svg +0 -1
- package/dist/assets/img/loading_static.8f403ae.svg +0 -10
- package/dist/assets/img/main-service1.d536cc2.png +0 -0
- package/dist/assets/img/main-service2.9b99549.png +0 -0
- package/dist/assets/img/not_found_search.2ddb8d1.png +0 -0
- package/dist/assets/img/package.8d37d0f.svg +0 -5
- package/dist/assets/img/package_fade.763c001.svg +0 -1
- package/dist/assets/img/rating--average.1ea492c.svg +0 -12
- package/dist/assets/img/rating--great.e3d712e.svg +0 -16
- package/dist/assets/img/rating--poor.2938a25.svg +0 -12
- package/dist/assets/img/search.f9705ff.svg +0 -1
- package/dist/assets/img/send.6db52a9.svg +0 -3
- package/dist/assets/img/shop.f7dc7d8.svg +0 -1
- package/dist/assets/img/shop_faded.df7845a.svg +0 -1
- package/dist/assets/img/subiz-mono.877e9f5.svg +0 -3
- package/dist/assets/img/x.26fdfa3.svg +0 -5
- package/dist/malicious-app.js +0 -13
- package/dist/screenshoot.html +0 -7
- package/dist/screenshoot.js +0 -5677
package/dist/441.js
DELETED
|
@@ -1,2840 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
(self["webpackChunk_subiz_widget_v4"] = self["webpackChunk_subiz_widget_v4"] || []).push([[441],{
|
|
3
|
-
|
|
4
|
-
/***/ 7441:
|
|
5
|
-
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
6
|
-
|
|
7
|
-
__webpack_require__.r(__webpack_exports__);
|
|
8
|
-
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
9
|
-
/* harmony export */ "Lexer": () => (/* binding */ Lexer),
|
|
10
|
-
/* harmony export */ "Parser": () => (/* binding */ Parser),
|
|
11
|
-
/* harmony export */ "Renderer": () => (/* binding */ Renderer),
|
|
12
|
-
/* harmony export */ "Slugger": () => (/* binding */ Slugger),
|
|
13
|
-
/* harmony export */ "TextRenderer": () => (/* binding */ TextRenderer),
|
|
14
|
-
/* harmony export */ "Tokenizer": () => (/* binding */ Tokenizer),
|
|
15
|
-
/* harmony export */ "defaults": () => (/* binding */ defaults),
|
|
16
|
-
/* harmony export */ "getDefaults": () => (/* binding */ getDefaults),
|
|
17
|
-
/* harmony export */ "lexer": () => (/* binding */ lexer),
|
|
18
|
-
/* harmony export */ "marked": () => (/* binding */ marked),
|
|
19
|
-
/* harmony export */ "options": () => (/* binding */ options),
|
|
20
|
-
/* harmony export */ "parse": () => (/* binding */ parse),
|
|
21
|
-
/* harmony export */ "parseInline": () => (/* binding */ parseInline),
|
|
22
|
-
/* harmony export */ "parser": () => (/* binding */ parser),
|
|
23
|
-
/* harmony export */ "setOptions": () => (/* binding */ setOptions),
|
|
24
|
-
/* harmony export */ "use": () => (/* binding */ use),
|
|
25
|
-
/* harmony export */ "walkTokens": () => (/* binding */ walkTokens)
|
|
26
|
-
/* harmony export */ });
|
|
27
|
-
/**
|
|
28
|
-
* marked - a markdown parser
|
|
29
|
-
* Copyright (c) 2011-2022, Christopher Jeffrey. (MIT Licensed)
|
|
30
|
-
* https://github.com/markedjs/marked
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* DO NOT EDIT THIS FILE
|
|
35
|
-
* The code in this file is generated from files in ./src/
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
function getDefaults() {
|
|
39
|
-
return {
|
|
40
|
-
async: false,
|
|
41
|
-
baseUrl: null,
|
|
42
|
-
breaks: false,
|
|
43
|
-
extensions: null,
|
|
44
|
-
gfm: true,
|
|
45
|
-
headerIds: true,
|
|
46
|
-
headerPrefix: '',
|
|
47
|
-
highlight: null,
|
|
48
|
-
langPrefix: 'language-',
|
|
49
|
-
mangle: true,
|
|
50
|
-
pedantic: false,
|
|
51
|
-
renderer: null,
|
|
52
|
-
sanitize: false,
|
|
53
|
-
sanitizer: null,
|
|
54
|
-
silent: false,
|
|
55
|
-
smartypants: false,
|
|
56
|
-
tokenizer: null,
|
|
57
|
-
walkTokens: null,
|
|
58
|
-
xhtml: false
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
let defaults = getDefaults();
|
|
63
|
-
|
|
64
|
-
function changeDefaults(newDefaults) {
|
|
65
|
-
defaults = newDefaults;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Helpers
|
|
70
|
-
*/
|
|
71
|
-
const escapeTest = /[&<>"']/;
|
|
72
|
-
const escapeReplace = new RegExp(escapeTest.source, 'g');
|
|
73
|
-
const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/;
|
|
74
|
-
const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g');
|
|
75
|
-
const escapeReplacements = {
|
|
76
|
-
'&': '&',
|
|
77
|
-
'<': '<',
|
|
78
|
-
'>': '>',
|
|
79
|
-
'"': '"',
|
|
80
|
-
"'": '''
|
|
81
|
-
};
|
|
82
|
-
const getEscapeReplacement = (ch) => escapeReplacements[ch];
|
|
83
|
-
function escape(html, encode) {
|
|
84
|
-
if (encode) {
|
|
85
|
-
if (escapeTest.test(html)) {
|
|
86
|
-
return html.replace(escapeReplace, getEscapeReplacement);
|
|
87
|
-
}
|
|
88
|
-
} else {
|
|
89
|
-
if (escapeTestNoEncode.test(html)) {
|
|
90
|
-
return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return html;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* @param {string} html
|
|
101
|
-
*/
|
|
102
|
-
function unescape(html) {
|
|
103
|
-
// explicitly match decimal, hex, and named HTML entities
|
|
104
|
-
return html.replace(unescapeTest, (_, n) => {
|
|
105
|
-
n = n.toLowerCase();
|
|
106
|
-
if (n === 'colon') return ':';
|
|
107
|
-
if (n.charAt(0) === '#') {
|
|
108
|
-
return n.charAt(1) === 'x'
|
|
109
|
-
? String.fromCharCode(parseInt(n.substring(2), 16))
|
|
110
|
-
: String.fromCharCode(+n.substring(1));
|
|
111
|
-
}
|
|
112
|
-
return '';
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const caret = /(^|[^\[])\^/g;
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* @param {string | RegExp} regex
|
|
120
|
-
* @param {string} opt
|
|
121
|
-
*/
|
|
122
|
-
function edit(regex, opt) {
|
|
123
|
-
regex = typeof regex === 'string' ? regex : regex.source;
|
|
124
|
-
opt = opt || '';
|
|
125
|
-
const obj = {
|
|
126
|
-
replace: (name, val) => {
|
|
127
|
-
val = val.source || val;
|
|
128
|
-
val = val.replace(caret, '$1');
|
|
129
|
-
regex = regex.replace(name, val);
|
|
130
|
-
return obj;
|
|
131
|
-
},
|
|
132
|
-
getRegex: () => {
|
|
133
|
-
return new RegExp(regex, opt);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
return obj;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const nonWordAndColonTest = /[^\w:]/g;
|
|
140
|
-
const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* @param {boolean} sanitize
|
|
144
|
-
* @param {string} base
|
|
145
|
-
* @param {string} href
|
|
146
|
-
*/
|
|
147
|
-
function cleanUrl(sanitize, base, href) {
|
|
148
|
-
if (sanitize) {
|
|
149
|
-
let prot;
|
|
150
|
-
try {
|
|
151
|
-
prot = decodeURIComponent(unescape(href))
|
|
152
|
-
.replace(nonWordAndColonTest, '')
|
|
153
|
-
.toLowerCase();
|
|
154
|
-
} catch (e) {
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
if (base && !originIndependentUrl.test(href)) {
|
|
162
|
-
href = resolveUrl(base, href);
|
|
163
|
-
}
|
|
164
|
-
try {
|
|
165
|
-
href = encodeURI(href).replace(/%25/g, '%');
|
|
166
|
-
} catch (e) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
return href;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const baseUrls = {};
|
|
173
|
-
const justDomain = /^[^:]+:\/*[^/]*$/;
|
|
174
|
-
const protocol = /^([^:]+:)[\s\S]*$/;
|
|
175
|
-
const domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* @param {string} base
|
|
179
|
-
* @param {string} href
|
|
180
|
-
*/
|
|
181
|
-
function resolveUrl(base, href) {
|
|
182
|
-
if (!baseUrls[' ' + base]) {
|
|
183
|
-
// we can ignore everything in base after the last slash of its path component,
|
|
184
|
-
// but we might need to add _that_
|
|
185
|
-
// https://tools.ietf.org/html/rfc3986#section-3
|
|
186
|
-
if (justDomain.test(base)) {
|
|
187
|
-
baseUrls[' ' + base] = base + '/';
|
|
188
|
-
} else {
|
|
189
|
-
baseUrls[' ' + base] = rtrim(base, '/', true);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
base = baseUrls[' ' + base];
|
|
193
|
-
const relativeBase = base.indexOf(':') === -1;
|
|
194
|
-
|
|
195
|
-
if (href.substring(0, 2) === '//') {
|
|
196
|
-
if (relativeBase) {
|
|
197
|
-
return href;
|
|
198
|
-
}
|
|
199
|
-
return base.replace(protocol, '$1') + href;
|
|
200
|
-
} else if (href.charAt(0) === '/') {
|
|
201
|
-
if (relativeBase) {
|
|
202
|
-
return href;
|
|
203
|
-
}
|
|
204
|
-
return base.replace(domain, '$1') + href;
|
|
205
|
-
} else {
|
|
206
|
-
return base + href;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const noopTest = { exec: function noopTest() {} };
|
|
211
|
-
|
|
212
|
-
function merge(obj) {
|
|
213
|
-
let i = 1,
|
|
214
|
-
target,
|
|
215
|
-
key;
|
|
216
|
-
|
|
217
|
-
for (; i < arguments.length; i++) {
|
|
218
|
-
target = arguments[i];
|
|
219
|
-
for (key in target) {
|
|
220
|
-
if (Object.prototype.hasOwnProperty.call(target, key)) {
|
|
221
|
-
obj[key] = target[key];
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return obj;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function splitCells(tableRow, count) {
|
|
230
|
-
// ensure that every cell-delimiting pipe has a space
|
|
231
|
-
// before it to distinguish it from an escaped pipe
|
|
232
|
-
const row = tableRow.replace(/\|/g, (match, offset, str) => {
|
|
233
|
-
let escaped = false,
|
|
234
|
-
curr = offset;
|
|
235
|
-
while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
|
|
236
|
-
if (escaped) {
|
|
237
|
-
// odd number of slashes means | is escaped
|
|
238
|
-
// so we leave it alone
|
|
239
|
-
return '|';
|
|
240
|
-
} else {
|
|
241
|
-
// add space before unescaped |
|
|
242
|
-
return ' |';
|
|
243
|
-
}
|
|
244
|
-
}),
|
|
245
|
-
cells = row.split(/ \|/);
|
|
246
|
-
let i = 0;
|
|
247
|
-
|
|
248
|
-
// First/last cell in a row cannot be empty if it has no leading/trailing pipe
|
|
249
|
-
if (!cells[0].trim()) { cells.shift(); }
|
|
250
|
-
if (cells.length > 0 && !cells[cells.length - 1].trim()) { cells.pop(); }
|
|
251
|
-
|
|
252
|
-
if (cells.length > count) {
|
|
253
|
-
cells.splice(count);
|
|
254
|
-
} else {
|
|
255
|
-
while (cells.length < count) cells.push('');
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
for (; i < cells.length; i++) {
|
|
259
|
-
// leading or trailing whitespace is ignored per the gfm spec
|
|
260
|
-
cells[i] = cells[i].trim().replace(/\\\|/g, '|');
|
|
261
|
-
}
|
|
262
|
-
return cells;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
|
|
267
|
-
* /c*$/ is vulnerable to REDOS.
|
|
268
|
-
*
|
|
269
|
-
* @param {string} str
|
|
270
|
-
* @param {string} c
|
|
271
|
-
* @param {boolean} invert Remove suffix of non-c chars instead. Default falsey.
|
|
272
|
-
*/
|
|
273
|
-
function rtrim(str, c, invert) {
|
|
274
|
-
const l = str.length;
|
|
275
|
-
if (l === 0) {
|
|
276
|
-
return '';
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Length of suffix matching the invert condition.
|
|
280
|
-
let suffLen = 0;
|
|
281
|
-
|
|
282
|
-
// Step left until we fail to match the invert condition.
|
|
283
|
-
while (suffLen < l) {
|
|
284
|
-
const currChar = str.charAt(l - suffLen - 1);
|
|
285
|
-
if (currChar === c && !invert) {
|
|
286
|
-
suffLen++;
|
|
287
|
-
} else if (currChar !== c && invert) {
|
|
288
|
-
suffLen++;
|
|
289
|
-
} else {
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return str.slice(0, l - suffLen);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function findClosingBracket(str, b) {
|
|
298
|
-
if (str.indexOf(b[1]) === -1) {
|
|
299
|
-
return -1;
|
|
300
|
-
}
|
|
301
|
-
const l = str.length;
|
|
302
|
-
let level = 0,
|
|
303
|
-
i = 0;
|
|
304
|
-
for (; i < l; i++) {
|
|
305
|
-
if (str[i] === '\\') {
|
|
306
|
-
i++;
|
|
307
|
-
} else if (str[i] === b[0]) {
|
|
308
|
-
level++;
|
|
309
|
-
} else if (str[i] === b[1]) {
|
|
310
|
-
level--;
|
|
311
|
-
if (level < 0) {
|
|
312
|
-
return i;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return -1;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
function checkSanitizeDeprecation(opt) {
|
|
320
|
-
if (opt && opt.sanitize && !opt.silent) {
|
|
321
|
-
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');
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// copied from https://stackoverflow.com/a/5450113/806777
|
|
326
|
-
/**
|
|
327
|
-
* @param {string} pattern
|
|
328
|
-
* @param {number} count
|
|
329
|
-
*/
|
|
330
|
-
function repeatString(pattern, count) {
|
|
331
|
-
if (count < 1) {
|
|
332
|
-
return '';
|
|
333
|
-
}
|
|
334
|
-
let result = '';
|
|
335
|
-
while (count > 1) {
|
|
336
|
-
if (count & 1) {
|
|
337
|
-
result += pattern;
|
|
338
|
-
}
|
|
339
|
-
count >>= 1;
|
|
340
|
-
pattern += pattern;
|
|
341
|
-
}
|
|
342
|
-
return result + pattern;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function outputLink(cap, link, raw, lexer) {
|
|
346
|
-
const href = link.href;
|
|
347
|
-
const title = link.title ? escape(link.title) : null;
|
|
348
|
-
const text = cap[1].replace(/\\([\[\]])/g, '$1');
|
|
349
|
-
|
|
350
|
-
if (cap[0].charAt(0) !== '!') {
|
|
351
|
-
lexer.state.inLink = true;
|
|
352
|
-
const token = {
|
|
353
|
-
type: 'link',
|
|
354
|
-
raw,
|
|
355
|
-
href,
|
|
356
|
-
title,
|
|
357
|
-
text,
|
|
358
|
-
tokens: lexer.inlineTokens(text)
|
|
359
|
-
};
|
|
360
|
-
lexer.state.inLink = false;
|
|
361
|
-
return token;
|
|
362
|
-
}
|
|
363
|
-
return {
|
|
364
|
-
type: 'image',
|
|
365
|
-
raw,
|
|
366
|
-
href,
|
|
367
|
-
title,
|
|
368
|
-
text: escape(text)
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function indentCodeCompensation(raw, text) {
|
|
373
|
-
const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
|
|
374
|
-
|
|
375
|
-
if (matchIndentToCode === null) {
|
|
376
|
-
return text;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
const indentToCode = matchIndentToCode[1];
|
|
380
|
-
|
|
381
|
-
return text
|
|
382
|
-
.split('\n')
|
|
383
|
-
.map(node => {
|
|
384
|
-
const matchIndentInNode = node.match(/^\s+/);
|
|
385
|
-
if (matchIndentInNode === null) {
|
|
386
|
-
return node;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const [indentInNode] = matchIndentInNode;
|
|
390
|
-
|
|
391
|
-
if (indentInNode.length >= indentToCode.length) {
|
|
392
|
-
return node.slice(indentToCode.length);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return node;
|
|
396
|
-
})
|
|
397
|
-
.join('\n');
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Tokenizer
|
|
402
|
-
*/
|
|
403
|
-
class Tokenizer {
|
|
404
|
-
constructor(options) {
|
|
405
|
-
this.options = options || defaults;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
space(src) {
|
|
409
|
-
const cap = this.rules.block.newline.exec(src);
|
|
410
|
-
if (cap && cap[0].length > 0) {
|
|
411
|
-
return {
|
|
412
|
-
type: 'space',
|
|
413
|
-
raw: cap[0]
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
code(src) {
|
|
419
|
-
const cap = this.rules.block.code.exec(src);
|
|
420
|
-
if (cap) {
|
|
421
|
-
const text = cap[0].replace(/^ {1,4}/gm, '');
|
|
422
|
-
return {
|
|
423
|
-
type: 'code',
|
|
424
|
-
raw: cap[0],
|
|
425
|
-
codeBlockStyle: 'indented',
|
|
426
|
-
text: !this.options.pedantic
|
|
427
|
-
? rtrim(text, '\n')
|
|
428
|
-
: text
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
fences(src) {
|
|
434
|
-
const cap = this.rules.block.fences.exec(src);
|
|
435
|
-
if (cap) {
|
|
436
|
-
const raw = cap[0];
|
|
437
|
-
const text = indentCodeCompensation(raw, cap[3] || '');
|
|
438
|
-
|
|
439
|
-
return {
|
|
440
|
-
type: 'code',
|
|
441
|
-
raw,
|
|
442
|
-
lang: cap[2] ? cap[2].trim().replace(this.rules.inline._escapes, '$1') : cap[2],
|
|
443
|
-
text
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
heading(src) {
|
|
449
|
-
const cap = this.rules.block.heading.exec(src);
|
|
450
|
-
if (cap) {
|
|
451
|
-
let text = cap[2].trim();
|
|
452
|
-
|
|
453
|
-
// remove trailing #s
|
|
454
|
-
if (/#$/.test(text)) {
|
|
455
|
-
const trimmed = rtrim(text, '#');
|
|
456
|
-
if (this.options.pedantic) {
|
|
457
|
-
text = trimmed.trim();
|
|
458
|
-
} else if (!trimmed || / $/.test(trimmed)) {
|
|
459
|
-
// CommonMark requires space before trailing #s
|
|
460
|
-
text = trimmed.trim();
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return {
|
|
465
|
-
type: 'heading',
|
|
466
|
-
raw: cap[0],
|
|
467
|
-
depth: cap[1].length,
|
|
468
|
-
text,
|
|
469
|
-
tokens: this.lexer.inline(text)
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
hr(src) {
|
|
475
|
-
const cap = this.rules.block.hr.exec(src);
|
|
476
|
-
if (cap) {
|
|
477
|
-
return {
|
|
478
|
-
type: 'hr',
|
|
479
|
-
raw: cap[0]
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
blockquote(src) {
|
|
485
|
-
const cap = this.rules.block.blockquote.exec(src);
|
|
486
|
-
if (cap) {
|
|
487
|
-
const text = cap[0].replace(/^ *>[ \t]?/gm, '');
|
|
488
|
-
|
|
489
|
-
return {
|
|
490
|
-
type: 'blockquote',
|
|
491
|
-
raw: cap[0],
|
|
492
|
-
tokens: this.lexer.blockTokens(text, []),
|
|
493
|
-
text
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
list(src) {
|
|
499
|
-
let cap = this.rules.block.list.exec(src);
|
|
500
|
-
if (cap) {
|
|
501
|
-
let raw, istask, ischecked, indent, i, blankLine, endsWithBlankLine,
|
|
502
|
-
line, nextLine, rawLine, itemContents, endEarly;
|
|
503
|
-
|
|
504
|
-
let bull = cap[1].trim();
|
|
505
|
-
const isordered = bull.length > 1;
|
|
506
|
-
|
|
507
|
-
const list = {
|
|
508
|
-
type: 'list',
|
|
509
|
-
raw: '',
|
|
510
|
-
ordered: isordered,
|
|
511
|
-
start: isordered ? +bull.slice(0, -1) : '',
|
|
512
|
-
loose: false,
|
|
513
|
-
items: []
|
|
514
|
-
};
|
|
515
|
-
|
|
516
|
-
bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
|
|
517
|
-
|
|
518
|
-
if (this.options.pedantic) {
|
|
519
|
-
bull = isordered ? bull : '[*+-]';
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// Get next list item
|
|
523
|
-
const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`);
|
|
524
|
-
|
|
525
|
-
// Check if current bullet point can start a new List Item
|
|
526
|
-
while (src) {
|
|
527
|
-
endEarly = false;
|
|
528
|
-
if (!(cap = itemRegex.exec(src))) {
|
|
529
|
-
break;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?)
|
|
533
|
-
break;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
raw = cap[0];
|
|
537
|
-
src = src.substring(raw.length);
|
|
538
|
-
|
|
539
|
-
line = cap[2].split('\n', 1)[0];
|
|
540
|
-
nextLine = src.split('\n', 1)[0];
|
|
541
|
-
|
|
542
|
-
if (this.options.pedantic) {
|
|
543
|
-
indent = 2;
|
|
544
|
-
itemContents = line.trimLeft();
|
|
545
|
-
} else {
|
|
546
|
-
indent = cap[2].search(/[^ ]/); // Find first non-space char
|
|
547
|
-
indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent
|
|
548
|
-
itemContents = line.slice(indent);
|
|
549
|
-
indent += cap[1].length;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
blankLine = false;
|
|
553
|
-
|
|
554
|
-
if (!line && /^ *$/.test(nextLine)) { // Items begin with at most one blank line
|
|
555
|
-
raw += nextLine + '\n';
|
|
556
|
-
src = src.substring(nextLine.length + 1);
|
|
557
|
-
endEarly = true;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
if (!endEarly) {
|
|
561
|
-
const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?: [^\\n]*)?(?:\\n|$))`);
|
|
562
|
-
const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
|
|
563
|
-
const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`);
|
|
564
|
-
const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`);
|
|
565
|
-
|
|
566
|
-
// Check if following lines should be included in List Item
|
|
567
|
-
while (src) {
|
|
568
|
-
rawLine = src.split('\n', 1)[0];
|
|
569
|
-
line = rawLine;
|
|
570
|
-
|
|
571
|
-
// Re-align to follow commonmark nesting rules
|
|
572
|
-
if (this.options.pedantic) {
|
|
573
|
-
line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
// End list item if found code fences
|
|
577
|
-
if (fencesBeginRegex.test(line)) {
|
|
578
|
-
break;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// End list item if found start of new heading
|
|
582
|
-
if (headingBeginRegex.test(line)) {
|
|
583
|
-
break;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// End list item if found start of new bullet
|
|
587
|
-
if (nextBulletRegex.test(line)) {
|
|
588
|
-
break;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// Horizontal rule found
|
|
592
|
-
if (hrRegex.test(src)) {
|
|
593
|
-
break;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
if (line.search(/[^ ]/) >= indent || !line.trim()) { // Dedent if possible
|
|
597
|
-
itemContents += '\n' + line.slice(indent);
|
|
598
|
-
} else if (!blankLine) { // Until blank line, item doesn't need indentation
|
|
599
|
-
itemContents += '\n' + line;
|
|
600
|
-
} else { // Otherwise, improper indentation ends this item
|
|
601
|
-
break;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
if (!blankLine && !line.trim()) { // Check if current line is blank
|
|
605
|
-
blankLine = true;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
raw += rawLine + '\n';
|
|
609
|
-
src = src.substring(rawLine.length + 1);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
if (!list.loose) {
|
|
614
|
-
// If the previous item ended with a blank line, the list is loose
|
|
615
|
-
if (endsWithBlankLine) {
|
|
616
|
-
list.loose = true;
|
|
617
|
-
} else if (/\n *\n *$/.test(raw)) {
|
|
618
|
-
endsWithBlankLine = true;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// Check for task list items
|
|
623
|
-
if (this.options.gfm) {
|
|
624
|
-
istask = /^\[[ xX]\] /.exec(itemContents);
|
|
625
|
-
if (istask) {
|
|
626
|
-
ischecked = istask[0] !== '[ ] ';
|
|
627
|
-
itemContents = itemContents.replace(/^\[[ xX]\] +/, '');
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
list.items.push({
|
|
632
|
-
type: 'list_item',
|
|
633
|
-
raw,
|
|
634
|
-
task: !!istask,
|
|
635
|
-
checked: ischecked,
|
|
636
|
-
loose: false,
|
|
637
|
-
text: itemContents
|
|
638
|
-
});
|
|
639
|
-
|
|
640
|
-
list.raw += raw;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
|
|
644
|
-
list.items[list.items.length - 1].raw = raw.trimRight();
|
|
645
|
-
list.items[list.items.length - 1].text = itemContents.trimRight();
|
|
646
|
-
list.raw = list.raw.trimRight();
|
|
647
|
-
|
|
648
|
-
const l = list.items.length;
|
|
649
|
-
|
|
650
|
-
// Item child tokens handled here at end because we needed to have the final item to trim it first
|
|
651
|
-
for (i = 0; i < l; i++) {
|
|
652
|
-
this.lexer.state.top = false;
|
|
653
|
-
list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
|
|
654
|
-
const spacers = list.items[i].tokens.filter(t => t.type === 'space');
|
|
655
|
-
const hasMultipleLineBreaks = spacers.every(t => {
|
|
656
|
-
const chars = t.raw.split('');
|
|
657
|
-
let lineBreaks = 0;
|
|
658
|
-
for (const char of chars) {
|
|
659
|
-
if (char === '\n') {
|
|
660
|
-
lineBreaks += 1;
|
|
661
|
-
}
|
|
662
|
-
if (lineBreaks > 1) {
|
|
663
|
-
return true;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
return false;
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
if (!list.loose && spacers.length && hasMultipleLineBreaks) {
|
|
671
|
-
// Having a single line break doesn't mean a list is loose. A single line break is terminating the last list item
|
|
672
|
-
list.loose = true;
|
|
673
|
-
list.items[i].loose = true;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
return list;
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
html(src) {
|
|
682
|
-
const cap = this.rules.block.html.exec(src);
|
|
683
|
-
if (cap) {
|
|
684
|
-
const token = {
|
|
685
|
-
type: 'html',
|
|
686
|
-
raw: cap[0],
|
|
687
|
-
pre: !this.options.sanitizer
|
|
688
|
-
&& (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
|
|
689
|
-
text: cap[0]
|
|
690
|
-
};
|
|
691
|
-
if (this.options.sanitize) {
|
|
692
|
-
const text = this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0]);
|
|
693
|
-
token.type = 'paragraph';
|
|
694
|
-
token.text = text;
|
|
695
|
-
token.tokens = this.lexer.inline(text);
|
|
696
|
-
}
|
|
697
|
-
return token;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
def(src) {
|
|
702
|
-
const cap = this.rules.block.def.exec(src);
|
|
703
|
-
if (cap) {
|
|
704
|
-
const tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
|
|
705
|
-
const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline._escapes, '$1') : '';
|
|
706
|
-
const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline._escapes, '$1') : cap[3];
|
|
707
|
-
return {
|
|
708
|
-
type: 'def',
|
|
709
|
-
tag,
|
|
710
|
-
raw: cap[0],
|
|
711
|
-
href,
|
|
712
|
-
title
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
table(src) {
|
|
718
|
-
const cap = this.rules.block.table.exec(src);
|
|
719
|
-
if (cap) {
|
|
720
|
-
const item = {
|
|
721
|
-
type: 'table',
|
|
722
|
-
header: splitCells(cap[1]).map(c => { return { text: c }; }),
|
|
723
|
-
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
|
724
|
-
rows: cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : []
|
|
725
|
-
};
|
|
726
|
-
|
|
727
|
-
if (item.header.length === item.align.length) {
|
|
728
|
-
item.raw = cap[0];
|
|
729
|
-
|
|
730
|
-
let l = item.align.length;
|
|
731
|
-
let i, j, k, row;
|
|
732
|
-
for (i = 0; i < l; i++) {
|
|
733
|
-
if (/^ *-+: *$/.test(item.align[i])) {
|
|
734
|
-
item.align[i] = 'right';
|
|
735
|
-
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
|
736
|
-
item.align[i] = 'center';
|
|
737
|
-
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
|
738
|
-
item.align[i] = 'left';
|
|
739
|
-
} else {
|
|
740
|
-
item.align[i] = null;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
l = item.rows.length;
|
|
745
|
-
for (i = 0; i < l; i++) {
|
|
746
|
-
item.rows[i] = splitCells(item.rows[i], item.header.length).map(c => { return { text: c }; });
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
// parse child tokens inside headers and cells
|
|
750
|
-
|
|
751
|
-
// header child tokens
|
|
752
|
-
l = item.header.length;
|
|
753
|
-
for (j = 0; j < l; j++) {
|
|
754
|
-
item.header[j].tokens = this.lexer.inline(item.header[j].text);
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
// cell child tokens
|
|
758
|
-
l = item.rows.length;
|
|
759
|
-
for (j = 0; j < l; j++) {
|
|
760
|
-
row = item.rows[j];
|
|
761
|
-
for (k = 0; k < row.length; k++) {
|
|
762
|
-
row[k].tokens = this.lexer.inline(row[k].text);
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
return item;
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
lheading(src) {
|
|
772
|
-
const cap = this.rules.block.lheading.exec(src);
|
|
773
|
-
if (cap) {
|
|
774
|
-
return {
|
|
775
|
-
type: 'heading',
|
|
776
|
-
raw: cap[0],
|
|
777
|
-
depth: cap[2].charAt(0) === '=' ? 1 : 2,
|
|
778
|
-
text: cap[1],
|
|
779
|
-
tokens: this.lexer.inline(cap[1])
|
|
780
|
-
};
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
paragraph(src) {
|
|
785
|
-
const cap = this.rules.block.paragraph.exec(src);
|
|
786
|
-
if (cap) {
|
|
787
|
-
const text = cap[1].charAt(cap[1].length - 1) === '\n'
|
|
788
|
-
? cap[1].slice(0, -1)
|
|
789
|
-
: cap[1];
|
|
790
|
-
return {
|
|
791
|
-
type: 'paragraph',
|
|
792
|
-
raw: cap[0],
|
|
793
|
-
text,
|
|
794
|
-
tokens: this.lexer.inline(text)
|
|
795
|
-
};
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
text(src) {
|
|
800
|
-
const cap = this.rules.block.text.exec(src);
|
|
801
|
-
if (cap) {
|
|
802
|
-
return {
|
|
803
|
-
type: 'text',
|
|
804
|
-
raw: cap[0],
|
|
805
|
-
text: cap[0],
|
|
806
|
-
tokens: this.lexer.inline(cap[0])
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
escape(src) {
|
|
812
|
-
const cap = this.rules.inline.escape.exec(src);
|
|
813
|
-
if (cap) {
|
|
814
|
-
return {
|
|
815
|
-
type: 'escape',
|
|
816
|
-
raw: cap[0],
|
|
817
|
-
text: escape(cap[1])
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
tag(src) {
|
|
823
|
-
const cap = this.rules.inline.tag.exec(src);
|
|
824
|
-
if (cap) {
|
|
825
|
-
if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
|
|
826
|
-
this.lexer.state.inLink = true;
|
|
827
|
-
} else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
|
|
828
|
-
this.lexer.state.inLink = false;
|
|
829
|
-
}
|
|
830
|
-
if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
831
|
-
this.lexer.state.inRawBlock = true;
|
|
832
|
-
} else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
833
|
-
this.lexer.state.inRawBlock = false;
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
return {
|
|
837
|
-
type: this.options.sanitize
|
|
838
|
-
? 'text'
|
|
839
|
-
: 'html',
|
|
840
|
-
raw: cap[0],
|
|
841
|
-
inLink: this.lexer.state.inLink,
|
|
842
|
-
inRawBlock: this.lexer.state.inRawBlock,
|
|
843
|
-
text: this.options.sanitize
|
|
844
|
-
? (this.options.sanitizer
|
|
845
|
-
? this.options.sanitizer(cap[0])
|
|
846
|
-
: escape(cap[0]))
|
|
847
|
-
: cap[0]
|
|
848
|
-
};
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
link(src) {
|
|
853
|
-
const cap = this.rules.inline.link.exec(src);
|
|
854
|
-
if (cap) {
|
|
855
|
-
const trimmedUrl = cap[2].trim();
|
|
856
|
-
if (!this.options.pedantic && /^</.test(trimmedUrl)) {
|
|
857
|
-
// commonmark requires matching angle brackets
|
|
858
|
-
if (!(/>$/.test(trimmedUrl))) {
|
|
859
|
-
return;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
// ending angle bracket cannot be escaped
|
|
863
|
-
const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
|
|
864
|
-
if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
|
|
865
|
-
return;
|
|
866
|
-
}
|
|
867
|
-
} else {
|
|
868
|
-
// find closing parenthesis
|
|
869
|
-
const lastParenIndex = findClosingBracket(cap[2], '()');
|
|
870
|
-
if (lastParenIndex > -1) {
|
|
871
|
-
const start = cap[0].indexOf('!') === 0 ? 5 : 4;
|
|
872
|
-
const linkLen = start + cap[1].length + lastParenIndex;
|
|
873
|
-
cap[2] = cap[2].substring(0, lastParenIndex);
|
|
874
|
-
cap[0] = cap[0].substring(0, linkLen).trim();
|
|
875
|
-
cap[3] = '';
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
let href = cap[2];
|
|
879
|
-
let title = '';
|
|
880
|
-
if (this.options.pedantic) {
|
|
881
|
-
// split pedantic href and title
|
|
882
|
-
const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
|
|
883
|
-
|
|
884
|
-
if (link) {
|
|
885
|
-
href = link[1];
|
|
886
|
-
title = link[3];
|
|
887
|
-
}
|
|
888
|
-
} else {
|
|
889
|
-
title = cap[3] ? cap[3].slice(1, -1) : '';
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
href = href.trim();
|
|
893
|
-
if (/^</.test(href)) {
|
|
894
|
-
if (this.options.pedantic && !(/>$/.test(trimmedUrl))) {
|
|
895
|
-
// pedantic allows starting angle bracket without ending angle bracket
|
|
896
|
-
href = href.slice(1);
|
|
897
|
-
} else {
|
|
898
|
-
href = href.slice(1, -1);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
return outputLink(cap, {
|
|
902
|
-
href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
|
|
903
|
-
title: title ? title.replace(this.rules.inline._escapes, '$1') : title
|
|
904
|
-
}, cap[0], this.lexer);
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
reflink(src, links) {
|
|
909
|
-
let cap;
|
|
910
|
-
if ((cap = this.rules.inline.reflink.exec(src))
|
|
911
|
-
|| (cap = this.rules.inline.nolink.exec(src))) {
|
|
912
|
-
let link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
|
|
913
|
-
link = links[link.toLowerCase()];
|
|
914
|
-
if (!link) {
|
|
915
|
-
const text = cap[0].charAt(0);
|
|
916
|
-
return {
|
|
917
|
-
type: 'text',
|
|
918
|
-
raw: text,
|
|
919
|
-
text
|
|
920
|
-
};
|
|
921
|
-
}
|
|
922
|
-
return outputLink(cap, link, cap[0], this.lexer);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
emStrong(src, maskedSrc, prevChar = '') {
|
|
927
|
-
let match = this.rules.inline.emStrong.lDelim.exec(src);
|
|
928
|
-
if (!match) return;
|
|
929
|
-
|
|
930
|
-
// _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
|
|
931
|
-
if (match[3] && prevChar.match(/[\p{L}\p{N}]/u)) return;
|
|
932
|
-
|
|
933
|
-
const nextChar = match[1] || match[2] || '';
|
|
934
|
-
|
|
935
|
-
if (!nextChar || (nextChar && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
|
|
936
|
-
const lLength = match[0].length - 1;
|
|
937
|
-
let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
|
|
938
|
-
|
|
939
|
-
const endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
|
|
940
|
-
endReg.lastIndex = 0;
|
|
941
|
-
|
|
942
|
-
// Clip maskedSrc to same section of string as src (move to lexer?)
|
|
943
|
-
maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
|
|
944
|
-
|
|
945
|
-
while ((match = endReg.exec(maskedSrc)) != null) {
|
|
946
|
-
rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
|
|
947
|
-
|
|
948
|
-
if (!rDelim) continue; // skip single * in __abc*abc__
|
|
949
|
-
|
|
950
|
-
rLength = rDelim.length;
|
|
951
|
-
|
|
952
|
-
if (match[3] || match[4]) { // found another Left Delim
|
|
953
|
-
delimTotal += rLength;
|
|
954
|
-
continue;
|
|
955
|
-
} else if (match[5] || match[6]) { // either Left or Right Delim
|
|
956
|
-
if (lLength % 3 && !((lLength + rLength) % 3)) {
|
|
957
|
-
midDelimTotal += rLength;
|
|
958
|
-
continue; // CommonMark Emphasis Rules 9-10
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
delimTotal -= rLength;
|
|
963
|
-
|
|
964
|
-
if (delimTotal > 0) continue; // Haven't found enough closing delimiters
|
|
965
|
-
|
|
966
|
-
// Remove extra characters. *a*** -> *a*
|
|
967
|
-
rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
|
|
968
|
-
|
|
969
|
-
const raw = src.slice(0, lLength + match.index + (match[0].length - rDelim.length) + rLength);
|
|
970
|
-
|
|
971
|
-
// Create `em` if smallest delimiter has odd char count. *a***
|
|
972
|
-
if (Math.min(lLength, rLength) % 2) {
|
|
973
|
-
const text = raw.slice(1, -1);
|
|
974
|
-
return {
|
|
975
|
-
type: 'em',
|
|
976
|
-
raw,
|
|
977
|
-
text,
|
|
978
|
-
tokens: this.lexer.inlineTokens(text)
|
|
979
|
-
};
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
// Create 'strong' if smallest delimiter has even char count. **a***
|
|
983
|
-
const text = raw.slice(2, -2);
|
|
984
|
-
return {
|
|
985
|
-
type: 'strong',
|
|
986
|
-
raw,
|
|
987
|
-
text,
|
|
988
|
-
tokens: this.lexer.inlineTokens(text)
|
|
989
|
-
};
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
codespan(src) {
|
|
995
|
-
const cap = this.rules.inline.code.exec(src);
|
|
996
|
-
if (cap) {
|
|
997
|
-
let text = cap[2].replace(/\n/g, ' ');
|
|
998
|
-
const hasNonSpaceChars = /[^ ]/.test(text);
|
|
999
|
-
const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
|
|
1000
|
-
if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
|
|
1001
|
-
text = text.substring(1, text.length - 1);
|
|
1002
|
-
}
|
|
1003
|
-
text = escape(text, true);
|
|
1004
|
-
return {
|
|
1005
|
-
type: 'codespan',
|
|
1006
|
-
raw: cap[0],
|
|
1007
|
-
text
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
br(src) {
|
|
1013
|
-
const cap = this.rules.inline.br.exec(src);
|
|
1014
|
-
if (cap) {
|
|
1015
|
-
return {
|
|
1016
|
-
type: 'br',
|
|
1017
|
-
raw: cap[0]
|
|
1018
|
-
};
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
del(src) {
|
|
1023
|
-
const cap = this.rules.inline.del.exec(src);
|
|
1024
|
-
if (cap) {
|
|
1025
|
-
return {
|
|
1026
|
-
type: 'del',
|
|
1027
|
-
raw: cap[0],
|
|
1028
|
-
text: cap[2],
|
|
1029
|
-
tokens: this.lexer.inlineTokens(cap[2])
|
|
1030
|
-
};
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
autolink(src, mangle) {
|
|
1035
|
-
const cap = this.rules.inline.autolink.exec(src);
|
|
1036
|
-
if (cap) {
|
|
1037
|
-
let text, href;
|
|
1038
|
-
if (cap[2] === '@') {
|
|
1039
|
-
text = escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
|
|
1040
|
-
href = 'mailto:' + text;
|
|
1041
|
-
} else {
|
|
1042
|
-
text = escape(cap[1]);
|
|
1043
|
-
href = text;
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
return {
|
|
1047
|
-
type: 'link',
|
|
1048
|
-
raw: cap[0],
|
|
1049
|
-
text,
|
|
1050
|
-
href,
|
|
1051
|
-
tokens: [
|
|
1052
|
-
{
|
|
1053
|
-
type: 'text',
|
|
1054
|
-
raw: text,
|
|
1055
|
-
text
|
|
1056
|
-
}
|
|
1057
|
-
]
|
|
1058
|
-
};
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
url(src, mangle) {
|
|
1063
|
-
let cap;
|
|
1064
|
-
if (cap = this.rules.inline.url.exec(src)) {
|
|
1065
|
-
let text, href;
|
|
1066
|
-
if (cap[2] === '@') {
|
|
1067
|
-
text = escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
|
|
1068
|
-
href = 'mailto:' + text;
|
|
1069
|
-
} else {
|
|
1070
|
-
// do extended autolink path validation
|
|
1071
|
-
let prevCapZero;
|
|
1072
|
-
do {
|
|
1073
|
-
prevCapZero = cap[0];
|
|
1074
|
-
cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
|
|
1075
|
-
} while (prevCapZero !== cap[0]);
|
|
1076
|
-
text = escape(cap[0]);
|
|
1077
|
-
if (cap[1] === 'www.') {
|
|
1078
|
-
href = 'http://' + text;
|
|
1079
|
-
} else {
|
|
1080
|
-
href = text;
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
return {
|
|
1084
|
-
type: 'link',
|
|
1085
|
-
raw: cap[0],
|
|
1086
|
-
text,
|
|
1087
|
-
href,
|
|
1088
|
-
tokens: [
|
|
1089
|
-
{
|
|
1090
|
-
type: 'text',
|
|
1091
|
-
raw: text,
|
|
1092
|
-
text
|
|
1093
|
-
}
|
|
1094
|
-
]
|
|
1095
|
-
};
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
inlineText(src, smartypants) {
|
|
1100
|
-
const cap = this.rules.inline.text.exec(src);
|
|
1101
|
-
if (cap) {
|
|
1102
|
-
let text;
|
|
1103
|
-
if (this.lexer.state.inRawBlock) {
|
|
1104
|
-
text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0];
|
|
1105
|
-
} else {
|
|
1106
|
-
text = escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
|
|
1107
|
-
}
|
|
1108
|
-
return {
|
|
1109
|
-
type: 'text',
|
|
1110
|
-
raw: cap[0],
|
|
1111
|
-
text
|
|
1112
|
-
};
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
/**
|
|
1118
|
-
* Block-Level Grammar
|
|
1119
|
-
*/
|
|
1120
|
-
const block = {
|
|
1121
|
-
newline: /^(?: *(?:\n|$))+/,
|
|
1122
|
-
code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
|
|
1123
|
-
fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
|
|
1124
|
-
hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
|
|
1125
|
-
heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
|
|
1126
|
-
blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
|
|
1127
|
-
list: /^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/,
|
|
1128
|
-
html: '^ {0,3}(?:' // optional indentation
|
|
1129
|
-
+ '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
|
|
1130
|
-
+ '|comment[^\\n]*(\\n+|$)' // (2)
|
|
1131
|
-
+ '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
|
|
1132
|
-
+ '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
|
|
1133
|
-
+ '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
|
|
1134
|
-
+ '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
|
|
1135
|
-
+ '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
|
|
1136
|
-
+ '|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
|
|
1137
|
-
+ ')',
|
|
1138
|
-
def: /^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,
|
|
1139
|
-
table: noopTest,
|
|
1140
|
-
lheading: /^((?:.|\n(?!\n))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
|
|
1141
|
-
// regex template, placeholders will be replaced according to different paragraph
|
|
1142
|
-
// interruption rules of commonmark and the original markdown spec:
|
|
1143
|
-
_paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
|
|
1144
|
-
text: /^[^\n]+/
|
|
1145
|
-
};
|
|
1146
|
-
|
|
1147
|
-
block._label = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
|
|
1148
|
-
block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
|
|
1149
|
-
block.def = edit(block.def)
|
|
1150
|
-
.replace('label', block._label)
|
|
1151
|
-
.replace('title', block._title)
|
|
1152
|
-
.getRegex();
|
|
1153
|
-
|
|
1154
|
-
block.bullet = /(?:[*+-]|\d{1,9}[.)])/;
|
|
1155
|
-
block.listItemStart = edit(/^( *)(bull) */)
|
|
1156
|
-
.replace('bull', block.bullet)
|
|
1157
|
-
.getRegex();
|
|
1158
|
-
|
|
1159
|
-
block.list = edit(block.list)
|
|
1160
|
-
.replace(/bull/g, block.bullet)
|
|
1161
|
-
.replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
|
|
1162
|
-
.replace('def', '\\n+(?=' + block.def.source + ')')
|
|
1163
|
-
.getRegex();
|
|
1164
|
-
|
|
1165
|
-
block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
|
|
1166
|
-
+ '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
|
|
1167
|
-
+ '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
|
|
1168
|
-
+ '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
|
|
1169
|
-
+ '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
|
|
1170
|
-
+ '|track|ul';
|
|
1171
|
-
block._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
|
|
1172
|
-
block.html = edit(block.html, 'i')
|
|
1173
|
-
.replace('comment', block._comment)
|
|
1174
|
-
.replace('tag', block._tag)
|
|
1175
|
-
.replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
|
|
1176
|
-
.getRegex();
|
|
1177
|
-
|
|
1178
|
-
block.paragraph = edit(block._paragraph)
|
|
1179
|
-
.replace('hr', block.hr)
|
|
1180
|
-
.replace('heading', ' {0,3}#{1,6} ')
|
|
1181
|
-
.replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
|
|
1182
|
-
.replace('|table', '')
|
|
1183
|
-
.replace('blockquote', ' {0,3}>')
|
|
1184
|
-
.replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
|
|
1185
|
-
.replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
|
|
1186
|
-
.replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
|
|
1187
|
-
.replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
|
|
1188
|
-
.getRegex();
|
|
1189
|
-
|
|
1190
|
-
block.blockquote = edit(block.blockquote)
|
|
1191
|
-
.replace('paragraph', block.paragraph)
|
|
1192
|
-
.getRegex();
|
|
1193
|
-
|
|
1194
|
-
/**
|
|
1195
|
-
* Normal Block Grammar
|
|
1196
|
-
*/
|
|
1197
|
-
|
|
1198
|
-
block.normal = merge({}, block);
|
|
1199
|
-
|
|
1200
|
-
/**
|
|
1201
|
-
* GFM Block Grammar
|
|
1202
|
-
*/
|
|
1203
|
-
|
|
1204
|
-
block.gfm = merge({}, block.normal, {
|
|
1205
|
-
table: '^ *([^\\n ].*\\|.*)\\n' // Header
|
|
1206
|
-
+ ' {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?' // Align
|
|
1207
|
-
+ '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
|
|
1208
|
-
});
|
|
1209
|
-
|
|
1210
|
-
block.gfm.table = edit(block.gfm.table)
|
|
1211
|
-
.replace('hr', block.hr)
|
|
1212
|
-
.replace('heading', ' {0,3}#{1,6} ')
|
|
1213
|
-
.replace('blockquote', ' {0,3}>')
|
|
1214
|
-
.replace('code', ' {4}[^\\n]')
|
|
1215
|
-
.replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
|
|
1216
|
-
.replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
|
|
1217
|
-
.replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
|
|
1218
|
-
.replace('tag', block._tag) // tables can be interrupted by type (6) html blocks
|
|
1219
|
-
.getRegex();
|
|
1220
|
-
|
|
1221
|
-
block.gfm.paragraph = edit(block._paragraph)
|
|
1222
|
-
.replace('hr', block.hr)
|
|
1223
|
-
.replace('heading', ' {0,3}#{1,6} ')
|
|
1224
|
-
.replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
|
|
1225
|
-
.replace('table', block.gfm.table) // interrupt paragraphs with table
|
|
1226
|
-
.replace('blockquote', ' {0,3}>')
|
|
1227
|
-
.replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n')
|
|
1228
|
-
.replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
|
|
1229
|
-
.replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)')
|
|
1230
|
-
.replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
|
|
1231
|
-
.getRegex();
|
|
1232
|
-
/**
|
|
1233
|
-
* Pedantic grammar (original John Gruber's loose markdown specification)
|
|
1234
|
-
*/
|
|
1235
|
-
|
|
1236
|
-
block.pedantic = merge({}, block.normal, {
|
|
1237
|
-
html: edit(
|
|
1238
|
-
'^ *(?:comment *(?:\\n|\\s*$)'
|
|
1239
|
-
+ '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
|
|
1240
|
-
+ '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
|
|
1241
|
-
.replace('comment', block._comment)
|
|
1242
|
-
.replace(/tag/g, '(?!(?:'
|
|
1243
|
-
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
|
|
1244
|
-
+ '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
|
|
1245
|
-
+ '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
|
|
1246
|
-
.getRegex(),
|
|
1247
|
-
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
|
|
1248
|
-
heading: /^(#{1,6})(.*)(?:\n+|$)/,
|
|
1249
|
-
fences: noopTest, // fences not supported
|
|
1250
|
-
lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,
|
|
1251
|
-
paragraph: edit(block.normal._paragraph)
|
|
1252
|
-
.replace('hr', block.hr)
|
|
1253
|
-
.replace('heading', ' *#{1,6} *[^\n]')
|
|
1254
|
-
.replace('lheading', block.lheading)
|
|
1255
|
-
.replace('blockquote', ' {0,3}>')
|
|
1256
|
-
.replace('|fences', '')
|
|
1257
|
-
.replace('|list', '')
|
|
1258
|
-
.replace('|html', '')
|
|
1259
|
-
.getRegex()
|
|
1260
|
-
});
|
|
1261
|
-
|
|
1262
|
-
/**
|
|
1263
|
-
* Inline-Level Grammar
|
|
1264
|
-
*/
|
|
1265
|
-
const inline = {
|
|
1266
|
-
escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
|
|
1267
|
-
autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
|
|
1268
|
-
url: noopTest,
|
|
1269
|
-
tag: '^comment'
|
|
1270
|
-
+ '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
|
|
1271
|
-
+ '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
|
|
1272
|
-
+ '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
|
|
1273
|
-
+ '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
|
|
1274
|
-
+ '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>', // CDATA section
|
|
1275
|
-
link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
|
|
1276
|
-
reflink: /^!?\[(label)\]\[(ref)\]/,
|
|
1277
|
-
nolink: /^!?\[(ref)\](?:\[\])?/,
|
|
1278
|
-
reflinkSearch: 'reflink|nolink(?!\\()',
|
|
1279
|
-
emStrong: {
|
|
1280
|
-
lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
|
|
1281
|
-
// (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.
|
|
1282
|
-
// () Skip orphan inside strong () Consume to delim (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a
|
|
1283
|
-
rDelimAst: /^(?:[^_*\\]|\\.)*?\_\_(?:[^_*\\]|\\.)*?\*(?:[^_*\\]|\\.)*?(?=\_\_)|(?:[^*\\]|\\.)+(?=[^*])|[punct_](\*+)(?=[\s]|$)|(?:[^punct*_\s\\]|\\.)(\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|(?:[^punct*_\s\\]|\\.)(\*+)(?=[^punct*_\s])/,
|
|
1284
|
-
rDelimUnd: /^(?:[^_*\\]|\\.)*?\*\*(?:[^_*\\]|\\.)*?\_(?:[^_*\\]|\\.)*?(?=\*\*)|(?:[^_\\]|\\.)+(?=[^_])|[punct*](\_+)(?=[\s]|$)|(?:[^punct*_\s\\]|\\.)(\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
|
|
1285
|
-
},
|
|
1286
|
-
code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
|
|
1287
|
-
br: /^( {2,}|\\)\n(?!\s*$)/,
|
|
1288
|
-
del: noopTest,
|
|
1289
|
-
text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
|
|
1290
|
-
punctuation: /^([\spunctuation])/
|
|
1291
|
-
};
|
|
1292
|
-
|
|
1293
|
-
// list of punctuation marks from CommonMark spec
|
|
1294
|
-
// without * and _ to handle the different emphasis markers * and _
|
|
1295
|
-
inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
|
|
1296
|
-
inline.punctuation = edit(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex();
|
|
1297
|
-
|
|
1298
|
-
// sequences em should skip over [title](link), `code`, <html>
|
|
1299
|
-
inline.blockSkip = /\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g;
|
|
1300
|
-
// lookbehind is not available on Safari as of version 16
|
|
1301
|
-
// inline.escapedEmSt = /(?<=(?:^|[^\\)(?:\\[^])*)\\[*_]/g;
|
|
1302
|
-
inline.escapedEmSt = /(?:^|[^\\])(?:\\\\)*\\[*_]/g;
|
|
1303
|
-
|
|
1304
|
-
inline._comment = edit(block._comment).replace('(?:-->|$)', '-->').getRegex();
|
|
1305
|
-
|
|
1306
|
-
inline.emStrong.lDelim = edit(inline.emStrong.lDelim)
|
|
1307
|
-
.replace(/punct/g, inline._punctuation)
|
|
1308
|
-
.getRegex();
|
|
1309
|
-
|
|
1310
|
-
inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'g')
|
|
1311
|
-
.replace(/punct/g, inline._punctuation)
|
|
1312
|
-
.getRegex();
|
|
1313
|
-
|
|
1314
|
-
inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'g')
|
|
1315
|
-
.replace(/punct/g, inline._punctuation)
|
|
1316
|
-
.getRegex();
|
|
1317
|
-
|
|
1318
|
-
inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
|
|
1319
|
-
|
|
1320
|
-
inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
|
|
1321
|
-
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])?)+(?![-_])/;
|
|
1322
|
-
inline.autolink = edit(inline.autolink)
|
|
1323
|
-
.replace('scheme', inline._scheme)
|
|
1324
|
-
.replace('email', inline._email)
|
|
1325
|
-
.getRegex();
|
|
1326
|
-
|
|
1327
|
-
inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
|
|
1328
|
-
|
|
1329
|
-
inline.tag = edit(inline.tag)
|
|
1330
|
-
.replace('comment', inline._comment)
|
|
1331
|
-
.replace('attribute', inline._attribute)
|
|
1332
|
-
.getRegex();
|
|
1333
|
-
|
|
1334
|
-
inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
|
|
1335
|
-
inline._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
|
|
1336
|
-
inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
|
|
1337
|
-
|
|
1338
|
-
inline.link = edit(inline.link)
|
|
1339
|
-
.replace('label', inline._label)
|
|
1340
|
-
.replace('href', inline._href)
|
|
1341
|
-
.replace('title', inline._title)
|
|
1342
|
-
.getRegex();
|
|
1343
|
-
|
|
1344
|
-
inline.reflink = edit(inline.reflink)
|
|
1345
|
-
.replace('label', inline._label)
|
|
1346
|
-
.replace('ref', block._label)
|
|
1347
|
-
.getRegex();
|
|
1348
|
-
|
|
1349
|
-
inline.nolink = edit(inline.nolink)
|
|
1350
|
-
.replace('ref', block._label)
|
|
1351
|
-
.getRegex();
|
|
1352
|
-
|
|
1353
|
-
inline.reflinkSearch = edit(inline.reflinkSearch, 'g')
|
|
1354
|
-
.replace('reflink', inline.reflink)
|
|
1355
|
-
.replace('nolink', inline.nolink)
|
|
1356
|
-
.getRegex();
|
|
1357
|
-
|
|
1358
|
-
/**
|
|
1359
|
-
* Normal Inline Grammar
|
|
1360
|
-
*/
|
|
1361
|
-
|
|
1362
|
-
inline.normal = merge({}, inline);
|
|
1363
|
-
|
|
1364
|
-
/**
|
|
1365
|
-
* Pedantic Inline Grammar
|
|
1366
|
-
*/
|
|
1367
|
-
|
|
1368
|
-
inline.pedantic = merge({}, inline.normal, {
|
|
1369
|
-
strong: {
|
|
1370
|
-
start: /^__|\*\*/,
|
|
1371
|
-
middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
|
|
1372
|
-
endAst: /\*\*(?!\*)/g,
|
|
1373
|
-
endUnd: /__(?!_)/g
|
|
1374
|
-
},
|
|
1375
|
-
em: {
|
|
1376
|
-
start: /^_|\*/,
|
|
1377
|
-
middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
|
|
1378
|
-
endAst: /\*(?!\*)/g,
|
|
1379
|
-
endUnd: /_(?!_)/g
|
|
1380
|
-
},
|
|
1381
|
-
link: edit(/^!?\[(label)\]\((.*?)\)/)
|
|
1382
|
-
.replace('label', inline._label)
|
|
1383
|
-
.getRegex(),
|
|
1384
|
-
reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
|
|
1385
|
-
.replace('label', inline._label)
|
|
1386
|
-
.getRegex()
|
|
1387
|
-
});
|
|
1388
|
-
|
|
1389
|
-
/**
|
|
1390
|
-
* GFM Inline Grammar
|
|
1391
|
-
*/
|
|
1392
|
-
|
|
1393
|
-
inline.gfm = merge({}, inline.normal, {
|
|
1394
|
-
escape: edit(inline.escape).replace('])', '~|])').getRegex(),
|
|
1395
|
-
_extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
|
|
1396
|
-
url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
|
|
1397
|
-
_backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
|
|
1398
|
-
del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
|
|
1399
|
-
text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
|
|
1400
|
-
});
|
|
1401
|
-
|
|
1402
|
-
inline.gfm.url = edit(inline.gfm.url, 'i')
|
|
1403
|
-
.replace('email', inline.gfm._extended_email)
|
|
1404
|
-
.getRegex();
|
|
1405
|
-
/**
|
|
1406
|
-
* GFM + Line Breaks Inline Grammar
|
|
1407
|
-
*/
|
|
1408
|
-
|
|
1409
|
-
inline.breaks = merge({}, inline.gfm, {
|
|
1410
|
-
br: edit(inline.br).replace('{2,}', '*').getRegex(),
|
|
1411
|
-
text: edit(inline.gfm.text)
|
|
1412
|
-
.replace('\\b_', '\\b_| {2,}\\n')
|
|
1413
|
-
.replace(/\{2,\}/g, '*')
|
|
1414
|
-
.getRegex()
|
|
1415
|
-
});
|
|
1416
|
-
|
|
1417
|
-
/**
|
|
1418
|
-
* smartypants text replacement
|
|
1419
|
-
* @param {string} text
|
|
1420
|
-
*/
|
|
1421
|
-
function smartypants(text) {
|
|
1422
|
-
return text
|
|
1423
|
-
// em-dashes
|
|
1424
|
-
.replace(/---/g, '\u2014')
|
|
1425
|
-
// en-dashes
|
|
1426
|
-
.replace(/--/g, '\u2013')
|
|
1427
|
-
// opening singles
|
|
1428
|
-
.replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
|
|
1429
|
-
// closing singles & apostrophes
|
|
1430
|
-
.replace(/'/g, '\u2019')
|
|
1431
|
-
// opening doubles
|
|
1432
|
-
.replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
|
|
1433
|
-
// closing doubles
|
|
1434
|
-
.replace(/"/g, '\u201d')
|
|
1435
|
-
// ellipses
|
|
1436
|
-
.replace(/\.{3}/g, '\u2026');
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
/**
|
|
1440
|
-
* mangle email addresses
|
|
1441
|
-
* @param {string} text
|
|
1442
|
-
*/
|
|
1443
|
-
function mangle(text) {
|
|
1444
|
-
let out = '',
|
|
1445
|
-
i,
|
|
1446
|
-
ch;
|
|
1447
|
-
|
|
1448
|
-
const l = text.length;
|
|
1449
|
-
for (i = 0; i < l; i++) {
|
|
1450
|
-
ch = text.charCodeAt(i);
|
|
1451
|
-
if (Math.random() > 0.5) {
|
|
1452
|
-
ch = 'x' + ch.toString(16);
|
|
1453
|
-
}
|
|
1454
|
-
out += '&#' + ch + ';';
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
return out;
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
/**
|
|
1461
|
-
* Block Lexer
|
|
1462
|
-
*/
|
|
1463
|
-
class Lexer {
|
|
1464
|
-
constructor(options) {
|
|
1465
|
-
this.tokens = [];
|
|
1466
|
-
this.tokens.links = Object.create(null);
|
|
1467
|
-
this.options = options || defaults;
|
|
1468
|
-
this.options.tokenizer = this.options.tokenizer || new Tokenizer();
|
|
1469
|
-
this.tokenizer = this.options.tokenizer;
|
|
1470
|
-
this.tokenizer.options = this.options;
|
|
1471
|
-
this.tokenizer.lexer = this;
|
|
1472
|
-
this.inlineQueue = [];
|
|
1473
|
-
this.state = {
|
|
1474
|
-
inLink: false,
|
|
1475
|
-
inRawBlock: false,
|
|
1476
|
-
top: true
|
|
1477
|
-
};
|
|
1478
|
-
|
|
1479
|
-
const rules = {
|
|
1480
|
-
block: block.normal,
|
|
1481
|
-
inline: inline.normal
|
|
1482
|
-
};
|
|
1483
|
-
|
|
1484
|
-
if (this.options.pedantic) {
|
|
1485
|
-
rules.block = block.pedantic;
|
|
1486
|
-
rules.inline = inline.pedantic;
|
|
1487
|
-
} else if (this.options.gfm) {
|
|
1488
|
-
rules.block = block.gfm;
|
|
1489
|
-
if (this.options.breaks) {
|
|
1490
|
-
rules.inline = inline.breaks;
|
|
1491
|
-
} else {
|
|
1492
|
-
rules.inline = inline.gfm;
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
this.tokenizer.rules = rules;
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
/**
|
|
1499
|
-
* Expose Rules
|
|
1500
|
-
*/
|
|
1501
|
-
static get rules() {
|
|
1502
|
-
return {
|
|
1503
|
-
block,
|
|
1504
|
-
inline
|
|
1505
|
-
};
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
/**
|
|
1509
|
-
* Static Lex Method
|
|
1510
|
-
*/
|
|
1511
|
-
static lex(src, options) {
|
|
1512
|
-
const lexer = new Lexer(options);
|
|
1513
|
-
return lexer.lex(src);
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
/**
|
|
1517
|
-
* Static Lex Inline Method
|
|
1518
|
-
*/
|
|
1519
|
-
static lexInline(src, options) {
|
|
1520
|
-
const lexer = new Lexer(options);
|
|
1521
|
-
return lexer.inlineTokens(src);
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
/**
|
|
1525
|
-
* Preprocessing
|
|
1526
|
-
*/
|
|
1527
|
-
lex(src) {
|
|
1528
|
-
src = src
|
|
1529
|
-
.replace(/\r\n|\r/g, '\n');
|
|
1530
|
-
|
|
1531
|
-
this.blockTokens(src, this.tokens);
|
|
1532
|
-
|
|
1533
|
-
let next;
|
|
1534
|
-
while (next = this.inlineQueue.shift()) {
|
|
1535
|
-
this.inlineTokens(next.src, next.tokens);
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
return this.tokens;
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
/**
|
|
1542
|
-
* Lexing
|
|
1543
|
-
*/
|
|
1544
|
-
blockTokens(src, tokens = []) {
|
|
1545
|
-
if (this.options.pedantic) {
|
|
1546
|
-
src = src.replace(/\t/g, ' ').replace(/^ +$/gm, '');
|
|
1547
|
-
} else {
|
|
1548
|
-
src = src.replace(/^( *)(\t+)/gm, (_, leading, tabs) => {
|
|
1549
|
-
return leading + ' '.repeat(tabs.length);
|
|
1550
|
-
});
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
let token, lastToken, cutSrc, lastParagraphClipped;
|
|
1554
|
-
|
|
1555
|
-
while (src) {
|
|
1556
|
-
if (this.options.extensions
|
|
1557
|
-
&& this.options.extensions.block
|
|
1558
|
-
&& this.options.extensions.block.some((extTokenizer) => {
|
|
1559
|
-
if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
|
|
1560
|
-
src = src.substring(token.raw.length);
|
|
1561
|
-
tokens.push(token);
|
|
1562
|
-
return true;
|
|
1563
|
-
}
|
|
1564
|
-
return false;
|
|
1565
|
-
})) {
|
|
1566
|
-
continue;
|
|
1567
|
-
}
|
|
1568
|
-
|
|
1569
|
-
// newline
|
|
1570
|
-
if (token = this.tokenizer.space(src)) {
|
|
1571
|
-
src = src.substring(token.raw.length);
|
|
1572
|
-
if (token.raw.length === 1 && tokens.length > 0) {
|
|
1573
|
-
// if there's a single \n as a spacer, it's terminating the last line,
|
|
1574
|
-
// so move it there so that we don't get unecessary paragraph tags
|
|
1575
|
-
tokens[tokens.length - 1].raw += '\n';
|
|
1576
|
-
} else {
|
|
1577
|
-
tokens.push(token);
|
|
1578
|
-
}
|
|
1579
|
-
continue;
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
// code
|
|
1583
|
-
if (token = this.tokenizer.code(src)) {
|
|
1584
|
-
src = src.substring(token.raw.length);
|
|
1585
|
-
lastToken = tokens[tokens.length - 1];
|
|
1586
|
-
// An indented code block cannot interrupt a paragraph.
|
|
1587
|
-
if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
|
|
1588
|
-
lastToken.raw += '\n' + token.raw;
|
|
1589
|
-
lastToken.text += '\n' + token.text;
|
|
1590
|
-
this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
|
|
1591
|
-
} else {
|
|
1592
|
-
tokens.push(token);
|
|
1593
|
-
}
|
|
1594
|
-
continue;
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
// fences
|
|
1598
|
-
if (token = this.tokenizer.fences(src)) {
|
|
1599
|
-
src = src.substring(token.raw.length);
|
|
1600
|
-
tokens.push(token);
|
|
1601
|
-
continue;
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
// heading
|
|
1605
|
-
if (token = this.tokenizer.heading(src)) {
|
|
1606
|
-
src = src.substring(token.raw.length);
|
|
1607
|
-
tokens.push(token);
|
|
1608
|
-
continue;
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
// hr
|
|
1612
|
-
if (token = this.tokenizer.hr(src)) {
|
|
1613
|
-
src = src.substring(token.raw.length);
|
|
1614
|
-
tokens.push(token);
|
|
1615
|
-
continue;
|
|
1616
|
-
}
|
|
1617
|
-
|
|
1618
|
-
// blockquote
|
|
1619
|
-
if (token = this.tokenizer.blockquote(src)) {
|
|
1620
|
-
src = src.substring(token.raw.length);
|
|
1621
|
-
tokens.push(token);
|
|
1622
|
-
continue;
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
// list
|
|
1626
|
-
if (token = this.tokenizer.list(src)) {
|
|
1627
|
-
src = src.substring(token.raw.length);
|
|
1628
|
-
tokens.push(token);
|
|
1629
|
-
continue;
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
// html
|
|
1633
|
-
if (token = this.tokenizer.html(src)) {
|
|
1634
|
-
src = src.substring(token.raw.length);
|
|
1635
|
-
tokens.push(token);
|
|
1636
|
-
continue;
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
// def
|
|
1640
|
-
if (token = this.tokenizer.def(src)) {
|
|
1641
|
-
src = src.substring(token.raw.length);
|
|
1642
|
-
lastToken = tokens[tokens.length - 1];
|
|
1643
|
-
if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
|
|
1644
|
-
lastToken.raw += '\n' + token.raw;
|
|
1645
|
-
lastToken.text += '\n' + token.raw;
|
|
1646
|
-
this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
|
|
1647
|
-
} else if (!this.tokens.links[token.tag]) {
|
|
1648
|
-
this.tokens.links[token.tag] = {
|
|
1649
|
-
href: token.href,
|
|
1650
|
-
title: token.title
|
|
1651
|
-
};
|
|
1652
|
-
}
|
|
1653
|
-
continue;
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
|
-
// table (gfm)
|
|
1657
|
-
if (token = this.tokenizer.table(src)) {
|
|
1658
|
-
src = src.substring(token.raw.length);
|
|
1659
|
-
tokens.push(token);
|
|
1660
|
-
continue;
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
|
-
// lheading
|
|
1664
|
-
if (token = this.tokenizer.lheading(src)) {
|
|
1665
|
-
src = src.substring(token.raw.length);
|
|
1666
|
-
tokens.push(token);
|
|
1667
|
-
continue;
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
// top-level paragraph
|
|
1671
|
-
// prevent paragraph consuming extensions by clipping 'src' to extension start
|
|
1672
|
-
cutSrc = src;
|
|
1673
|
-
if (this.options.extensions && this.options.extensions.startBlock) {
|
|
1674
|
-
let startIndex = Infinity;
|
|
1675
|
-
const tempSrc = src.slice(1);
|
|
1676
|
-
let tempStart;
|
|
1677
|
-
this.options.extensions.startBlock.forEach(function(getStartIndex) {
|
|
1678
|
-
tempStart = getStartIndex.call({ lexer: this }, tempSrc);
|
|
1679
|
-
if (typeof tempStart === 'number' && tempStart >= 0) { startIndex = Math.min(startIndex, tempStart); }
|
|
1680
|
-
});
|
|
1681
|
-
if (startIndex < Infinity && startIndex >= 0) {
|
|
1682
|
-
cutSrc = src.substring(0, startIndex + 1);
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
|
|
1686
|
-
lastToken = tokens[tokens.length - 1];
|
|
1687
|
-
if (lastParagraphClipped && lastToken.type === 'paragraph') {
|
|
1688
|
-
lastToken.raw += '\n' + token.raw;
|
|
1689
|
-
lastToken.text += '\n' + token.text;
|
|
1690
|
-
this.inlineQueue.pop();
|
|
1691
|
-
this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
|
|
1692
|
-
} else {
|
|
1693
|
-
tokens.push(token);
|
|
1694
|
-
}
|
|
1695
|
-
lastParagraphClipped = (cutSrc.length !== src.length);
|
|
1696
|
-
src = src.substring(token.raw.length);
|
|
1697
|
-
continue;
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
// text
|
|
1701
|
-
if (token = this.tokenizer.text(src)) {
|
|
1702
|
-
src = src.substring(token.raw.length);
|
|
1703
|
-
lastToken = tokens[tokens.length - 1];
|
|
1704
|
-
if (lastToken && lastToken.type === 'text') {
|
|
1705
|
-
lastToken.raw += '\n' + token.raw;
|
|
1706
|
-
lastToken.text += '\n' + token.text;
|
|
1707
|
-
this.inlineQueue.pop();
|
|
1708
|
-
this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;
|
|
1709
|
-
} else {
|
|
1710
|
-
tokens.push(token);
|
|
1711
|
-
}
|
|
1712
|
-
continue;
|
|
1713
|
-
}
|
|
1714
|
-
|
|
1715
|
-
if (src) {
|
|
1716
|
-
const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
|
|
1717
|
-
if (this.options.silent) {
|
|
1718
|
-
console.error(errMsg);
|
|
1719
|
-
break;
|
|
1720
|
-
} else {
|
|
1721
|
-
throw new Error(errMsg);
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
|
-
this.state.top = true;
|
|
1727
|
-
return tokens;
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
inline(src, tokens = []) {
|
|
1731
|
-
this.inlineQueue.push({ src, tokens });
|
|
1732
|
-
return tokens;
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
/**
|
|
1736
|
-
* Lexing/Compiling
|
|
1737
|
-
*/
|
|
1738
|
-
inlineTokens(src, tokens = []) {
|
|
1739
|
-
let token, lastToken, cutSrc;
|
|
1740
|
-
|
|
1741
|
-
// String with links masked to avoid interference with em and strong
|
|
1742
|
-
let maskedSrc = src;
|
|
1743
|
-
let match;
|
|
1744
|
-
let keepPrevChar, prevChar;
|
|
1745
|
-
|
|
1746
|
-
// Mask out reflinks
|
|
1747
|
-
if (this.tokens.links) {
|
|
1748
|
-
const links = Object.keys(this.tokens.links);
|
|
1749
|
-
if (links.length > 0) {
|
|
1750
|
-
while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
|
|
1751
|
-
if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
|
|
1752
|
-
maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
// Mask out other blocks
|
|
1758
|
-
while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
|
|
1759
|
-
maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
|
|
1760
|
-
}
|
|
1761
|
-
|
|
1762
|
-
// Mask out escaped em & strong delimiters
|
|
1763
|
-
while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {
|
|
1764
|
-
maskedSrc = maskedSrc.slice(0, match.index + match[0].length - 2) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);
|
|
1765
|
-
this.tokenizer.rules.inline.escapedEmSt.lastIndex--;
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
|
-
while (src) {
|
|
1769
|
-
if (!keepPrevChar) {
|
|
1770
|
-
prevChar = '';
|
|
1771
|
-
}
|
|
1772
|
-
keepPrevChar = false;
|
|
1773
|
-
|
|
1774
|
-
// extensions
|
|
1775
|
-
if (this.options.extensions
|
|
1776
|
-
&& this.options.extensions.inline
|
|
1777
|
-
&& this.options.extensions.inline.some((extTokenizer) => {
|
|
1778
|
-
if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
|
|
1779
|
-
src = src.substring(token.raw.length);
|
|
1780
|
-
tokens.push(token);
|
|
1781
|
-
return true;
|
|
1782
|
-
}
|
|
1783
|
-
return false;
|
|
1784
|
-
})) {
|
|
1785
|
-
continue;
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
|
-
// escape
|
|
1789
|
-
if (token = this.tokenizer.escape(src)) {
|
|
1790
|
-
src = src.substring(token.raw.length);
|
|
1791
|
-
tokens.push(token);
|
|
1792
|
-
continue;
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
// tag
|
|
1796
|
-
if (token = this.tokenizer.tag(src)) {
|
|
1797
|
-
src = src.substring(token.raw.length);
|
|
1798
|
-
lastToken = tokens[tokens.length - 1];
|
|
1799
|
-
if (lastToken && token.type === 'text' && lastToken.type === 'text') {
|
|
1800
|
-
lastToken.raw += token.raw;
|
|
1801
|
-
lastToken.text += token.text;
|
|
1802
|
-
} else {
|
|
1803
|
-
tokens.push(token);
|
|
1804
|
-
}
|
|
1805
|
-
continue;
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
|
-
// link
|
|
1809
|
-
if (token = this.tokenizer.link(src)) {
|
|
1810
|
-
src = src.substring(token.raw.length);
|
|
1811
|
-
tokens.push(token);
|
|
1812
|
-
continue;
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1815
|
-
// reflink, nolink
|
|
1816
|
-
if (token = this.tokenizer.reflink(src, this.tokens.links)) {
|
|
1817
|
-
src = src.substring(token.raw.length);
|
|
1818
|
-
lastToken = tokens[tokens.length - 1];
|
|
1819
|
-
if (lastToken && token.type === 'text' && lastToken.type === 'text') {
|
|
1820
|
-
lastToken.raw += token.raw;
|
|
1821
|
-
lastToken.text += token.text;
|
|
1822
|
-
} else {
|
|
1823
|
-
tokens.push(token);
|
|
1824
|
-
}
|
|
1825
|
-
continue;
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
// em & strong
|
|
1829
|
-
if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
|
|
1830
|
-
src = src.substring(token.raw.length);
|
|
1831
|
-
tokens.push(token);
|
|
1832
|
-
continue;
|
|
1833
|
-
}
|
|
1834
|
-
|
|
1835
|
-
// code
|
|
1836
|
-
if (token = this.tokenizer.codespan(src)) {
|
|
1837
|
-
src = src.substring(token.raw.length);
|
|
1838
|
-
tokens.push(token);
|
|
1839
|
-
continue;
|
|
1840
|
-
}
|
|
1841
|
-
|
|
1842
|
-
// br
|
|
1843
|
-
if (token = this.tokenizer.br(src)) {
|
|
1844
|
-
src = src.substring(token.raw.length);
|
|
1845
|
-
tokens.push(token);
|
|
1846
|
-
continue;
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
|
-
// del (gfm)
|
|
1850
|
-
if (token = this.tokenizer.del(src)) {
|
|
1851
|
-
src = src.substring(token.raw.length);
|
|
1852
|
-
tokens.push(token);
|
|
1853
|
-
continue;
|
|
1854
|
-
}
|
|
1855
|
-
|
|
1856
|
-
// autolink
|
|
1857
|
-
if (token = this.tokenizer.autolink(src, mangle)) {
|
|
1858
|
-
src = src.substring(token.raw.length);
|
|
1859
|
-
tokens.push(token);
|
|
1860
|
-
continue;
|
|
1861
|
-
}
|
|
1862
|
-
|
|
1863
|
-
// url (gfm)
|
|
1864
|
-
if (!this.state.inLink && (token = this.tokenizer.url(src, mangle))) {
|
|
1865
|
-
src = src.substring(token.raw.length);
|
|
1866
|
-
tokens.push(token);
|
|
1867
|
-
continue;
|
|
1868
|
-
}
|
|
1869
|
-
|
|
1870
|
-
// text
|
|
1871
|
-
// prevent inlineText consuming extensions by clipping 'src' to extension start
|
|
1872
|
-
cutSrc = src;
|
|
1873
|
-
if (this.options.extensions && this.options.extensions.startInline) {
|
|
1874
|
-
let startIndex = Infinity;
|
|
1875
|
-
const tempSrc = src.slice(1);
|
|
1876
|
-
let tempStart;
|
|
1877
|
-
this.options.extensions.startInline.forEach(function(getStartIndex) {
|
|
1878
|
-
tempStart = getStartIndex.call({ lexer: this }, tempSrc);
|
|
1879
|
-
if (typeof tempStart === 'number' && tempStart >= 0) { startIndex = Math.min(startIndex, tempStart); }
|
|
1880
|
-
});
|
|
1881
|
-
if (startIndex < Infinity && startIndex >= 0) {
|
|
1882
|
-
cutSrc = src.substring(0, startIndex + 1);
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1885
|
-
if (token = this.tokenizer.inlineText(cutSrc, smartypants)) {
|
|
1886
|
-
src = src.substring(token.raw.length);
|
|
1887
|
-
if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started
|
|
1888
|
-
prevChar = token.raw.slice(-1);
|
|
1889
|
-
}
|
|
1890
|
-
keepPrevChar = true;
|
|
1891
|
-
lastToken = tokens[tokens.length - 1];
|
|
1892
|
-
if (lastToken && lastToken.type === 'text') {
|
|
1893
|
-
lastToken.raw += token.raw;
|
|
1894
|
-
lastToken.text += token.text;
|
|
1895
|
-
} else {
|
|
1896
|
-
tokens.push(token);
|
|
1897
|
-
}
|
|
1898
|
-
continue;
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
if (src) {
|
|
1902
|
-
const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
|
|
1903
|
-
if (this.options.silent) {
|
|
1904
|
-
console.error(errMsg);
|
|
1905
|
-
break;
|
|
1906
|
-
} else {
|
|
1907
|
-
throw new Error(errMsg);
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
|
|
1912
|
-
return tokens;
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1916
|
-
/**
|
|
1917
|
-
* Renderer
|
|
1918
|
-
*/
|
|
1919
|
-
class Renderer {
|
|
1920
|
-
constructor(options) {
|
|
1921
|
-
this.options = options || defaults;
|
|
1922
|
-
}
|
|
1923
|
-
|
|
1924
|
-
code(code, infostring, escaped) {
|
|
1925
|
-
const lang = (infostring || '').match(/\S*/)[0];
|
|
1926
|
-
if (this.options.highlight) {
|
|
1927
|
-
const out = this.options.highlight(code, lang);
|
|
1928
|
-
if (out != null && out !== code) {
|
|
1929
|
-
escaped = true;
|
|
1930
|
-
code = out;
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
code = code.replace(/\n$/, '') + '\n';
|
|
1935
|
-
|
|
1936
|
-
if (!lang) {
|
|
1937
|
-
return '<pre><code>'
|
|
1938
|
-
+ (escaped ? code : escape(code, true))
|
|
1939
|
-
+ '</code></pre>\n';
|
|
1940
|
-
}
|
|
1941
|
-
|
|
1942
|
-
return '<pre><code class="'
|
|
1943
|
-
+ this.options.langPrefix
|
|
1944
|
-
+ escape(lang)
|
|
1945
|
-
+ '">'
|
|
1946
|
-
+ (escaped ? code : escape(code, true))
|
|
1947
|
-
+ '</code></pre>\n';
|
|
1948
|
-
}
|
|
1949
|
-
|
|
1950
|
-
/**
|
|
1951
|
-
* @param {string} quote
|
|
1952
|
-
*/
|
|
1953
|
-
blockquote(quote) {
|
|
1954
|
-
return `<blockquote>\n${quote}</blockquote>\n`;
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
html(html) {
|
|
1958
|
-
return html;
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
/**
|
|
1962
|
-
* @param {string} text
|
|
1963
|
-
* @param {string} level
|
|
1964
|
-
* @param {string} raw
|
|
1965
|
-
* @param {any} slugger
|
|
1966
|
-
*/
|
|
1967
|
-
heading(text, level, raw, slugger) {
|
|
1968
|
-
if (this.options.headerIds) {
|
|
1969
|
-
const id = this.options.headerPrefix + slugger.slug(raw);
|
|
1970
|
-
return `<h${level} id="${id}">${text}</h${level}>\n`;
|
|
1971
|
-
}
|
|
1972
|
-
|
|
1973
|
-
// ignore IDs
|
|
1974
|
-
return `<h${level}>${text}</h${level}>\n`;
|
|
1975
|
-
}
|
|
1976
|
-
|
|
1977
|
-
hr() {
|
|
1978
|
-
return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
|
-
list(body, ordered, start) {
|
|
1982
|
-
const type = ordered ? 'ol' : 'ul',
|
|
1983
|
-
startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
|
|
1984
|
-
return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
|
|
1985
|
-
}
|
|
1986
|
-
|
|
1987
|
-
/**
|
|
1988
|
-
* @param {string} text
|
|
1989
|
-
*/
|
|
1990
|
-
listitem(text) {
|
|
1991
|
-
return `<li>${text}</li>\n`;
|
|
1992
|
-
}
|
|
1993
|
-
|
|
1994
|
-
checkbox(checked) {
|
|
1995
|
-
return '<input '
|
|
1996
|
-
+ (checked ? 'checked="" ' : '')
|
|
1997
|
-
+ 'disabled="" type="checkbox"'
|
|
1998
|
-
+ (this.options.xhtml ? ' /' : '')
|
|
1999
|
-
+ '> ';
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
|
-
/**
|
|
2003
|
-
* @param {string} text
|
|
2004
|
-
*/
|
|
2005
|
-
paragraph(text) {
|
|
2006
|
-
return `<p>${text}</p>\n`;
|
|
2007
|
-
}
|
|
2008
|
-
|
|
2009
|
-
/**
|
|
2010
|
-
* @param {string} header
|
|
2011
|
-
* @param {string} body
|
|
2012
|
-
*/
|
|
2013
|
-
table(header, body) {
|
|
2014
|
-
if (body) body = `<tbody>${body}</tbody>`;
|
|
2015
|
-
|
|
2016
|
-
return '<table>\n'
|
|
2017
|
-
+ '<thead>\n'
|
|
2018
|
-
+ header
|
|
2019
|
-
+ '</thead>\n'
|
|
2020
|
-
+ body
|
|
2021
|
-
+ '</table>\n';
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
/**
|
|
2025
|
-
* @param {string} content
|
|
2026
|
-
*/
|
|
2027
|
-
tablerow(content) {
|
|
2028
|
-
return `<tr>\n${content}</tr>\n`;
|
|
2029
|
-
}
|
|
2030
|
-
|
|
2031
|
-
tablecell(content, flags) {
|
|
2032
|
-
const type = flags.header ? 'th' : 'td';
|
|
2033
|
-
const tag = flags.align
|
|
2034
|
-
? `<${type} align="${flags.align}">`
|
|
2035
|
-
: `<${type}>`;
|
|
2036
|
-
return tag + content + `</${type}>\n`;
|
|
2037
|
-
}
|
|
2038
|
-
|
|
2039
|
-
/**
|
|
2040
|
-
* span level renderer
|
|
2041
|
-
* @param {string} text
|
|
2042
|
-
*/
|
|
2043
|
-
strong(text) {
|
|
2044
|
-
return `<strong>${text}</strong>`;
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
/**
|
|
2048
|
-
* @param {string} text
|
|
2049
|
-
*/
|
|
2050
|
-
em(text) {
|
|
2051
|
-
return `<em>${text}</em>`;
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
/**
|
|
2055
|
-
* @param {string} text
|
|
2056
|
-
*/
|
|
2057
|
-
codespan(text) {
|
|
2058
|
-
return `<code>${text}</code>`;
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
|
-
br() {
|
|
2062
|
-
return this.options.xhtml ? '<br/>' : '<br>';
|
|
2063
|
-
}
|
|
2064
|
-
|
|
2065
|
-
/**
|
|
2066
|
-
* @param {string} text
|
|
2067
|
-
*/
|
|
2068
|
-
del(text) {
|
|
2069
|
-
return `<del>${text}</del>`;
|
|
2070
|
-
}
|
|
2071
|
-
|
|
2072
|
-
/**
|
|
2073
|
-
* @param {string} href
|
|
2074
|
-
* @param {string} title
|
|
2075
|
-
* @param {string} text
|
|
2076
|
-
*/
|
|
2077
|
-
link(href, title, text) {
|
|
2078
|
-
href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
|
|
2079
|
-
if (href === null) {
|
|
2080
|
-
return text;
|
|
2081
|
-
}
|
|
2082
|
-
let out = '<a href="' + href + '"';
|
|
2083
|
-
if (title) {
|
|
2084
|
-
out += ' title="' + title + '"';
|
|
2085
|
-
}
|
|
2086
|
-
out += '>' + text + '</a>';
|
|
2087
|
-
return out;
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
/**
|
|
2091
|
-
* @param {string} href
|
|
2092
|
-
* @param {string} title
|
|
2093
|
-
* @param {string} text
|
|
2094
|
-
*/
|
|
2095
|
-
image(href, title, text) {
|
|
2096
|
-
href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
|
|
2097
|
-
if (href === null) {
|
|
2098
|
-
return text;
|
|
2099
|
-
}
|
|
2100
|
-
|
|
2101
|
-
let out = `<img src="${href}" alt="${text}"`;
|
|
2102
|
-
if (title) {
|
|
2103
|
-
out += ` title="${title}"`;
|
|
2104
|
-
}
|
|
2105
|
-
out += this.options.xhtml ? '/>' : '>';
|
|
2106
|
-
return out;
|
|
2107
|
-
}
|
|
2108
|
-
|
|
2109
|
-
text(text) {
|
|
2110
|
-
return text;
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
|
-
/**
|
|
2115
|
-
* TextRenderer
|
|
2116
|
-
* returns only the textual part of the token
|
|
2117
|
-
*/
|
|
2118
|
-
class TextRenderer {
|
|
2119
|
-
// no need for block level renderers
|
|
2120
|
-
strong(text) {
|
|
2121
|
-
return text;
|
|
2122
|
-
}
|
|
2123
|
-
|
|
2124
|
-
em(text) {
|
|
2125
|
-
return text;
|
|
2126
|
-
}
|
|
2127
|
-
|
|
2128
|
-
codespan(text) {
|
|
2129
|
-
return text;
|
|
2130
|
-
}
|
|
2131
|
-
|
|
2132
|
-
del(text) {
|
|
2133
|
-
return text;
|
|
2134
|
-
}
|
|
2135
|
-
|
|
2136
|
-
html(text) {
|
|
2137
|
-
return text;
|
|
2138
|
-
}
|
|
2139
|
-
|
|
2140
|
-
text(text) {
|
|
2141
|
-
return text;
|
|
2142
|
-
}
|
|
2143
|
-
|
|
2144
|
-
link(href, title, text) {
|
|
2145
|
-
return '' + text;
|
|
2146
|
-
}
|
|
2147
|
-
|
|
2148
|
-
image(href, title, text) {
|
|
2149
|
-
return '' + text;
|
|
2150
|
-
}
|
|
2151
|
-
|
|
2152
|
-
br() {
|
|
2153
|
-
return '';
|
|
2154
|
-
}
|
|
2155
|
-
}
|
|
2156
|
-
|
|
2157
|
-
/**
|
|
2158
|
-
* Slugger generates header id
|
|
2159
|
-
*/
|
|
2160
|
-
class Slugger {
|
|
2161
|
-
constructor() {
|
|
2162
|
-
this.seen = {};
|
|
2163
|
-
}
|
|
2164
|
-
|
|
2165
|
-
/**
|
|
2166
|
-
* @param {string} value
|
|
2167
|
-
*/
|
|
2168
|
-
serialize(value) {
|
|
2169
|
-
return value
|
|
2170
|
-
.toLowerCase()
|
|
2171
|
-
.trim()
|
|
2172
|
-
// remove html tags
|
|
2173
|
-
.replace(/<[!\/a-z].*?>/ig, '')
|
|
2174
|
-
// remove unwanted chars
|
|
2175
|
-
.replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '')
|
|
2176
|
-
.replace(/\s/g, '-');
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
|
-
/**
|
|
2180
|
-
* Finds the next safe (unique) slug to use
|
|
2181
|
-
* @param {string} originalSlug
|
|
2182
|
-
* @param {boolean} isDryRun
|
|
2183
|
-
*/
|
|
2184
|
-
getNextSafeSlug(originalSlug, isDryRun) {
|
|
2185
|
-
let slug = originalSlug;
|
|
2186
|
-
let occurenceAccumulator = 0;
|
|
2187
|
-
if (this.seen.hasOwnProperty(slug)) {
|
|
2188
|
-
occurenceAccumulator = this.seen[originalSlug];
|
|
2189
|
-
do {
|
|
2190
|
-
occurenceAccumulator++;
|
|
2191
|
-
slug = originalSlug + '-' + occurenceAccumulator;
|
|
2192
|
-
} while (this.seen.hasOwnProperty(slug));
|
|
2193
|
-
}
|
|
2194
|
-
if (!isDryRun) {
|
|
2195
|
-
this.seen[originalSlug] = occurenceAccumulator;
|
|
2196
|
-
this.seen[slug] = 0;
|
|
2197
|
-
}
|
|
2198
|
-
return slug;
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
|
-
/**
|
|
2202
|
-
* Convert string to unique id
|
|
2203
|
-
* @param {object} [options]
|
|
2204
|
-
* @param {boolean} [options.dryrun] Generates the next unique slug without
|
|
2205
|
-
* updating the internal accumulator.
|
|
2206
|
-
*/
|
|
2207
|
-
slug(value, options = {}) {
|
|
2208
|
-
const slug = this.serialize(value);
|
|
2209
|
-
return this.getNextSafeSlug(slug, options.dryrun);
|
|
2210
|
-
}
|
|
2211
|
-
}
|
|
2212
|
-
|
|
2213
|
-
/**
|
|
2214
|
-
* Parsing & Compiling
|
|
2215
|
-
*/
|
|
2216
|
-
class Parser {
|
|
2217
|
-
constructor(options) {
|
|
2218
|
-
this.options = options || defaults;
|
|
2219
|
-
this.options.renderer = this.options.renderer || new Renderer();
|
|
2220
|
-
this.renderer = this.options.renderer;
|
|
2221
|
-
this.renderer.options = this.options;
|
|
2222
|
-
this.textRenderer = new TextRenderer();
|
|
2223
|
-
this.slugger = new Slugger();
|
|
2224
|
-
}
|
|
2225
|
-
|
|
2226
|
-
/**
|
|
2227
|
-
* Static Parse Method
|
|
2228
|
-
*/
|
|
2229
|
-
static parse(tokens, options) {
|
|
2230
|
-
const parser = new Parser(options);
|
|
2231
|
-
return parser.parse(tokens);
|
|
2232
|
-
}
|
|
2233
|
-
|
|
2234
|
-
/**
|
|
2235
|
-
* Static Parse Inline Method
|
|
2236
|
-
*/
|
|
2237
|
-
static parseInline(tokens, options) {
|
|
2238
|
-
const parser = new Parser(options);
|
|
2239
|
-
return parser.parseInline(tokens);
|
|
2240
|
-
}
|
|
2241
|
-
|
|
2242
|
-
/**
|
|
2243
|
-
* Parse Loop
|
|
2244
|
-
*/
|
|
2245
|
-
parse(tokens, top = true) {
|
|
2246
|
-
let out = '',
|
|
2247
|
-
i,
|
|
2248
|
-
j,
|
|
2249
|
-
k,
|
|
2250
|
-
l2,
|
|
2251
|
-
l3,
|
|
2252
|
-
row,
|
|
2253
|
-
cell,
|
|
2254
|
-
header,
|
|
2255
|
-
body,
|
|
2256
|
-
token,
|
|
2257
|
-
ordered,
|
|
2258
|
-
start,
|
|
2259
|
-
loose,
|
|
2260
|
-
itemBody,
|
|
2261
|
-
item,
|
|
2262
|
-
checked,
|
|
2263
|
-
task,
|
|
2264
|
-
checkbox,
|
|
2265
|
-
ret;
|
|
2266
|
-
|
|
2267
|
-
const l = tokens.length;
|
|
2268
|
-
for (i = 0; i < l; i++) {
|
|
2269
|
-
token = tokens[i];
|
|
2270
|
-
|
|
2271
|
-
// Run any renderer extensions
|
|
2272
|
-
if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
|
|
2273
|
-
ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
|
|
2274
|
-
if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'paragraph', 'text'].includes(token.type)) {
|
|
2275
|
-
out += ret || '';
|
|
2276
|
-
continue;
|
|
2277
|
-
}
|
|
2278
|
-
}
|
|
2279
|
-
|
|
2280
|
-
switch (token.type) {
|
|
2281
|
-
case 'space': {
|
|
2282
|
-
continue;
|
|
2283
|
-
}
|
|
2284
|
-
case 'hr': {
|
|
2285
|
-
out += this.renderer.hr();
|
|
2286
|
-
continue;
|
|
2287
|
-
}
|
|
2288
|
-
case 'heading': {
|
|
2289
|
-
out += this.renderer.heading(
|
|
2290
|
-
this.parseInline(token.tokens),
|
|
2291
|
-
token.depth,
|
|
2292
|
-
unescape(this.parseInline(token.tokens, this.textRenderer)),
|
|
2293
|
-
this.slugger);
|
|
2294
|
-
continue;
|
|
2295
|
-
}
|
|
2296
|
-
case 'code': {
|
|
2297
|
-
out += this.renderer.code(token.text,
|
|
2298
|
-
token.lang,
|
|
2299
|
-
token.escaped);
|
|
2300
|
-
continue;
|
|
2301
|
-
}
|
|
2302
|
-
case 'table': {
|
|
2303
|
-
header = '';
|
|
2304
|
-
|
|
2305
|
-
// header
|
|
2306
|
-
cell = '';
|
|
2307
|
-
l2 = token.header.length;
|
|
2308
|
-
for (j = 0; j < l2; j++) {
|
|
2309
|
-
cell += this.renderer.tablecell(
|
|
2310
|
-
this.parseInline(token.header[j].tokens),
|
|
2311
|
-
{ header: true, align: token.align[j] }
|
|
2312
|
-
);
|
|
2313
|
-
}
|
|
2314
|
-
header += this.renderer.tablerow(cell);
|
|
2315
|
-
|
|
2316
|
-
body = '';
|
|
2317
|
-
l2 = token.rows.length;
|
|
2318
|
-
for (j = 0; j < l2; j++) {
|
|
2319
|
-
row = token.rows[j];
|
|
2320
|
-
|
|
2321
|
-
cell = '';
|
|
2322
|
-
l3 = row.length;
|
|
2323
|
-
for (k = 0; k < l3; k++) {
|
|
2324
|
-
cell += this.renderer.tablecell(
|
|
2325
|
-
this.parseInline(row[k].tokens),
|
|
2326
|
-
{ header: false, align: token.align[k] }
|
|
2327
|
-
);
|
|
2328
|
-
}
|
|
2329
|
-
|
|
2330
|
-
body += this.renderer.tablerow(cell);
|
|
2331
|
-
}
|
|
2332
|
-
out += this.renderer.table(header, body);
|
|
2333
|
-
continue;
|
|
2334
|
-
}
|
|
2335
|
-
case 'blockquote': {
|
|
2336
|
-
body = this.parse(token.tokens);
|
|
2337
|
-
out += this.renderer.blockquote(body);
|
|
2338
|
-
continue;
|
|
2339
|
-
}
|
|
2340
|
-
case 'list': {
|
|
2341
|
-
ordered = token.ordered;
|
|
2342
|
-
start = token.start;
|
|
2343
|
-
loose = token.loose;
|
|
2344
|
-
l2 = token.items.length;
|
|
2345
|
-
|
|
2346
|
-
body = '';
|
|
2347
|
-
for (j = 0; j < l2; j++) {
|
|
2348
|
-
item = token.items[j];
|
|
2349
|
-
checked = item.checked;
|
|
2350
|
-
task = item.task;
|
|
2351
|
-
|
|
2352
|
-
itemBody = '';
|
|
2353
|
-
if (item.task) {
|
|
2354
|
-
checkbox = this.renderer.checkbox(checked);
|
|
2355
|
-
if (loose) {
|
|
2356
|
-
if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') {
|
|
2357
|
-
item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
|
|
2358
|
-
if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
|
|
2359
|
-
item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
|
|
2360
|
-
}
|
|
2361
|
-
} else {
|
|
2362
|
-
item.tokens.unshift({
|
|
2363
|
-
type: 'text',
|
|
2364
|
-
text: checkbox
|
|
2365
|
-
});
|
|
2366
|
-
}
|
|
2367
|
-
} else {
|
|
2368
|
-
itemBody += checkbox;
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
|
|
2372
|
-
itemBody += this.parse(item.tokens, loose);
|
|
2373
|
-
body += this.renderer.listitem(itemBody, task, checked);
|
|
2374
|
-
}
|
|
2375
|
-
|
|
2376
|
-
out += this.renderer.list(body, ordered, start);
|
|
2377
|
-
continue;
|
|
2378
|
-
}
|
|
2379
|
-
case 'html': {
|
|
2380
|
-
// TODO parse inline content if parameter markdown=1
|
|
2381
|
-
out += this.renderer.html(token.text);
|
|
2382
|
-
continue;
|
|
2383
|
-
}
|
|
2384
|
-
case 'paragraph': {
|
|
2385
|
-
out += this.renderer.paragraph(this.parseInline(token.tokens));
|
|
2386
|
-
continue;
|
|
2387
|
-
}
|
|
2388
|
-
case 'text': {
|
|
2389
|
-
body = token.tokens ? this.parseInline(token.tokens) : token.text;
|
|
2390
|
-
while (i + 1 < l && tokens[i + 1].type === 'text') {
|
|
2391
|
-
token = tokens[++i];
|
|
2392
|
-
body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);
|
|
2393
|
-
}
|
|
2394
|
-
out += top ? this.renderer.paragraph(body) : body;
|
|
2395
|
-
continue;
|
|
2396
|
-
}
|
|
2397
|
-
|
|
2398
|
-
default: {
|
|
2399
|
-
const errMsg = 'Token with "' + token.type + '" type was not found.';
|
|
2400
|
-
if (this.options.silent) {
|
|
2401
|
-
console.error(errMsg);
|
|
2402
|
-
return;
|
|
2403
|
-
} else {
|
|
2404
|
-
throw new Error(errMsg);
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
|
-
|
|
2410
|
-
return out;
|
|
2411
|
-
}
|
|
2412
|
-
|
|
2413
|
-
/**
|
|
2414
|
-
* Parse Inline Tokens
|
|
2415
|
-
*/
|
|
2416
|
-
parseInline(tokens, renderer) {
|
|
2417
|
-
renderer = renderer || this.renderer;
|
|
2418
|
-
let out = '',
|
|
2419
|
-
i,
|
|
2420
|
-
token,
|
|
2421
|
-
ret;
|
|
2422
|
-
|
|
2423
|
-
const l = tokens.length;
|
|
2424
|
-
for (i = 0; i < l; i++) {
|
|
2425
|
-
token = tokens[i];
|
|
2426
|
-
|
|
2427
|
-
// Run any renderer extensions
|
|
2428
|
-
if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
|
|
2429
|
-
ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
|
|
2430
|
-
if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) {
|
|
2431
|
-
out += ret || '';
|
|
2432
|
-
continue;
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
|
|
2436
|
-
switch (token.type) {
|
|
2437
|
-
case 'escape': {
|
|
2438
|
-
out += renderer.text(token.text);
|
|
2439
|
-
break;
|
|
2440
|
-
}
|
|
2441
|
-
case 'html': {
|
|
2442
|
-
out += renderer.html(token.text);
|
|
2443
|
-
break;
|
|
2444
|
-
}
|
|
2445
|
-
case 'link': {
|
|
2446
|
-
out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
|
|
2447
|
-
break;
|
|
2448
|
-
}
|
|
2449
|
-
case 'image': {
|
|
2450
|
-
out += renderer.image(token.href, token.title, token.text);
|
|
2451
|
-
break;
|
|
2452
|
-
}
|
|
2453
|
-
case 'strong': {
|
|
2454
|
-
out += renderer.strong(this.parseInline(token.tokens, renderer));
|
|
2455
|
-
break;
|
|
2456
|
-
}
|
|
2457
|
-
case 'em': {
|
|
2458
|
-
out += renderer.em(this.parseInline(token.tokens, renderer));
|
|
2459
|
-
break;
|
|
2460
|
-
}
|
|
2461
|
-
case 'codespan': {
|
|
2462
|
-
out += renderer.codespan(token.text);
|
|
2463
|
-
break;
|
|
2464
|
-
}
|
|
2465
|
-
case 'br': {
|
|
2466
|
-
out += renderer.br();
|
|
2467
|
-
break;
|
|
2468
|
-
}
|
|
2469
|
-
case 'del': {
|
|
2470
|
-
out += renderer.del(this.parseInline(token.tokens, renderer));
|
|
2471
|
-
break;
|
|
2472
|
-
}
|
|
2473
|
-
case 'text': {
|
|
2474
|
-
out += renderer.text(token.text);
|
|
2475
|
-
break;
|
|
2476
|
-
}
|
|
2477
|
-
default: {
|
|
2478
|
-
const errMsg = 'Token with "' + token.type + '" type was not found.';
|
|
2479
|
-
if (this.options.silent) {
|
|
2480
|
-
console.error(errMsg);
|
|
2481
|
-
return;
|
|
2482
|
-
} else {
|
|
2483
|
-
throw new Error(errMsg);
|
|
2484
|
-
}
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
|
-
return out;
|
|
2489
|
-
}
|
|
2490
|
-
}
|
|
2491
|
-
|
|
2492
|
-
/**
|
|
2493
|
-
* Marked
|
|
2494
|
-
*/
|
|
2495
|
-
function marked(src, opt, callback) {
|
|
2496
|
-
// throw error in case of non string input
|
|
2497
|
-
if (typeof src === 'undefined' || src === null) {
|
|
2498
|
-
throw new Error('marked(): input parameter is undefined or null');
|
|
2499
|
-
}
|
|
2500
|
-
if (typeof src !== 'string') {
|
|
2501
|
-
throw new Error('marked(): input parameter is of type '
|
|
2502
|
-
+ Object.prototype.toString.call(src) + ', string expected');
|
|
2503
|
-
}
|
|
2504
|
-
|
|
2505
|
-
if (typeof opt === 'function') {
|
|
2506
|
-
callback = opt;
|
|
2507
|
-
opt = null;
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
|
-
opt = merge({}, marked.defaults, opt || {});
|
|
2511
|
-
checkSanitizeDeprecation(opt);
|
|
2512
|
-
|
|
2513
|
-
if (callback) {
|
|
2514
|
-
const highlight = opt.highlight;
|
|
2515
|
-
let tokens;
|
|
2516
|
-
|
|
2517
|
-
try {
|
|
2518
|
-
tokens = Lexer.lex(src, opt);
|
|
2519
|
-
} catch (e) {
|
|
2520
|
-
return callback(e);
|
|
2521
|
-
}
|
|
2522
|
-
|
|
2523
|
-
const done = function(err) {
|
|
2524
|
-
let out;
|
|
2525
|
-
|
|
2526
|
-
if (!err) {
|
|
2527
|
-
try {
|
|
2528
|
-
if (opt.walkTokens) {
|
|
2529
|
-
marked.walkTokens(tokens, opt.walkTokens);
|
|
2530
|
-
}
|
|
2531
|
-
out = Parser.parse(tokens, opt);
|
|
2532
|
-
} catch (e) {
|
|
2533
|
-
err = e;
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2536
|
-
|
|
2537
|
-
opt.highlight = highlight;
|
|
2538
|
-
|
|
2539
|
-
return err
|
|
2540
|
-
? callback(err)
|
|
2541
|
-
: callback(null, out);
|
|
2542
|
-
};
|
|
2543
|
-
|
|
2544
|
-
if (!highlight || highlight.length < 3) {
|
|
2545
|
-
return done();
|
|
2546
|
-
}
|
|
2547
|
-
|
|
2548
|
-
delete opt.highlight;
|
|
2549
|
-
|
|
2550
|
-
if (!tokens.length) return done();
|
|
2551
|
-
|
|
2552
|
-
let pending = 0;
|
|
2553
|
-
marked.walkTokens(tokens, function(token) {
|
|
2554
|
-
if (token.type === 'code') {
|
|
2555
|
-
pending++;
|
|
2556
|
-
setTimeout(() => {
|
|
2557
|
-
highlight(token.text, token.lang, function(err, code) {
|
|
2558
|
-
if (err) {
|
|
2559
|
-
return done(err);
|
|
2560
|
-
}
|
|
2561
|
-
if (code != null && code !== token.text) {
|
|
2562
|
-
token.text = code;
|
|
2563
|
-
token.escaped = true;
|
|
2564
|
-
}
|
|
2565
|
-
|
|
2566
|
-
pending--;
|
|
2567
|
-
if (pending === 0) {
|
|
2568
|
-
done();
|
|
2569
|
-
}
|
|
2570
|
-
});
|
|
2571
|
-
}, 0);
|
|
2572
|
-
}
|
|
2573
|
-
});
|
|
2574
|
-
|
|
2575
|
-
if (pending === 0) {
|
|
2576
|
-
done();
|
|
2577
|
-
}
|
|
2578
|
-
|
|
2579
|
-
return;
|
|
2580
|
-
}
|
|
2581
|
-
|
|
2582
|
-
function onError(e) {
|
|
2583
|
-
e.message += '\nPlease report this to https://github.com/markedjs/marked.';
|
|
2584
|
-
if (opt.silent) {
|
|
2585
|
-
return '<p>An error occurred:</p><pre>'
|
|
2586
|
-
+ escape(e.message + '', true)
|
|
2587
|
-
+ '</pre>';
|
|
2588
|
-
}
|
|
2589
|
-
throw e;
|
|
2590
|
-
}
|
|
2591
|
-
|
|
2592
|
-
try {
|
|
2593
|
-
const tokens = Lexer.lex(src, opt);
|
|
2594
|
-
if (opt.walkTokens) {
|
|
2595
|
-
if (opt.async) {
|
|
2596
|
-
return Promise.all(marked.walkTokens(tokens, opt.walkTokens))
|
|
2597
|
-
.then(() => {
|
|
2598
|
-
return Parser.parse(tokens, opt);
|
|
2599
|
-
})
|
|
2600
|
-
.catch(onError);
|
|
2601
|
-
}
|
|
2602
|
-
marked.walkTokens(tokens, opt.walkTokens);
|
|
2603
|
-
}
|
|
2604
|
-
return Parser.parse(tokens, opt);
|
|
2605
|
-
} catch (e) {
|
|
2606
|
-
onError(e);
|
|
2607
|
-
}
|
|
2608
|
-
}
|
|
2609
|
-
|
|
2610
|
-
/**
|
|
2611
|
-
* Options
|
|
2612
|
-
*/
|
|
2613
|
-
|
|
2614
|
-
marked.options =
|
|
2615
|
-
marked.setOptions = function(opt) {
|
|
2616
|
-
merge(marked.defaults, opt);
|
|
2617
|
-
changeDefaults(marked.defaults);
|
|
2618
|
-
return marked;
|
|
2619
|
-
};
|
|
2620
|
-
|
|
2621
|
-
marked.getDefaults = getDefaults;
|
|
2622
|
-
|
|
2623
|
-
marked.defaults = defaults;
|
|
2624
|
-
|
|
2625
|
-
/**
|
|
2626
|
-
* Use Extension
|
|
2627
|
-
*/
|
|
2628
|
-
|
|
2629
|
-
marked.use = function(...args) {
|
|
2630
|
-
const extensions = marked.defaults.extensions || { renderers: {}, childTokens: {} };
|
|
2631
|
-
|
|
2632
|
-
args.forEach((pack) => {
|
|
2633
|
-
// copy options to new object
|
|
2634
|
-
const opts = merge({}, pack);
|
|
2635
|
-
|
|
2636
|
-
// set async to true if it was set to true before
|
|
2637
|
-
opts.async = marked.defaults.async || opts.async;
|
|
2638
|
-
|
|
2639
|
-
// ==-- Parse "addon" extensions --== //
|
|
2640
|
-
if (pack.extensions) {
|
|
2641
|
-
pack.extensions.forEach((ext) => {
|
|
2642
|
-
if (!ext.name) {
|
|
2643
|
-
throw new Error('extension name required');
|
|
2644
|
-
}
|
|
2645
|
-
if (ext.renderer) { // Renderer extensions
|
|
2646
|
-
const prevRenderer = extensions.renderers[ext.name];
|
|
2647
|
-
if (prevRenderer) {
|
|
2648
|
-
// Replace extension with func to run new extension but fall back if false
|
|
2649
|
-
extensions.renderers[ext.name] = function(...args) {
|
|
2650
|
-
let ret = ext.renderer.apply(this, args);
|
|
2651
|
-
if (ret === false) {
|
|
2652
|
-
ret = prevRenderer.apply(this, args);
|
|
2653
|
-
}
|
|
2654
|
-
return ret;
|
|
2655
|
-
};
|
|
2656
|
-
} else {
|
|
2657
|
-
extensions.renderers[ext.name] = ext.renderer;
|
|
2658
|
-
}
|
|
2659
|
-
}
|
|
2660
|
-
if (ext.tokenizer) { // Tokenizer Extensions
|
|
2661
|
-
if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
|
|
2662
|
-
throw new Error("extension level must be 'block' or 'inline'");
|
|
2663
|
-
}
|
|
2664
|
-
if (extensions[ext.level]) {
|
|
2665
|
-
extensions[ext.level].unshift(ext.tokenizer);
|
|
2666
|
-
} else {
|
|
2667
|
-
extensions[ext.level] = [ext.tokenizer];
|
|
2668
|
-
}
|
|
2669
|
-
if (ext.start) { // Function to check for start of token
|
|
2670
|
-
if (ext.level === 'block') {
|
|
2671
|
-
if (extensions.startBlock) {
|
|
2672
|
-
extensions.startBlock.push(ext.start);
|
|
2673
|
-
} else {
|
|
2674
|
-
extensions.startBlock = [ext.start];
|
|
2675
|
-
}
|
|
2676
|
-
} else if (ext.level === 'inline') {
|
|
2677
|
-
if (extensions.startInline) {
|
|
2678
|
-
extensions.startInline.push(ext.start);
|
|
2679
|
-
} else {
|
|
2680
|
-
extensions.startInline = [ext.start];
|
|
2681
|
-
}
|
|
2682
|
-
}
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
if (ext.childTokens) { // Child tokens to be visited by walkTokens
|
|
2686
|
-
extensions.childTokens[ext.name] = ext.childTokens;
|
|
2687
|
-
}
|
|
2688
|
-
});
|
|
2689
|
-
opts.extensions = extensions;
|
|
2690
|
-
}
|
|
2691
|
-
|
|
2692
|
-
// ==-- Parse "overwrite" extensions --== //
|
|
2693
|
-
if (pack.renderer) {
|
|
2694
|
-
const renderer = marked.defaults.renderer || new Renderer();
|
|
2695
|
-
for (const prop in pack.renderer) {
|
|
2696
|
-
const prevRenderer = renderer[prop];
|
|
2697
|
-
// Replace renderer with func to run extension, but fall back if false
|
|
2698
|
-
renderer[prop] = (...args) => {
|
|
2699
|
-
let ret = pack.renderer[prop].apply(renderer, args);
|
|
2700
|
-
if (ret === false) {
|
|
2701
|
-
ret = prevRenderer.apply(renderer, args);
|
|
2702
|
-
}
|
|
2703
|
-
return ret;
|
|
2704
|
-
};
|
|
2705
|
-
}
|
|
2706
|
-
opts.renderer = renderer;
|
|
2707
|
-
}
|
|
2708
|
-
if (pack.tokenizer) {
|
|
2709
|
-
const tokenizer = marked.defaults.tokenizer || new Tokenizer();
|
|
2710
|
-
for (const prop in pack.tokenizer) {
|
|
2711
|
-
const prevTokenizer = tokenizer[prop];
|
|
2712
|
-
// Replace tokenizer with func to run extension, but fall back if false
|
|
2713
|
-
tokenizer[prop] = (...args) => {
|
|
2714
|
-
let ret = pack.tokenizer[prop].apply(tokenizer, args);
|
|
2715
|
-
if (ret === false) {
|
|
2716
|
-
ret = prevTokenizer.apply(tokenizer, args);
|
|
2717
|
-
}
|
|
2718
|
-
return ret;
|
|
2719
|
-
};
|
|
2720
|
-
}
|
|
2721
|
-
opts.tokenizer = tokenizer;
|
|
2722
|
-
}
|
|
2723
|
-
|
|
2724
|
-
// ==-- Parse WalkTokens extensions --== //
|
|
2725
|
-
if (pack.walkTokens) {
|
|
2726
|
-
const walkTokens = marked.defaults.walkTokens;
|
|
2727
|
-
opts.walkTokens = function(token) {
|
|
2728
|
-
let values = [];
|
|
2729
|
-
values.push(pack.walkTokens.call(this, token));
|
|
2730
|
-
if (walkTokens) {
|
|
2731
|
-
values = values.concat(walkTokens.call(this, token));
|
|
2732
|
-
}
|
|
2733
|
-
return values;
|
|
2734
|
-
};
|
|
2735
|
-
}
|
|
2736
|
-
|
|
2737
|
-
marked.setOptions(opts);
|
|
2738
|
-
});
|
|
2739
|
-
};
|
|
2740
|
-
|
|
2741
|
-
/**
|
|
2742
|
-
* Run callback for every token
|
|
2743
|
-
*/
|
|
2744
|
-
|
|
2745
|
-
marked.walkTokens = function(tokens, callback) {
|
|
2746
|
-
let values = [];
|
|
2747
|
-
for (const token of tokens) {
|
|
2748
|
-
values = values.concat(callback.call(marked, token));
|
|
2749
|
-
switch (token.type) {
|
|
2750
|
-
case 'table': {
|
|
2751
|
-
for (const cell of token.header) {
|
|
2752
|
-
values = values.concat(marked.walkTokens(cell.tokens, callback));
|
|
2753
|
-
}
|
|
2754
|
-
for (const row of token.rows) {
|
|
2755
|
-
for (const cell of row) {
|
|
2756
|
-
values = values.concat(marked.walkTokens(cell.tokens, callback));
|
|
2757
|
-
}
|
|
2758
|
-
}
|
|
2759
|
-
break;
|
|
2760
|
-
}
|
|
2761
|
-
case 'list': {
|
|
2762
|
-
values = values.concat(marked.walkTokens(token.items, callback));
|
|
2763
|
-
break;
|
|
2764
|
-
}
|
|
2765
|
-
default: {
|
|
2766
|
-
if (marked.defaults.extensions && marked.defaults.extensions.childTokens && marked.defaults.extensions.childTokens[token.type]) { // Walk any extensions
|
|
2767
|
-
marked.defaults.extensions.childTokens[token.type].forEach(function(childTokens) {
|
|
2768
|
-
values = values.concat(marked.walkTokens(token[childTokens], callback));
|
|
2769
|
-
});
|
|
2770
|
-
} else if (token.tokens) {
|
|
2771
|
-
values = values.concat(marked.walkTokens(token.tokens, callback));
|
|
2772
|
-
}
|
|
2773
|
-
}
|
|
2774
|
-
}
|
|
2775
|
-
}
|
|
2776
|
-
return values;
|
|
2777
|
-
};
|
|
2778
|
-
|
|
2779
|
-
/**
|
|
2780
|
-
* Parse Inline
|
|
2781
|
-
* @param {string} src
|
|
2782
|
-
*/
|
|
2783
|
-
marked.parseInline = function(src, opt) {
|
|
2784
|
-
// throw error in case of non string input
|
|
2785
|
-
if (typeof src === 'undefined' || src === null) {
|
|
2786
|
-
throw new Error('marked.parseInline(): input parameter is undefined or null');
|
|
2787
|
-
}
|
|
2788
|
-
if (typeof src !== 'string') {
|
|
2789
|
-
throw new Error('marked.parseInline(): input parameter is of type '
|
|
2790
|
-
+ Object.prototype.toString.call(src) + ', string expected');
|
|
2791
|
-
}
|
|
2792
|
-
|
|
2793
|
-
opt = merge({}, marked.defaults, opt || {});
|
|
2794
|
-
checkSanitizeDeprecation(opt);
|
|
2795
|
-
|
|
2796
|
-
try {
|
|
2797
|
-
const tokens = Lexer.lexInline(src, opt);
|
|
2798
|
-
if (opt.walkTokens) {
|
|
2799
|
-
marked.walkTokens(tokens, opt.walkTokens);
|
|
2800
|
-
}
|
|
2801
|
-
return Parser.parseInline(tokens, opt);
|
|
2802
|
-
} catch (e) {
|
|
2803
|
-
e.message += '\nPlease report this to https://github.com/markedjs/marked.';
|
|
2804
|
-
if (opt.silent) {
|
|
2805
|
-
return '<p>An error occurred:</p><pre>'
|
|
2806
|
-
+ escape(e.message + '', true)
|
|
2807
|
-
+ '</pre>';
|
|
2808
|
-
}
|
|
2809
|
-
throw e;
|
|
2810
|
-
}
|
|
2811
|
-
};
|
|
2812
|
-
|
|
2813
|
-
/**
|
|
2814
|
-
* Expose
|
|
2815
|
-
*/
|
|
2816
|
-
marked.Parser = Parser;
|
|
2817
|
-
marked.parser = Parser.parse;
|
|
2818
|
-
marked.Renderer = Renderer;
|
|
2819
|
-
marked.TextRenderer = TextRenderer;
|
|
2820
|
-
marked.Lexer = Lexer;
|
|
2821
|
-
marked.lexer = Lexer.lex;
|
|
2822
|
-
marked.Tokenizer = Tokenizer;
|
|
2823
|
-
marked.Slugger = Slugger;
|
|
2824
|
-
marked.parse = marked;
|
|
2825
|
-
|
|
2826
|
-
const options = marked.options;
|
|
2827
|
-
const setOptions = marked.setOptions;
|
|
2828
|
-
const use = marked.use;
|
|
2829
|
-
const walkTokens = marked.walkTokens;
|
|
2830
|
-
const parseInline = marked.parseInline;
|
|
2831
|
-
const parse = marked;
|
|
2832
|
-
const parser = Parser.parse;
|
|
2833
|
-
const lexer = Lexer.lex;
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
/***/ })
|
|
2839
|
-
|
|
2840
|
-
}]);
|