marked 1.0.0 → 1.1.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 +168 -61
- package/lib/marked.js +233 -83
- package/marked.min.js +1 -1
- package/package.json +10 -9
- package/src/Lexer.js +16 -4
- package/src/Parser.js +1 -1
- package/src/Renderer.js +1 -1
- package/src/Tokenizer.js +62 -15
- package/src/defaults.js +1 -0
- package/src/marked.js +85 -39
- package/src/rules.js +2 -1
package/package.json
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
"name": "marked",
|
|
3
3
|
"description": "A markdown parser built for speed",
|
|
4
4
|
"author": "Christopher Jeffrey",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.1.0",
|
|
6
6
|
"main": "./src/marked.js",
|
|
7
|
+
"browser": "./lib/marked.js",
|
|
7
8
|
"bin": "./bin/marked",
|
|
8
9
|
"man": "./man/marked.1",
|
|
9
10
|
"files": [
|
|
@@ -30,27 +31,27 @@
|
|
|
30
31
|
"html"
|
|
31
32
|
],
|
|
32
33
|
"devDependencies": {
|
|
33
|
-
"@babel/core": "^7.9.
|
|
34
|
-
"@babel/preset-env": "^7.9.
|
|
35
|
-
"@markedjs/html-differ": "^3.0.
|
|
34
|
+
"@babel/core": "^7.9.6",
|
|
35
|
+
"@babel/preset-env": "^7.9.6",
|
|
36
|
+
"@markedjs/html-differ": "^3.0.2",
|
|
36
37
|
"cheerio": "^1.0.0-rc.3",
|
|
37
38
|
"commonmark": "0.29.x",
|
|
38
|
-
"eslint": "^
|
|
39
|
+
"eslint": "^7.0.0",
|
|
39
40
|
"eslint-config-standard": "^14.1.1",
|
|
40
41
|
"eslint-plugin-import": "^2.20.2",
|
|
41
42
|
"eslint-plugin-node": "^11.1.0",
|
|
42
43
|
"eslint-plugin-promise": "^4.2.1",
|
|
43
44
|
"eslint-plugin-standard": "^4.0.1",
|
|
44
|
-
"front-matter": "^3.1
|
|
45
|
+
"front-matter": "^3.2.1",
|
|
45
46
|
"jasmine": "^3.5.0",
|
|
46
47
|
"markdown": "0.5.x",
|
|
47
48
|
"markdown-it": "10.x",
|
|
48
49
|
"node-fetch": "^2.6.0",
|
|
49
|
-
"rollup": "^2.
|
|
50
|
+
"rollup": "^2.10.2",
|
|
50
51
|
"rollup-plugin-babel": "^4.4.0",
|
|
51
52
|
"rollup-plugin-commonjs": "^10.1.0",
|
|
52
|
-
"rollup-plugin-license": "^2.0.
|
|
53
|
-
"uglify-js": "^3.9.
|
|
53
|
+
"rollup-plugin-license": "^2.0.1",
|
|
54
|
+
"uglify-js": "^3.9.3",
|
|
54
55
|
"vuln-regex-detector": "^1.3.0"
|
|
55
56
|
},
|
|
56
57
|
"scripts": {
|
package/src/Lexer.js
CHANGED
|
@@ -112,7 +112,7 @@ module.exports = class Lexer {
|
|
|
112
112
|
*/
|
|
113
113
|
blockTokens(src, tokens = [], top = true) {
|
|
114
114
|
src = src.replace(/^ +$/gm, '');
|
|
115
|
-
let token, i, l;
|
|
115
|
+
let token, i, l, lastToken;
|
|
116
116
|
|
|
117
117
|
while (src) {
|
|
118
118
|
// newline
|
|
@@ -127,7 +127,13 @@ module.exports = class Lexer {
|
|
|
127
127
|
// code
|
|
128
128
|
if (token = this.tokenizer.code(src, tokens)) {
|
|
129
129
|
src = src.substring(token.raw.length);
|
|
130
|
-
|
|
130
|
+
if (token.type) {
|
|
131
|
+
tokens.push(token);
|
|
132
|
+
} else {
|
|
133
|
+
lastToken = tokens[tokens.length - 1];
|
|
134
|
+
lastToken.raw += '\n' + token.raw;
|
|
135
|
+
lastToken.text += '\n' + token.text;
|
|
136
|
+
}
|
|
131
137
|
continue;
|
|
132
138
|
}
|
|
133
139
|
|
|
@@ -219,9 +225,15 @@ module.exports = class Lexer {
|
|
|
219
225
|
}
|
|
220
226
|
|
|
221
227
|
// text
|
|
222
|
-
if (token = this.tokenizer.text(src)) {
|
|
228
|
+
if (token = this.tokenizer.text(src, tokens)) {
|
|
223
229
|
src = src.substring(token.raw.length);
|
|
224
|
-
|
|
230
|
+
if (token.type) {
|
|
231
|
+
tokens.push(token);
|
|
232
|
+
} else {
|
|
233
|
+
lastToken = tokens[tokens.length - 1];
|
|
234
|
+
lastToken.raw += '\n' + token.raw;
|
|
235
|
+
lastToken.text += '\n' + token.text;
|
|
236
|
+
}
|
|
225
237
|
continue;
|
|
226
238
|
}
|
|
227
239
|
|
package/src/Parser.js
CHANGED
|
@@ -130,7 +130,7 @@ module.exports = class Parser {
|
|
|
130
130
|
if (item.task) {
|
|
131
131
|
checkbox = this.renderer.checkbox(checked);
|
|
132
132
|
if (loose) {
|
|
133
|
-
if (item.tokens[0].type === 'text') {
|
|
133
|
+
if (item.tokens.length > 0 && item.tokens[0].type === 'text') {
|
|
134
134
|
item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
|
|
135
135
|
if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
|
|
136
136
|
item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
|
package/src/Renderer.js
CHANGED
package/src/Tokenizer.js
CHANGED
|
@@ -29,6 +29,34 @@ function outputLink(cap, link, raw) {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function indentCodeCompensation(raw, text) {
|
|
33
|
+
const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
|
|
34
|
+
|
|
35
|
+
if (matchIndentToCode === null) {
|
|
36
|
+
return text;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const indentToCode = matchIndentToCode[1];
|
|
40
|
+
|
|
41
|
+
return text
|
|
42
|
+
.split('\n')
|
|
43
|
+
.map(node => {
|
|
44
|
+
const matchIndentInNode = node.match(/^\s+/);
|
|
45
|
+
if (matchIndentInNode === null) {
|
|
46
|
+
return node;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const [indentInNode] = matchIndentInNode;
|
|
50
|
+
|
|
51
|
+
if (indentInNode.length >= indentToCode.length) {
|
|
52
|
+
return node.slice(indentToCode.length);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return node;
|
|
56
|
+
})
|
|
57
|
+
.join('\n');
|
|
58
|
+
}
|
|
59
|
+
|
|
32
60
|
/**
|
|
33
61
|
* Tokenizer
|
|
34
62
|
*/
|
|
@@ -56,32 +84,35 @@ module.exports = class Tokenizer {
|
|
|
56
84
|
const lastToken = tokens[tokens.length - 1];
|
|
57
85
|
// An indented code block cannot interrupt a paragraph.
|
|
58
86
|
if (lastToken && lastToken.type === 'paragraph') {
|
|
59
|
-
tokens.pop();
|
|
60
|
-
lastToken.text += '\n' + cap[0].trimRight();
|
|
61
|
-
lastToken.raw += '\n' + cap[0];
|
|
62
|
-
return lastToken;
|
|
63
|
-
} else {
|
|
64
|
-
const text = cap[0].replace(/^ {4}/gm, '');
|
|
65
87
|
return {
|
|
66
|
-
type: 'code',
|
|
67
88
|
raw: cap[0],
|
|
68
|
-
|
|
69
|
-
text: !this.options.pedantic
|
|
70
|
-
? rtrim(text, '\n')
|
|
71
|
-
: text
|
|
89
|
+
text: cap[0].trimRight()
|
|
72
90
|
};
|
|
73
91
|
}
|
|
92
|
+
|
|
93
|
+
const text = cap[0].replace(/^ {4}/gm, '');
|
|
94
|
+
return {
|
|
95
|
+
type: 'code',
|
|
96
|
+
raw: cap[0],
|
|
97
|
+
codeBlockStyle: 'indented',
|
|
98
|
+
text: !this.options.pedantic
|
|
99
|
+
? rtrim(text, '\n')
|
|
100
|
+
: text
|
|
101
|
+
};
|
|
74
102
|
}
|
|
75
103
|
}
|
|
76
104
|
|
|
77
105
|
fences(src) {
|
|
78
106
|
const cap = this.rules.block.fences.exec(src);
|
|
79
107
|
if (cap) {
|
|
108
|
+
const raw = cap[0];
|
|
109
|
+
const text = indentCodeCompensation(raw, cap[3] || '');
|
|
110
|
+
|
|
80
111
|
return {
|
|
81
112
|
type: 'code',
|
|
82
|
-
raw
|
|
113
|
+
raw,
|
|
83
114
|
lang: cap[2] ? cap[2].trim() : cap[2],
|
|
84
|
-
text
|
|
115
|
+
text
|
|
85
116
|
};
|
|
86
117
|
}
|
|
87
118
|
}
|
|
@@ -238,6 +269,7 @@ module.exports = class Tokenizer {
|
|
|
238
269
|
}
|
|
239
270
|
|
|
240
271
|
list.items.push({
|
|
272
|
+
type: 'list_item',
|
|
241
273
|
raw,
|
|
242
274
|
task: istask,
|
|
243
275
|
checked: ischecked,
|
|
@@ -343,9 +375,17 @@ module.exports = class Tokenizer {
|
|
|
343
375
|
}
|
|
344
376
|
}
|
|
345
377
|
|
|
346
|
-
text(src) {
|
|
378
|
+
text(src, tokens) {
|
|
347
379
|
const cap = this.rules.block.text.exec(src);
|
|
348
380
|
if (cap) {
|
|
381
|
+
const lastToken = tokens[tokens.length - 1];
|
|
382
|
+
if (lastToken && lastToken.type === 'text') {
|
|
383
|
+
return {
|
|
384
|
+
raw: cap[0],
|
|
385
|
+
text: cap[0]
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
349
389
|
return {
|
|
350
390
|
type: 'text',
|
|
351
391
|
raw: cap[0],
|
|
@@ -473,10 +513,17 @@ module.exports = class Tokenizer {
|
|
|
473
513
|
codespan(src) {
|
|
474
514
|
const cap = this.rules.inline.code.exec(src);
|
|
475
515
|
if (cap) {
|
|
516
|
+
let text = cap[2].replace(/\n/g, ' ');
|
|
517
|
+
const hasNonSpaceChars = /[^ ]/.test(text);
|
|
518
|
+
const hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');
|
|
519
|
+
if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
|
|
520
|
+
text = text.substring(1, text.length - 1);
|
|
521
|
+
}
|
|
522
|
+
text = escape(text, true);
|
|
476
523
|
return {
|
|
477
524
|
type: 'codespan',
|
|
478
525
|
raw: cap[0],
|
|
479
|
-
text
|
|
526
|
+
text
|
|
480
527
|
};
|
|
481
528
|
}
|
|
482
529
|
}
|
package/src/defaults.js
CHANGED
package/src/marked.js
CHANGED
|
@@ -28,18 +28,17 @@ function marked(src, opt, callback) {
|
|
|
28
28
|
+ Object.prototype.toString.call(src) + ', string expected');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
31
|
+
if (typeof opt === 'function') {
|
|
32
|
+
callback = opt;
|
|
33
|
+
opt = null;
|
|
34
|
+
}
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
opt = merge({}, marked.defaults, opt || {});
|
|
37
|
+
checkSanitizeDeprecation(opt);
|
|
38
|
+
|
|
39
|
+
if (callback) {
|
|
39
40
|
const highlight = opt.highlight;
|
|
40
|
-
let tokens
|
|
41
|
-
pending,
|
|
42
|
-
i = 0;
|
|
41
|
+
let tokens;
|
|
43
42
|
|
|
44
43
|
try {
|
|
45
44
|
tokens = Lexer.lex(src, opt);
|
|
@@ -47,20 +46,15 @@ function marked(src, opt, callback) {
|
|
|
47
46
|
return callback(e);
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
pending = tokens.length;
|
|
51
|
-
|
|
52
49
|
const done = function(err) {
|
|
53
|
-
if (err) {
|
|
54
|
-
opt.highlight = highlight;
|
|
55
|
-
return callback(err);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
50
|
let out;
|
|
59
51
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
52
|
+
if (!err) {
|
|
53
|
+
try {
|
|
54
|
+
out = Parser.parse(tokens, opt);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
err = e;
|
|
57
|
+
}
|
|
64
58
|
}
|
|
65
59
|
|
|
66
60
|
opt.highlight = highlight;
|
|
@@ -76,34 +70,45 @@ function marked(src, opt, callback) {
|
|
|
76
70
|
|
|
77
71
|
delete opt.highlight;
|
|
78
72
|
|
|
79
|
-
if (!
|
|
73
|
+
if (!tokens.length) return done();
|
|
80
74
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
75
|
+
let pending = 0;
|
|
76
|
+
marked.walkTokens(tokens, function(token) {
|
|
77
|
+
if (token.type === 'code') {
|
|
78
|
+
pending++;
|
|
79
|
+
highlight(token.text, token.lang, function(err, code) {
|
|
80
|
+
if (err) {
|
|
81
|
+
return done(err);
|
|
82
|
+
}
|
|
83
|
+
if (code != null && code !== token.text) {
|
|
84
|
+
token.text = code;
|
|
85
|
+
token.escaped = true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pending--;
|
|
89
|
+
if (pending === 0) {
|
|
90
|
+
done();
|
|
90
91
|
}
|
|
91
|
-
token.text = code;
|
|
92
|
-
token.escaped = true;
|
|
93
|
-
--pending || done();
|
|
94
92
|
});
|
|
95
|
-
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (pending === 0) {
|
|
97
|
+
done();
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
return;
|
|
99
101
|
}
|
|
102
|
+
|
|
100
103
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
const tokens = Lexer.lex(src, opt);
|
|
105
|
+
if (opt.walkTokens) {
|
|
106
|
+
marked.walkTokens(tokens, opt.walkTokens);
|
|
107
|
+
}
|
|
108
|
+
return Parser.parse(tokens, opt);
|
|
104
109
|
} catch (e) {
|
|
105
110
|
e.message += '\nPlease report this to https://github.com/markedjs/marked.';
|
|
106
|
-
if (
|
|
111
|
+
if (opt.silent) {
|
|
107
112
|
return '<p>An error occurred:</p><pre>'
|
|
108
113
|
+ escape(e.message + '', true)
|
|
109
114
|
+ '</pre>';
|
|
@@ -161,9 +166,50 @@ marked.use = function(extension) {
|
|
|
161
166
|
}
|
|
162
167
|
opts.tokenizer = tokenizer;
|
|
163
168
|
}
|
|
169
|
+
if (extension.walkTokens) {
|
|
170
|
+
const walkTokens = marked.defaults.walkTokens;
|
|
171
|
+
opts.walkTokens = (token) => {
|
|
172
|
+
extension.walkTokens(token);
|
|
173
|
+
if (walkTokens) {
|
|
174
|
+
walkTokens(token);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
164
178
|
marked.setOptions(opts);
|
|
165
179
|
};
|
|
166
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Run callback for every token
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
marked.walkTokens = function(tokens, callback) {
|
|
186
|
+
for (const token of tokens) {
|
|
187
|
+
callback(token);
|
|
188
|
+
switch (token.type) {
|
|
189
|
+
case 'table': {
|
|
190
|
+
for (const cell of token.tokens.header) {
|
|
191
|
+
marked.walkTokens(cell, callback);
|
|
192
|
+
}
|
|
193
|
+
for (const row of token.tokens.cells) {
|
|
194
|
+
for (const cell of row) {
|
|
195
|
+
marked.walkTokens(cell, callback);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
case 'list': {
|
|
201
|
+
marked.walkTokens(token.items, callback);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
default: {
|
|
205
|
+
if (token.tokens) {
|
|
206
|
+
marked.walkTokens(token.tokens, callback);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
167
213
|
/**
|
|
168
214
|
* Expose
|
|
169
215
|
*/
|
package/src/rules.js
CHANGED
|
@@ -169,7 +169,7 @@ const inline = {
|
|
|
169
169
|
reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
|
|
170
170
|
nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
|
|
171
171
|
strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
|
|
172
|
-
em: /^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\
|
|
172
|
+
em: /^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\s,punctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\s,punctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/,
|
|
173
173
|
code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
|
|
174
174
|
br: /^( {2,}|\\)\n(?!\s*$)/,
|
|
175
175
|
del: noopTest,
|
|
@@ -178,6 +178,7 @@ const inline = {
|
|
|
178
178
|
|
|
179
179
|
// list of punctuation marks from common mark spec
|
|
180
180
|
// without ` and ] to workaround Rule 17 (inline code blocks/links)
|
|
181
|
+
// without , to work around example 393
|
|
181
182
|
inline._punctuation = '!"#$%&\'()*+\\-./:;<=>?@\\[^_{|}~';
|
|
182
183
|
inline.em = edit(inline.em).replace(/punctuation/g, inline._punctuation).getRegex();
|
|
183
184
|
|