marked 2.1.3 → 3.0.3
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/README.md +6 -0
- package/lib/marked.esm.js +254 -305
- package/lib/marked.js +288 -304
- package/marked.min.js +1 -1
- package/package.json +16 -15
- package/src/Lexer.js +40 -102
- package/src/Parser.js +7 -7
- package/src/Tokenizer.js +194 -170
- package/src/helpers.js +4 -0
- package/src/marked.js +4 -4
- package/src/rules.js +5 -25
package/src/Parser.js
CHANGED
|
@@ -66,7 +66,7 @@ module.exports = class Parser {
|
|
|
66
66
|
|
|
67
67
|
// Run any renderer extensions
|
|
68
68
|
if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
|
|
69
|
-
ret = this.options.extensions.renderers[token.type].call(this, token);
|
|
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;
|
|
@@ -222,7 +222,7 @@ module.exports = class Parser {
|
|
|
222
222
|
|
|
223
223
|
// Run any renderer extensions
|
|
224
224
|
if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
|
|
225
|
-
ret = this.options.extensions.renderers[token.type].call(this, token);
|
|
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,19 +6,23 @@ 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
|
-
|
|
15
|
+
lexer.state.inLink = true;
|
|
16
|
+
const token = {
|
|
16
17
|
type: 'link',
|
|
17
18
|
raw,
|
|
18
19
|
href,
|
|
19
20
|
title,
|
|
20
|
-
text
|
|
21
|
+
text,
|
|
22
|
+
tokens: lexer.inlineTokens(text, [])
|
|
21
23
|
};
|
|
24
|
+
lexer.state.inLink = false;
|
|
25
|
+
return token;
|
|
22
26
|
} else {
|
|
23
27
|
return {
|
|
24
28
|
type: 'image',
|
|
@@ -125,48 +129,15 @@ module.exports = class Tokenizer {
|
|
|
125
129
|
}
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
|
|
132
|
+
const token = {
|
|
129
133
|
type: 'heading',
|
|
130
134
|
raw: cap[0],
|
|
131
135
|
depth: cap[1].length,
|
|
132
|
-
text: text
|
|
136
|
+
text: text,
|
|
137
|
+
tokens: []
|
|
133
138
|
};
|
|
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]
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
if (item.header.length === item.align.length) {
|
|
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
|
-
}
|
|
139
|
+
this.lexer.inline(token.text, token.tokens);
|
|
140
|
+
return token;
|
|
170
141
|
}
|
|
171
142
|
}
|
|
172
143
|
|
|
@@ -188,138 +159,155 @@ module.exports = class Tokenizer {
|
|
|
188
159
|
return {
|
|
189
160
|
type: 'blockquote',
|
|
190
161
|
raw: cap[0],
|
|
162
|
+
tokens: this.lexer.blockTokens(text, []),
|
|
191
163
|
text
|
|
192
164
|
};
|
|
193
165
|
}
|
|
194
166
|
}
|
|
195
167
|
|
|
196
168
|
list(src) {
|
|
197
|
-
|
|
169
|
+
let cap = this.rules.block.list.exec(src);
|
|
198
170
|
if (cap) {
|
|
199
|
-
let raw
|
|
200
|
-
|
|
171
|
+
let raw, istask, ischecked, indent, i, blankLine, endsWithBlankLine,
|
|
172
|
+
line, lines, itemContents;
|
|
173
|
+
|
|
174
|
+
let bull = cap[1].trim();
|
|
201
175
|
const isordered = bull.length > 1;
|
|
202
176
|
|
|
203
177
|
const list = {
|
|
204
178
|
type: 'list',
|
|
205
|
-
raw,
|
|
179
|
+
raw: '',
|
|
206
180
|
ordered: isordered,
|
|
207
181
|
start: isordered ? +bull.slice(0, -1) : '',
|
|
208
182
|
loose: false,
|
|
209
183
|
items: []
|
|
210
184
|
};
|
|
211
185
|
|
|
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
|
-
}
|
|
186
|
+
bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`;
|
|
187
|
+
|
|
188
|
+
if (this.options.pedantic) {
|
|
189
|
+
bull = isordered ? bull : '[*+-]';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Get next list item
|
|
193
|
+
const itemRegex = new RegExp(`^( {0,3}${bull})((?: [^\\n]*| *)(?:\\n[^\\n]*)*(?:\\n|$))`);
|
|
194
|
+
|
|
195
|
+
// Get each top-level item
|
|
196
|
+
while (src) {
|
|
197
|
+
if (this.rules.block.hr.test(src)) { // End list if we encounter an HR (possibly move into itemRegex?)
|
|
198
|
+
break;
|
|
243
199
|
}
|
|
244
200
|
|
|
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;
|
|
201
|
+
if (!(cap = itemRegex.exec(src))) {
|
|
202
|
+
break;
|
|
270
203
|
}
|
|
271
204
|
|
|
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, '');
|
|
205
|
+
lines = cap[2].split('\n');
|
|
206
|
+
|
|
207
|
+
if (this.options.pedantic) {
|
|
208
|
+
indent = 2;
|
|
209
|
+
itemContents = lines[0].trimLeft();
|
|
210
|
+
} else {
|
|
211
|
+
indent = cap[2].search(/[^ ]/); // Find first non-space char
|
|
212
|
+
indent = cap[1].length + (indent > 4 ? 1 : indent); // intented code blocks after 4 spaces; indent is always 1
|
|
213
|
+
itemContents = lines[0].slice(indent - cap[1].length);
|
|
284
214
|
}
|
|
285
215
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
216
|
+
blankLine = false;
|
|
217
|
+
raw = cap[0];
|
|
218
|
+
|
|
219
|
+
if (!lines[0] && /^ *$/.test(lines[1])) { // items begin with at most one blank line
|
|
220
|
+
raw = cap[1] + lines.slice(0, 2).join('\n') + '\n';
|
|
221
|
+
list.loose = true;
|
|
222
|
+
lines = [];
|
|
290
223
|
}
|
|
291
224
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
225
|
+
const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])`);
|
|
226
|
+
|
|
227
|
+
for (i = 1; i < lines.length; i++) {
|
|
228
|
+
line = lines[i];
|
|
229
|
+
|
|
230
|
+
if (this.options.pedantic) { // Re-align to follow commonmark nesting rules
|
|
231
|
+
line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// End list item if found start of new bullet
|
|
235
|
+
if (nextBulletRegex.test(line)) {
|
|
236
|
+
raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Until we encounter a blank line, item contents do not need indentation
|
|
241
|
+
if (!blankLine) {
|
|
242
|
+
if (!line.trim()) { // Check if current line is empty
|
|
243
|
+
blankLine = true;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Dedent if possible
|
|
247
|
+
if (line.search(/[^ ]/) >= indent) {
|
|
248
|
+
itemContents += '\n' + line.slice(indent);
|
|
249
|
+
} else {
|
|
250
|
+
itemContents += '\n' + line;
|
|
251
|
+
}
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Dedent this line
|
|
256
|
+
if (line.search(/[^ ]/) >= indent || !line.trim()) {
|
|
257
|
+
itemContents += '\n' + line.slice(indent);
|
|
258
|
+
continue;
|
|
259
|
+
} else { // Line was not properly indented; end of this item
|
|
260
|
+
raw = cap[1] + lines.slice(0, i).join('\n') + '\n';
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
299
263
|
}
|
|
300
264
|
|
|
301
|
-
if (loose) {
|
|
302
|
-
list
|
|
265
|
+
if (!list.loose) {
|
|
266
|
+
// If the previous item ended with a blank line, the list is loose
|
|
267
|
+
if (endsWithBlankLine) {
|
|
268
|
+
list.loose = true;
|
|
269
|
+
} else if (/\n *\n *$/.test(raw)) {
|
|
270
|
+
endsWithBlankLine = true;
|
|
271
|
+
}
|
|
303
272
|
}
|
|
304
273
|
|
|
305
274
|
// Check for task list items
|
|
306
275
|
if (this.options.gfm) {
|
|
307
|
-
istask = /^\[[ xX]\] /.
|
|
308
|
-
ischecked = undefined;
|
|
276
|
+
istask = /^\[[ xX]\] /.exec(itemContents);
|
|
309
277
|
if (istask) {
|
|
310
|
-
ischecked =
|
|
311
|
-
|
|
278
|
+
ischecked = istask[0] !== '[ ] ';
|
|
279
|
+
itemContents = itemContents.replace(/^\[[ xX]\] +/, '');
|
|
312
280
|
}
|
|
313
281
|
}
|
|
314
282
|
|
|
315
283
|
list.items.push({
|
|
316
284
|
type: 'list_item',
|
|
317
|
-
raw,
|
|
318
|
-
task: istask,
|
|
285
|
+
raw: raw,
|
|
286
|
+
task: !!istask,
|
|
319
287
|
checked: ischecked,
|
|
320
|
-
loose:
|
|
321
|
-
text:
|
|
288
|
+
loose: false,
|
|
289
|
+
text: itemContents
|
|
322
290
|
});
|
|
291
|
+
|
|
292
|
+
list.raw += raw;
|
|
293
|
+
src = src.slice(raw.length);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
|
|
297
|
+
list.items[list.items.length - 1].raw = raw.trimRight();
|
|
298
|
+
list.items[list.items.length - 1].text = itemContents.trimRight();
|
|
299
|
+
list.raw = list.raw.trimRight();
|
|
300
|
+
|
|
301
|
+
const l = list.items.length;
|
|
302
|
+
|
|
303
|
+
// Item child tokens handled here at end because we needed to have the final item to trim it first
|
|
304
|
+
for (i = 0; i < l; i++) {
|
|
305
|
+
this.lexer.state.top = false;
|
|
306
|
+
list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);
|
|
307
|
+
if (list.items[i].tokens.some(t => t.type === 'space')) {
|
|
308
|
+
list.loose = true;
|
|
309
|
+
list.items[i].loose = true;
|
|
310
|
+
}
|
|
323
311
|
}
|
|
324
312
|
|
|
325
313
|
return list;
|
|
@@ -329,15 +317,20 @@ module.exports = class Tokenizer {
|
|
|
329
317
|
html(src) {
|
|
330
318
|
const cap = this.rules.block.html.exec(src);
|
|
331
319
|
if (cap) {
|
|
332
|
-
|
|
333
|
-
type:
|
|
334
|
-
? 'paragraph'
|
|
335
|
-
: 'html',
|
|
320
|
+
const token = {
|
|
321
|
+
type: 'html',
|
|
336
322
|
raw: cap[0],
|
|
337
323
|
pre: !this.options.sanitizer
|
|
338
324
|
&& (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
|
|
339
|
-
text:
|
|
325
|
+
text: cap[0]
|
|
340
326
|
};
|
|
327
|
+
if (this.options.sanitize) {
|
|
328
|
+
token.type = 'paragraph';
|
|
329
|
+
token.text = this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0]);
|
|
330
|
+
token.tokens = [];
|
|
331
|
+
this.lexer.inline(token.text, token.tokens);
|
|
332
|
+
}
|
|
333
|
+
return token;
|
|
341
334
|
}
|
|
342
335
|
}
|
|
343
336
|
|
|
@@ -361,16 +354,16 @@ module.exports = class Tokenizer {
|
|
|
361
354
|
if (cap) {
|
|
362
355
|
const item = {
|
|
363
356
|
type: 'table',
|
|
364
|
-
header: splitCells(cap[1].
|
|
357
|
+
header: splitCells(cap[1]).map(c => { return { text: c }; }),
|
|
365
358
|
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
|
366
|
-
|
|
359
|
+
rows: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
|
|
367
360
|
};
|
|
368
361
|
|
|
369
362
|
if (item.header.length === item.align.length) {
|
|
370
363
|
item.raw = cap[0];
|
|
371
364
|
|
|
372
365
|
let l = item.align.length;
|
|
373
|
-
let i;
|
|
366
|
+
let i, j, k, row;
|
|
374
367
|
for (i = 0; i < l; i++) {
|
|
375
368
|
if (/^ *-+: *$/.test(item.align[i])) {
|
|
376
369
|
item.align[i] = 'right';
|
|
@@ -383,11 +376,28 @@ module.exports = class Tokenizer {
|
|
|
383
376
|
}
|
|
384
377
|
}
|
|
385
378
|
|
|
386
|
-
l = item.
|
|
379
|
+
l = item.rows.length;
|
|
387
380
|
for (i = 0; i < l; i++) {
|
|
388
|
-
item.
|
|
389
|
-
|
|
390
|
-
|
|
381
|
+
item.rows[i] = splitCells(item.rows[i], item.header.length).map(c => { return { text: c }; });
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// parse child tokens inside headers and cells
|
|
385
|
+
|
|
386
|
+
// header child tokens
|
|
387
|
+
l = item.header.length;
|
|
388
|
+
for (j = 0; j < l; j++) {
|
|
389
|
+
item.header[j].tokens = [];
|
|
390
|
+
this.lexer.inlineTokens(item.header[j].text, item.header[j].tokens);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// cell child tokens
|
|
394
|
+
l = item.rows.length;
|
|
395
|
+
for (j = 0; j < l; j++) {
|
|
396
|
+
row = item.rows[j];
|
|
397
|
+
for (k = 0; k < row.length; k++) {
|
|
398
|
+
row[k].tokens = [];
|
|
399
|
+
this.lexer.inlineTokens(row[k].text, row[k].tokens);
|
|
400
|
+
}
|
|
391
401
|
}
|
|
392
402
|
|
|
393
403
|
return item;
|
|
@@ -398,36 +408,45 @@ module.exports = class Tokenizer {
|
|
|
398
408
|
lheading(src) {
|
|
399
409
|
const cap = this.rules.block.lheading.exec(src);
|
|
400
410
|
if (cap) {
|
|
401
|
-
|
|
411
|
+
const token = {
|
|
402
412
|
type: 'heading',
|
|
403
413
|
raw: cap[0],
|
|
404
414
|
depth: cap[2].charAt(0) === '=' ? 1 : 2,
|
|
405
|
-
text: cap[1]
|
|
415
|
+
text: cap[1],
|
|
416
|
+
tokens: []
|
|
406
417
|
};
|
|
418
|
+
this.lexer.inline(token.text, token.tokens);
|
|
419
|
+
return token;
|
|
407
420
|
}
|
|
408
421
|
}
|
|
409
422
|
|
|
410
423
|
paragraph(src) {
|
|
411
424
|
const cap = this.rules.block.paragraph.exec(src);
|
|
412
425
|
if (cap) {
|
|
413
|
-
|
|
426
|
+
const token = {
|
|
414
427
|
type: 'paragraph',
|
|
415
428
|
raw: cap[0],
|
|
416
429
|
text: cap[1].charAt(cap[1].length - 1) === '\n'
|
|
417
430
|
? cap[1].slice(0, -1)
|
|
418
|
-
: cap[1]
|
|
431
|
+
: cap[1],
|
|
432
|
+
tokens: []
|
|
419
433
|
};
|
|
434
|
+
this.lexer.inline(token.text, token.tokens);
|
|
435
|
+
return token;
|
|
420
436
|
}
|
|
421
437
|
}
|
|
422
438
|
|
|
423
439
|
text(src) {
|
|
424
440
|
const cap = this.rules.block.text.exec(src);
|
|
425
441
|
if (cap) {
|
|
426
|
-
|
|
442
|
+
const token = {
|
|
427
443
|
type: 'text',
|
|
428
444
|
raw: cap[0],
|
|
429
|
-
text: cap[0]
|
|
445
|
+
text: cap[0],
|
|
446
|
+
tokens: []
|
|
430
447
|
};
|
|
448
|
+
this.lexer.inline(token.text, token.tokens);
|
|
449
|
+
return token;
|
|
431
450
|
}
|
|
432
451
|
}
|
|
433
452
|
|
|
@@ -442,18 +461,18 @@ module.exports = class Tokenizer {
|
|
|
442
461
|
}
|
|
443
462
|
}
|
|
444
463
|
|
|
445
|
-
tag(src
|
|
464
|
+
tag(src) {
|
|
446
465
|
const cap = this.rules.inline.tag.exec(src);
|
|
447
466
|
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;
|
|
467
|
+
if (!this.lexer.state.inLink && /^<a /i.test(cap[0])) {
|
|
468
|
+
this.lexer.state.inLink = true;
|
|
469
|
+
} else if (this.lexer.state.inLink && /^<\/a>/i.test(cap[0])) {
|
|
470
|
+
this.lexer.state.inLink = false;
|
|
452
471
|
}
|
|
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;
|
|
472
|
+
if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
473
|
+
this.lexer.state.inRawBlock = true;
|
|
474
|
+
} else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
|
|
475
|
+
this.lexer.state.inRawBlock = false;
|
|
457
476
|
}
|
|
458
477
|
|
|
459
478
|
return {
|
|
@@ -461,8 +480,8 @@ module.exports = class Tokenizer {
|
|
|
461
480
|
? 'text'
|
|
462
481
|
: 'html',
|
|
463
482
|
raw: cap[0],
|
|
464
|
-
inLink,
|
|
465
|
-
inRawBlock,
|
|
483
|
+
inLink: this.lexer.state.inLink,
|
|
484
|
+
inRawBlock: this.lexer.state.inRawBlock,
|
|
466
485
|
text: this.options.sanitize
|
|
467
486
|
? (this.options.sanitizer
|
|
468
487
|
? this.options.sanitizer(cap[0])
|
|
@@ -524,7 +543,7 @@ module.exports = class Tokenizer {
|
|
|
524
543
|
return outputLink(cap, {
|
|
525
544
|
href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
|
|
526
545
|
title: title ? title.replace(this.rules.inline._escapes, '$1') : title
|
|
527
|
-
}, cap[0]);
|
|
546
|
+
}, cap[0], this.lexer);
|
|
528
547
|
}
|
|
529
548
|
}
|
|
530
549
|
|
|
@@ -542,7 +561,7 @@ module.exports = class Tokenizer {
|
|
|
542
561
|
text
|
|
543
562
|
};
|
|
544
563
|
}
|
|
545
|
-
return outputLink(cap, link, cap[0]);
|
|
564
|
+
return outputLink(cap, link, cap[0], this.lexer);
|
|
546
565
|
}
|
|
547
566
|
}
|
|
548
567
|
|
|
@@ -591,18 +610,22 @@ module.exports = class Tokenizer {
|
|
|
591
610
|
|
|
592
611
|
// Create `em` if smallest delimiter has odd char count. *a***
|
|
593
612
|
if (Math.min(lLength, rLength) % 2) {
|
|
613
|
+
const text = src.slice(1, lLength + match.index + rLength);
|
|
594
614
|
return {
|
|
595
615
|
type: 'em',
|
|
596
616
|
raw: src.slice(0, lLength + match.index + rLength + 1),
|
|
597
|
-
text
|
|
617
|
+
text,
|
|
618
|
+
tokens: this.lexer.inlineTokens(text, [])
|
|
598
619
|
};
|
|
599
620
|
}
|
|
600
621
|
|
|
601
622
|
// Create 'strong' if smallest delimiter has even char count. **a***
|
|
623
|
+
const text = src.slice(2, lLength + match.index + rLength - 1);
|
|
602
624
|
return {
|
|
603
625
|
type: 'strong',
|
|
604
626
|
raw: src.slice(0, lLength + match.index + rLength + 1),
|
|
605
|
-
text
|
|
627
|
+
text,
|
|
628
|
+
tokens: this.lexer.inlineTokens(text, [])
|
|
606
629
|
};
|
|
607
630
|
}
|
|
608
631
|
}
|
|
@@ -642,7 +665,8 @@ module.exports = class Tokenizer {
|
|
|
642
665
|
return {
|
|
643
666
|
type: 'del',
|
|
644
667
|
raw: cap[0],
|
|
645
|
-
text: cap[2]
|
|
668
|
+
text: cap[2],
|
|
669
|
+
tokens: this.lexer.inlineTokens(cap[2], [])
|
|
646
670
|
};
|
|
647
671
|
}
|
|
648
672
|
}
|
|
@@ -712,11 +736,11 @@ module.exports = class Tokenizer {
|
|
|
712
736
|
}
|
|
713
737
|
}
|
|
714
738
|
|
|
715
|
-
inlineText(src,
|
|
739
|
+
inlineText(src, smartypants) {
|
|
716
740
|
const cap = this.rules.inline.text.exec(src);
|
|
717
741
|
if (cap) {
|
|
718
742
|
let text;
|
|
719
|
-
if (inRawBlock) {
|
|
743
|
+
if (this.lexer.state.inRawBlock) {
|
|
720
744
|
text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0];
|
|
721
745
|
} else {
|
|
722
746
|
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
|
@@ -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;
|