marked 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/marked.esm.js +267 -319
- package/lib/marked.js +299 -333
- package/marked.min.js +1 -1
- package/package.json +15 -14
- package/src/Lexer.js +46 -106
- package/src/Parser.js +9 -9
- package/src/Tokenizer.js +191 -169
- package/src/helpers.js +4 -0
- package/src/marked.js +8 -9
- package/src/rules.js +9 -29
package/src/Parser.js
CHANGED
|
@@ -65,8 +65,8 @@ module.exports = class Parser {
|
|
|
65
65
|
token = tokens[i];
|
|
66
66
|
|
|
67
67
|
// Run any renderer extensions
|
|
68
|
-
if (this.options.extensions
|
|
69
|
-
ret = this.options.extensions.renderers[token.type].call(this, token);
|
|
68
|
+
if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
|
|
69
|
+
ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
|
|
70
70
|
if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'paragraph', 'text'].includes(token.type)) {
|
|
71
71
|
out += ret || '';
|
|
72
72
|
continue;
|
|
@@ -103,22 +103,22 @@ module.exports = class Parser {
|
|
|
103
103
|
l2 = token.header.length;
|
|
104
104
|
for (j = 0; j < l2; j++) {
|
|
105
105
|
cell += this.renderer.tablecell(
|
|
106
|
-
this.parseInline(token.
|
|
106
|
+
this.parseInline(token.header[j].tokens),
|
|
107
107
|
{ header: true, align: token.align[j] }
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
header += this.renderer.tablerow(cell);
|
|
111
111
|
|
|
112
112
|
body = '';
|
|
113
|
-
l2 = token.
|
|
113
|
+
l2 = token.rows.length;
|
|
114
114
|
for (j = 0; j < l2; j++) {
|
|
115
|
-
row = token.
|
|
115
|
+
row = token.rows[j];
|
|
116
116
|
|
|
117
117
|
cell = '';
|
|
118
118
|
l3 = row.length;
|
|
119
119
|
for (k = 0; k < l3; k++) {
|
|
120
120
|
cell += this.renderer.tablecell(
|
|
121
|
-
this.parseInline(row[k]),
|
|
121
|
+
this.parseInline(row[k].tokens),
|
|
122
122
|
{ header: false, align: token.align[k] }
|
|
123
123
|
);
|
|
124
124
|
}
|
|
@@ -149,7 +149,7 @@ module.exports = class Parser {
|
|
|
149
149
|
if (item.task) {
|
|
150
150
|
checkbox = this.renderer.checkbox(checked);
|
|
151
151
|
if (loose) {
|
|
152
|
-
if (item.tokens.length > 0 && item.tokens[0].type === '
|
|
152
|
+
if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') {
|
|
153
153
|
item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
|
|
154
154
|
if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
|
|
155
155
|
item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
|
|
@@ -221,8 +221,8 @@ module.exports = class Parser {
|
|
|
221
221
|
token = tokens[i];
|
|
222
222
|
|
|
223
223
|
// Run any renderer extensions
|
|
224
|
-
if (this.options.extensions
|
|
225
|
-
ret = this.options.extensions.renderers[token.type].call(this, token);
|
|
224
|
+
if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
|
|
225
|
+
ret = this.options.extensions.renderers[token.type].call({ parser: this }, token);
|
|
226
226
|
if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) {
|
|
227
227
|
out += ret || '';
|
|
228
228
|
continue;
|
package/src/Tokenizer.js
CHANGED
|
@@ -6,18 +6,20 @@ const {
|
|
|
6
6
|
findClosingBracket
|
|
7
7
|
} = require('./helpers.js');
|
|
8
8
|
|
|
9
|
-
function outputLink(cap, link, raw) {
|
|
9
|
+
function outputLink(cap, link, raw, lexer) {
|
|
10
10
|
const href = link.href;
|
|
11
11
|
const title = link.title ? escape(link.title) : null;
|
|
12
12
|
const text = cap[1].replace(/\\([\[\]])/g, '$1');
|
|
13
13
|
|
|
14
14
|
if (cap[0].charAt(0) !== '!') {
|
|
15
|
+
lexer.state.inLink = true;
|
|
15
16
|
return {
|
|
16
17
|
type: 'link',
|
|
17
18
|
raw,
|
|
18
19
|
href,
|
|
19
20
|
title,
|
|
20
|
-
text
|
|
21
|
+
text,
|
|
22
|
+
tokens: lexer.inlineTokens(text, [])
|
|
21
23
|
};
|
|
22
24
|
} else {
|
|
23
25
|
return {
|
|
@@ -125,48 +127,15 @@ module.exports = class Tokenizer {
|
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
|
|
128
|
-
|
|
130
|
+
const token = {
|
|
129
131
|
type: 'heading',
|
|
130
132
|
raw: cap[0],
|
|
131
133
|
depth: cap[1].length,
|
|
132
|
-
text: text
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
nptable(src) {
|
|
138
|
-
const cap = this.rules.block.nptable.exec(src);
|
|
139
|
-
if (cap) {
|
|
140
|
-
const item = {
|
|
141
|
-
type: 'table',
|
|
142
|
-
header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
|
|
143
|
-
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
|
144
|
-
cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [],
|
|
145
|
-
raw: cap[0]
|
|
134
|
+
text: text,
|
|
135
|
+
tokens: []
|
|
146
136
|
};
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
let l = item.align.length;
|
|
150
|
-
let i;
|
|
151
|
-
for (i = 0; i < l; i++) {
|
|
152
|
-
if (/^ *-+: *$/.test(item.align[i])) {
|
|
153
|
-
item.align[i] = 'right';
|
|
154
|
-
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
|
155
|
-
item.align[i] = 'center';
|
|
156
|
-
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
|
157
|
-
item.align[i] = 'left';
|
|
158
|
-
} else {
|
|
159
|
-
item.align[i] = null;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
l = item.cells.length;
|
|
164
|
-
for (i = 0; i < l; i++) {
|
|
165
|
-
item.cells[i] = splitCells(item.cells[i], item.header.length);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return item;
|
|
169
|
-
}
|
|
137
|
+
this.lexer.inline(token.text, token.tokens);
|
|
138
|
+
return token;
|
|
170
139
|
}
|
|
171
140
|
}
|
|
172
141
|
|
|
@@ -188,138 +157,155 @@ module.exports = class Tokenizer {
|
|
|
188
157
|
return {
|
|
189
158
|
type: 'blockquote',
|
|
190
159
|
raw: cap[0],
|
|
160
|
+
tokens: this.lexer.blockTokens(text, []),
|
|
191
161
|
text
|
|
192
162
|
};
|
|
193
163
|
}
|
|
194
164
|
}
|
|
195
165
|
|
|
196
166
|
list(src) {
|
|
197
|
-
|
|
167
|
+
let cap = this.rules.block.list.exec(src);
|
|
198
168
|
if (cap) {
|
|
199
|
-
let raw
|
|
200
|
-
|
|
169
|
+
let raw, istask, ischecked, indent, i, blankLine, endsWithBlankLine,
|
|
170
|
+
line, lines, itemContents;
|
|
171
|
+
|
|
172
|
+
let bull = cap[1].trim();
|
|
201
173
|
const isordered = bull.length > 1;
|
|
202
174
|
|
|
203
175
|
const list = {
|
|
204
176
|
type: 'list',
|
|
205
|
-
raw,
|
|
177
|
+
raw: '',
|
|
206
178
|
ordered: isordered,
|
|
207
179
|
start: isordered ? +bull.slice(0, -1) : '',
|
|
208
180
|
loose: false,
|
|
209
181
|
items: []
|
|
210
182
|
};
|
|
211
183
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
let l = itemMatch.length;
|
|
227
|
-
bcurr = this.rules.block.listItemStart.exec(itemMatch[0]);
|
|
228
|
-
for (let i = 0; i < l; i++) {
|
|
229
|
-
item = itemMatch[i];
|
|
230
|
-
raw = item;
|
|
231
|
-
|
|
232
|
-
if (!this.options.pedantic) {
|
|
233
|
-
// Determine if current item contains the end of the list
|
|
234
|
-
endMatch = item.match(new RegExp('\\n\\s*\\n {0,' + (bcurr[0].length - 1) + '}\\S'));
|
|
235
|
-
if (endMatch) {
|
|
236
|
-
addBack = item.length - endMatch.index + itemMatch.slice(i + 1).join('\n').length;
|
|
237
|
-
list.raw = list.raw.substring(0, list.raw.length - addBack);
|
|
238
|
-
|
|
239
|
-
item = item.substring(0, endMatch.index);
|
|
240
|
-
raw = item;
|
|
241
|
-
l = i + 1;
|
|
242
|
-
}
|
|
184
|
+
bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
|
|
185
|
+
|
|
186
|
+
if (this.options.pedantic) {
|
|
187
|
+
bull = isordered ? bull : '[*+-]';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Get next list item
|
|
191
|
+
const itemRegex = new RegExp(`^( {0,3}${bull})((?: [^\\n]*| *)(?:\\n[^\\n]*)*(?:\\n|$))`);
|
|
192
|
+
|
|
193
|
+
// Get each top-level item
|
|
194
|
+
while (src) {
|
|
195
|
+
if (this.rules.block.hr.test(src)) { // End list if we encounter an HR (possibly move into itemRegex?)
|
|
196
|
+
break;
|
|
243
197
|
}
|
|
244
198
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (i !== l - 1) {
|
|
248
|
-
bnext = this.rules.block.listItemStart.exec(itemMatch[i + 1]);
|
|
249
|
-
if (
|
|
250
|
-
!this.options.pedantic
|
|
251
|
-
? bnext[1].length >= bcurr[0].length || bnext[1].length > 3
|
|
252
|
-
: bnext[1].length > bcurr[1].length
|
|
253
|
-
) {
|
|
254
|
-
// nested list or continuation
|
|
255
|
-
itemMatch.splice(i, 2, itemMatch[i] + (!this.options.pedantic && bnext[1].length < bcurr[0].length && !itemMatch[i].match(/\n$/) ? '' : '\n') + itemMatch[i + 1]);
|
|
256
|
-
i--;
|
|
257
|
-
l--;
|
|
258
|
-
continue;
|
|
259
|
-
} else if (
|
|
260
|
-
// different bullet style
|
|
261
|
-
!this.options.pedantic || this.options.smartLists
|
|
262
|
-
? bnext[2][bnext[2].length - 1] !== bull[bull.length - 1]
|
|
263
|
-
: isordered === (bnext[2].length === 1)
|
|
264
|
-
) {
|
|
265
|
-
addBack = itemMatch.slice(i + 1).join('\n').length;
|
|
266
|
-
list.raw = list.raw.substring(0, list.raw.length - addBack);
|
|
267
|
-
i = l - 1;
|
|
268
|
-
}
|
|
269
|
-
bcurr = bnext;
|
|
199
|
+
if (!(cap = itemRegex.exec(src))) {
|
|
200
|
+
break;
|
|
270
201
|
}
|
|
271
202
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
item = !this.options.pedantic
|
|
282
|
-
? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
|
|
283
|
-
: item.replace(/^ {1,4}/gm, '');
|
|
203
|
+
lines = cap[2].split('\n');
|
|
204
|
+
|
|
205
|
+
if (this.options.pedantic) {
|
|
206
|
+
indent = 2;
|
|
207
|
+
itemContents = lines[0].trimLeft();
|
|
208
|
+
} else {
|
|
209
|
+
indent = cap[2].search(/[^ ]/); // Find first non-space char
|
|
210
|
+
indent = cap[1].length + (indent > 4 ? 1 : indent); // intented code blocks after 4 spaces; indent is always 1
|
|
211
|
+
itemContents = lines[0].slice(indent - cap[1].length);
|
|
284
212
|
}
|
|
285
213
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
214
|
+
blankLine = false;
|
|
215
|
+
raw = cap[0];
|
|
216
|
+
|
|
217
|
+
if (!lines[0] && /^ *$/.test(lines[1])) { // items begin with at most one blank line
|
|
218
|
+
raw = cap[1] + lines.slice(0, 2).join('\n') + '\n';
|
|
219
|
+
list.loose = true;
|
|
220
|
+
lines = [];
|
|
290
221
|
}
|
|
291
222
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
223
|
+
const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])`);
|
|
224
|
+
|
|
225
|
+
for (i = 1; i < lines.length; i++) {
|
|
226
|
+
line = lines[i];
|
|
227
|
+
|
|
228
|
+
if (this.options.pedantic) { // Re-align to follow commonmark nesting rules
|
|
229
|
+
line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// End list item if found start of new bullet
|
|
233
|
+
if (nextBulletRegex.test(line)) {
|
|
234
|
+
raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Until we encounter a blank line, item contents do not need indentation
|
|
239
|
+
if (!blankLine) {
|
|
240
|
+
if (!line.trim()) { // Check if current line is empty
|
|
241
|
+
blankLine = true;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Dedent if possible
|
|
245
|
+
if (line.search(/[^ ]/) >= indent) {
|
|
246
|
+
itemContents += '\n' + line.slice(indent);
|
|
247
|
+
} else {
|
|
248
|
+
itemContents += '\n' + line;
|
|
249
|
+
}
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Dedent this line
|
|
254
|
+
if (line.search(/[^ ]/) >= indent || !line.trim()) {
|
|
255
|
+
itemContents += '\n' + line.slice(indent);
|
|
256
|
+
continue;
|
|
257
|
+
} else { // Line was not properly indented; end of this item
|
|
258
|
+
raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
299
261
|
}
|
|
300
262
|
|
|
301
|
-
if (loose) {
|
|
302
|
-
list
|
|
263
|
+
if (!list.loose) {
|
|
264
|
+
// If the previous item ended with a blank line, the list is loose
|
|
265
|
+
if (endsWithBlankLine) {
|
|
266
|
+
list.loose = true;
|
|
267
|
+
} else if (/\n *\n *$/.test(raw)) {
|
|
268
|
+
endsWithBlankLine = true;
|
|
269
|
+
}
|
|
303
270
|
}
|
|
304
271
|
|
|
305
272
|
// Check for task list items
|
|
306
273
|
if (this.options.gfm) {
|
|
307
|
-
istask = /^\[[ xX]\] /.
|
|
308
|
-
ischecked = undefined;
|
|
274
|
+
istask = /^\[[ xX]\] /.exec(itemContents);
|
|
309
275
|
if (istask) {
|
|
310
|
-
ischecked =
|
|
311
|
-
|
|
276
|
+
ischecked = istask[0] !== '[ ] ';
|
|
277
|
+
itemContents = itemContents.replace(/^\[[ xX]\] +/, '');
|
|
312
278
|
}
|
|
313
279
|
}
|
|
314
280
|
|
|
315
281
|
list.items.push({
|
|
316
282
|
type: 'list_item',
|
|
317
|
-
raw,
|
|
318
|
-
task: istask,
|
|
283
|
+
raw: raw,
|
|
284
|
+
task: !!istask,
|
|
319
285
|
checked: ischecked,
|
|
320
|
-
loose:
|
|
321
|
-
text:
|
|
286
|
+
loose: false,
|
|
287
|
+
text: itemContents
|
|
322
288
|
});
|
|
289
|
+
|
|
290
|
+
list.raw += raw;
|
|
291
|
+
src = src.slice(raw.length);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
|
|
295
|
+
list.items[list.items.length - 1].raw = raw.trimRight();
|
|
296
|
+
list.items[list.items.length - 1].text = itemContents.trimRight();
|
|
297
|
+
list.raw = list.raw.trimRight();
|
|
298
|
+
|
|
299
|
+
const l = list.items.length;
|
|
300
|
+
|
|
301
|
+
// Item child tokens handled here at end because we needed to have the final item to trim it first
|
|
302
|
+
for (i = 0; i < l; i++) {
|
|
303
|
+
this.lexer.state.top = false;
|
|
304
|
+
list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
|
|
305
|
+
if (list.items[i].tokens.some(t => t.type === 'space')) {
|
|
306
|
+
list.loose = true;
|
|
307
|
+
list.items[i].loose = true;
|
|
308
|
+
}
|
|
323
309
|
}
|
|
324
310
|
|
|
325
311
|
return list;
|
|
@@ -329,15 +315,20 @@ module.exports = class Tokenizer {
|
|
|
329
315
|
html(src) {
|
|
330
316
|
const cap = this.rules.block.html.exec(src);
|
|
331
317
|
if (cap) {
|
|
332
|
-
|
|
333
|
-
type:
|
|
334
|
-
? 'paragraph'
|
|
335
|
-
: 'html',
|
|
318
|
+
const token = {
|
|
319
|
+
type: 'html',
|
|
336
320
|
raw: cap[0],
|
|
337
321
|
pre: !this.options.sanitizer
|
|
338
322
|
&& (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
|
|
339
|
-
text:
|
|
323
|
+
text: cap[0]
|
|
340
324
|
};
|
|
325
|
+
if (this.options.sanitize) {
|
|
326
|
+
token.type = 'paragraph';
|
|
327
|
+
token.text = this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0]);
|
|
328
|
+
token.tokens = [];
|
|
329
|
+
this.lexer.inline(token.text, token.tokens);
|
|
330
|
+
}
|
|
331
|
+
return token;
|
|
341
332
|
}
|
|
342
333
|
}
|
|
343
334
|
|
|
@@ -361,16 +352,16 @@ module.exports = class Tokenizer {
|
|
|
361
352
|
if (cap) {
|
|
362
353
|
const item = {
|
|
363
354
|
type: 'table',
|
|
364
|
-
header: splitCells(cap[1].
|
|
355
|
+
header: splitCells(cap[1]).map(c => { return { text: c }; }),
|
|
365
356
|
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
|
366
|
-
|
|
357
|
+
rows: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
|
|
367
358
|
};
|
|
368
359
|
|
|
369
360
|
if (item.header.length === item.align.length) {
|
|
370
361
|
item.raw = cap[0];
|
|
371
362
|
|
|
372
363
|
let l = item.align.length;
|
|
373
|
-
let i;
|
|
364
|
+
let i, j, k, row;
|
|
374
365
|
for (i = 0; i < l; i++) {
|
|
375
366
|
if (/^ *-+: *$/.test(item.align[i])) {
|
|
376
367
|
item.align[i] = 'right';
|
|
@@ -383,11 +374,28 @@ module.exports = class Tokenizer {
|
|
|
383
374
|
}
|
|
384
375
|
}
|
|
385
376
|
|
|
386
|
-
l = item.
|
|
377
|
+
l = item.rows.length;
|
|
387
378
|
for (i = 0; i < l; i++) {
|
|
388
|
-
item.
|
|
389
|
-
|
|
390
|
-
|
|
379
|
+
item.rows[i] = splitCells(item.rows[i], item.header.length).map(c => { return { text: c }; });
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// parse child tokens inside headers and cells
|
|
383
|
+
|
|
384
|
+
// header child tokens
|
|
385
|
+
l = item.header.length;
|
|
386
|
+
for (j = 0; j < l; j++) {
|
|
387
|
+
item.header[j].tokens = [];
|
|
388
|
+
this.lexer.inlineTokens(item.header[j].text, item.header[j].tokens);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// cell child tokens
|
|
392
|
+
l = item.rows.length;
|
|
393
|
+
for (j = 0; j < l; j++) {
|
|
394
|
+
row = item.rows[j];
|
|
395
|
+
for (k = 0; k < row.length; k++) {
|
|
396
|
+
row[k].tokens = [];
|
|
397
|
+
this.lexer.inlineTokens(row[k].text, row[k].tokens);
|
|
398
|
+
}
|
|
391
399
|
}
|
|
392
400
|
|
|
393
401
|
return item;
|
|
@@ -398,36 +406,45 @@ module.exports = class Tokenizer {
|
|
|
398
406
|
lheading(src) {
|
|
399
407
|
const cap = this.rules.block.lheading.exec(src);
|
|
400
408
|
if (cap) {
|
|
401
|
-
|
|
409
|
+
const token = {
|
|
402
410
|
type: 'heading',
|
|
403
411
|
raw: cap[0],
|
|
404
412
|
depth: cap[2].charAt(0) === '=' ? 1 : 2,
|
|
405
|
-
text: cap[1]
|
|
413
|
+
text: cap[1],
|
|
414
|
+
tokens: []
|
|
406
415
|
};
|
|
416
|
+
this.lexer.inline(token.text, token.tokens);
|
|
417
|
+
return token;
|
|
407
418
|
}
|
|
408
419
|
}
|
|
409
420
|
|
|
410
421
|
paragraph(src) {
|
|
411
422
|
const cap = this.rules.block.paragraph.exec(src);
|
|
412
423
|
if (cap) {
|
|
413
|
-
|
|
424
|
+
const token = {
|
|
414
425
|
type: 'paragraph',
|
|
415
426
|
raw: cap[0],
|
|
416
427
|
text: cap[1].charAt(cap[1].length - 1) === '\n'
|
|
417
428
|
? cap[1].slice(0, -1)
|
|
418
|
-
: cap[1]
|
|
429
|
+
: cap[1],
|
|
430
|
+
tokens: []
|
|
419
431
|
};
|
|
432
|
+
this.lexer.inline(token.text, token.tokens);
|
|
433
|
+
return token;
|
|
420
434
|
}
|
|
421
435
|
}
|
|
422
436
|
|
|
423
437
|
text(src) {
|
|
424
438
|
const cap = this.rules.block.text.exec(src);
|
|
425
439
|
if (cap) {
|
|
426
|
-
|
|
440
|
+
const token = {
|
|
427
441
|
type: 'text',
|
|
428
442
|
raw: cap[0],
|
|
429
|
-
text: cap[0]
|
|
443
|
+
text: cap[0],
|
|
444
|
+
tokens: []
|
|
430
445
|
};
|
|
446
|
+
this.lexer.inline(token.text, token.tokens);
|
|
447
|
+
return token;
|
|
431
448
|
}
|
|
432
449
|
}
|
|
433
450
|
|
|
@@ -442,18 +459,18 @@ module.exports = class Tokenizer {
|
|
|
442
459
|
}
|
|
443
460
|
}
|
|
444
461
|
|
|
445
|
-
tag(src
|
|
462
|
+
tag(src) {
|
|
446
463
|
const cap = this.rules.inline.tag.exec(src);
|
|
447
464
|
if (cap) {
|
|
448
|
-
if (!inLink && /^<a /i.test(cap[0])) {
|
|
449
|
-
inLink = true;
|
|
450
|
-
} else if (inLink && /^<\/a>/i.test(cap[0])) {
|
|
451
|
-
inLink = false;
|
|
465
|
+
if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
|
|
466
|
+
this.lexer.state.inLink = true;
|
|
467
|
+
} else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
|
|
468
|
+
this.lexer.state.inLink = false;
|
|
452
469
|
}
|
|
453
|
-
if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
454
|
-
inRawBlock = true;
|
|
455
|
-
} else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
456
|
-
inRawBlock = false;
|
|
470
|
+
if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
471
|
+
this.lexer.state.inRawBlock = true;
|
|
472
|
+
} else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
473
|
+
this.lexer.state.inRawBlock = false;
|
|
457
474
|
}
|
|
458
475
|
|
|
459
476
|
return {
|
|
@@ -461,8 +478,8 @@ module.exports = class Tokenizer {
|
|
|
461
478
|
? 'text'
|
|
462
479
|
: 'html',
|
|
463
480
|
raw: cap[0],
|
|
464
|
-
inLink,
|
|
465
|
-
inRawBlock,
|
|
481
|
+
inLink: this.lexer.state.inLink,
|
|
482
|
+
inRawBlock: this.lexer.state.inRawBlock,
|
|
466
483
|
text: this.options.sanitize
|
|
467
484
|
? (this.options.sanitizer
|
|
468
485
|
? this.options.sanitizer(cap[0])
|
|
@@ -524,7 +541,7 @@ module.exports = class Tokenizer {
|
|
|
524
541
|
return outputLink(cap, {
|
|
525
542
|
href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
|
|
526
543
|
title: title ? title.replace(this.rules.inline._escapes, '$1') : title
|
|
527
|
-
}, cap[0]);
|
|
544
|
+
}, cap[0], this.lexer);
|
|
528
545
|
}
|
|
529
546
|
}
|
|
530
547
|
|
|
@@ -542,7 +559,7 @@ module.exports = class Tokenizer {
|
|
|
542
559
|
text
|
|
543
560
|
};
|
|
544
561
|
}
|
|
545
|
-
return outputLink(cap, link, cap[0]);
|
|
562
|
+
return outputLink(cap, link, cap[0], this.lexer);
|
|
546
563
|
}
|
|
547
564
|
}
|
|
548
565
|
|
|
@@ -591,18 +608,22 @@ module.exports = class Tokenizer {
|
|
|
591
608
|
|
|
592
609
|
// Create `em` if smallest delimiter has odd char count. *a***
|
|
593
610
|
if (Math.min(lLength, rLength) % 2) {
|
|
611
|
+
const text = src.slice(1, lLength + match.index + rLength);
|
|
594
612
|
return {
|
|
595
613
|
type: 'em',
|
|
596
614
|
raw: src.slice(0, lLength + match.index + rLength + 1),
|
|
597
|
-
text
|
|
615
|
+
text,
|
|
616
|
+
tokens: this.lexer.inlineTokens(text, [])
|
|
598
617
|
};
|
|
599
618
|
}
|
|
600
619
|
|
|
601
620
|
// Create 'strong' if smallest delimiter has even char count. **a***
|
|
621
|
+
const text = src.slice(2, lLength + match.index + rLength - 1);
|
|
602
622
|
return {
|
|
603
623
|
type: 'strong',
|
|
604
624
|
raw: src.slice(0, lLength + match.index + rLength + 1),
|
|
605
|
-
text
|
|
625
|
+
text,
|
|
626
|
+
tokens: this.lexer.inlineTokens(text, [])
|
|
606
627
|
};
|
|
607
628
|
}
|
|
608
629
|
}
|
|
@@ -642,7 +663,8 @@ module.exports = class Tokenizer {
|
|
|
642
663
|
return {
|
|
643
664
|
type: 'del',
|
|
644
665
|
raw: cap[0],
|
|
645
|
-
text: cap[2]
|
|
666
|
+
text: cap[2],
|
|
667
|
+
tokens: this.lexer.inlineTokens(cap[2], [])
|
|
646
668
|
};
|
|
647
669
|
}
|
|
648
670
|
}
|
|
@@ -712,11 +734,11 @@ module.exports = class Tokenizer {
|
|
|
712
734
|
}
|
|
713
735
|
}
|
|
714
736
|
|
|
715
|
-
inlineText(src,
|
|
737
|
+
inlineText(src, smartypants) {
|
|
716
738
|
const cap = this.rules.inline.text.exec(src);
|
|
717
739
|
if (cap) {
|
|
718
740
|
let text;
|
|
719
|
-
if (inRawBlock) {
|
|
741
|
+
if (this.lexer.state.inRawBlock) {
|
|
720
742
|
text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0];
|
|
721
743
|
} else {
|
|
722
744
|
text = escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
|
package/src/helpers.js
CHANGED
|
@@ -160,6 +160,10 @@ function splitCells(tableRow, count) {
|
|
|
160
160
|
cells = row.split(/ \|/);
|
|
161
161
|
let i = 0;
|
|
162
162
|
|
|
163
|
+
// First/last cell in a row cannot be empty if it has no leading/trailing pipe
|
|
164
|
+
if (!cells[0].trim()) { cells.shift(); }
|
|
165
|
+
if (!cells[cells.length - 1].trim()) { cells.pop(); }
|
|
166
|
+
|
|
163
167
|
if (cells.length > count) {
|
|
164
168
|
cells.splice(count);
|
|
165
169
|
} else {
|
package/src/marked.js
CHANGED
|
@@ -155,7 +155,7 @@ marked.use = function(...args) {
|
|
|
155
155
|
throw new Error('extension name required');
|
|
156
156
|
}
|
|
157
157
|
if (ext.renderer) { // Renderer extensions
|
|
158
|
-
const prevRenderer = extensions.renderers
|
|
158
|
+
const prevRenderer = extensions.renderers ? extensions.renderers[ext.name] : null;
|
|
159
159
|
if (prevRenderer) {
|
|
160
160
|
// Replace extension with func to run new extension but fall back if false
|
|
161
161
|
extensions.renderers[ext.name] = function(...args) {
|
|
@@ -260,12 +260,12 @@ marked.walkTokens = function(tokens, callback) {
|
|
|
260
260
|
callback(token);
|
|
261
261
|
switch (token.type) {
|
|
262
262
|
case 'table': {
|
|
263
|
-
for (const cell of token.
|
|
264
|
-
marked.walkTokens(cell, callback);
|
|
263
|
+
for (const cell of token.header) {
|
|
264
|
+
marked.walkTokens(cell.tokens, callback);
|
|
265
265
|
}
|
|
266
|
-
for (const row of token.
|
|
266
|
+
for (const row of token.rows) {
|
|
267
267
|
for (const cell of row) {
|
|
268
|
-
marked.walkTokens(cell, callback);
|
|
268
|
+
marked.walkTokens(cell.tokens, callback);
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
break;
|
|
@@ -275,12 +275,11 @@ marked.walkTokens = function(tokens, callback) {
|
|
|
275
275
|
break;
|
|
276
276
|
}
|
|
277
277
|
default: {
|
|
278
|
-
if (marked.defaults
|
|
279
|
-
marked.defaults
|
|
278
|
+
if (marked.defaults.extensions && marked.defaults.extensions.childTokens && marked.defaults.extensions.childTokens[token.type]) { // Walk any extensions
|
|
279
|
+
marked.defaults.extensions.childTokens[token.type].forEach(function(childTokens) {
|
|
280
280
|
marked.walkTokens(token[childTokens], callback);
|
|
281
281
|
});
|
|
282
|
-
}
|
|
283
|
-
if (token.tokens && !marked.defaults?.extensions?.childTokens[token.type]) {
|
|
282
|
+
} else if (token.tokens) {
|
|
284
283
|
marked.walkTokens(token.tokens, callback);
|
|
285
284
|
}
|
|
286
285
|
}
|