marked 5.0.5 → 5.1.1
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.cjs +317 -259
- package/lib/marked.esm.js +360 -316
- package/lib/marked.umd.js +317 -259
- package/marked.min.js +2 -2
- package/package.json +12 -12
- package/src/Instance.js +374 -0
- package/src/Lexer.js +2 -2
- package/src/Tokenizer.js +1 -1
- package/src/marked.js +13 -338
- package/src/rules.js +18 -17
package/src/Instance.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { getDefaults } from './defaults.js';
|
|
2
|
+
import { Lexer } from './Lexer.js';
|
|
3
|
+
import { Parser } from './Parser.js';
|
|
4
|
+
import { Hooks } from './Hooks.js';
|
|
5
|
+
import { Renderer } from './Renderer.js';
|
|
6
|
+
import { Tokenizer } from './Tokenizer.js';
|
|
7
|
+
import { TextRenderer } from './TextRenderer.js';
|
|
8
|
+
import { Slugger } from './Slugger.js';
|
|
9
|
+
import {
|
|
10
|
+
checkDeprecations,
|
|
11
|
+
escape
|
|
12
|
+
} from './helpers.js';
|
|
13
|
+
|
|
14
|
+
export class Marked {
|
|
15
|
+
defaults = getDefaults();
|
|
16
|
+
options = this.setOptions;
|
|
17
|
+
|
|
18
|
+
parse = this.#parseMarkdown(Lexer.lex, Parser.parse);
|
|
19
|
+
parseInline = this.#parseMarkdown(Lexer.lexInline, Parser.parseInline);
|
|
20
|
+
|
|
21
|
+
Parser = Parser;
|
|
22
|
+
parser = Parser.parse;
|
|
23
|
+
Renderer = Renderer;
|
|
24
|
+
TextRenderer = TextRenderer;
|
|
25
|
+
Lexer = Lexer;
|
|
26
|
+
lexer = Lexer.lex;
|
|
27
|
+
Tokenizer = Tokenizer;
|
|
28
|
+
Slugger = Slugger;
|
|
29
|
+
Hooks = Hooks;
|
|
30
|
+
|
|
31
|
+
constructor(...args) {
|
|
32
|
+
this.use(...args);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
walkTokens(tokens, callback) {
|
|
36
|
+
let values = [];
|
|
37
|
+
for (const token of tokens) {
|
|
38
|
+
values = values.concat(callback.call(this, token));
|
|
39
|
+
switch (token.type) {
|
|
40
|
+
case 'table': {
|
|
41
|
+
for (const cell of token.header) {
|
|
42
|
+
values = values.concat(this.walkTokens(cell.tokens, callback));
|
|
43
|
+
}
|
|
44
|
+
for (const row of token.rows) {
|
|
45
|
+
for (const cell of row) {
|
|
46
|
+
values = values.concat(this.walkTokens(cell.tokens, callback));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
case 'list': {
|
|
52
|
+
values = values.concat(this.walkTokens(token.items, callback));
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
default: {
|
|
56
|
+
if (this.defaults.extensions && this.defaults.extensions.childTokens && this.defaults.extensions.childTokens[token.type]) { // Walk any extensions
|
|
57
|
+
this.defaults.extensions.childTokens[token.type].forEach((childTokens) => {
|
|
58
|
+
values = values.concat(this.walkTokens(token[childTokens], callback));
|
|
59
|
+
});
|
|
60
|
+
} else if (token.tokens) {
|
|
61
|
+
values = values.concat(this.walkTokens(token.tokens, callback));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return values;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
use(...args) {
|
|
70
|
+
const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };
|
|
71
|
+
|
|
72
|
+
args.forEach((pack) => {
|
|
73
|
+
// copy options to new object
|
|
74
|
+
const opts = { ...pack };
|
|
75
|
+
|
|
76
|
+
// set async to true if it was set to true before
|
|
77
|
+
opts.async = this.defaults.async || opts.async || false;
|
|
78
|
+
|
|
79
|
+
// ==-- Parse "addon" extensions --== //
|
|
80
|
+
if (pack.extensions) {
|
|
81
|
+
pack.extensions.forEach((ext) => {
|
|
82
|
+
if (!ext.name) {
|
|
83
|
+
throw new Error('extension name required');
|
|
84
|
+
}
|
|
85
|
+
if (ext.renderer) { // Renderer extensions
|
|
86
|
+
const prevRenderer = extensions.renderers[ext.name];
|
|
87
|
+
if (prevRenderer) {
|
|
88
|
+
// Replace extension with func to run new extension but fall back if false
|
|
89
|
+
extensions.renderers[ext.name] = function(...args) {
|
|
90
|
+
let ret = ext.renderer.apply(this, args);
|
|
91
|
+
if (ret === false) {
|
|
92
|
+
ret = prevRenderer.apply(this, args);
|
|
93
|
+
}
|
|
94
|
+
return ret;
|
|
95
|
+
};
|
|
96
|
+
} else {
|
|
97
|
+
extensions.renderers[ext.name] = ext.renderer;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (ext.tokenizer) { // Tokenizer Extensions
|
|
101
|
+
if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
|
|
102
|
+
throw new Error("extension level must be 'block' or 'inline'");
|
|
103
|
+
}
|
|
104
|
+
if (extensions[ext.level]) {
|
|
105
|
+
extensions[ext.level].unshift(ext.tokenizer);
|
|
106
|
+
} else {
|
|
107
|
+
extensions[ext.level] = [ext.tokenizer];
|
|
108
|
+
}
|
|
109
|
+
if (ext.start) { // Function to check for start of token
|
|
110
|
+
if (ext.level === 'block') {
|
|
111
|
+
if (extensions.startBlock) {
|
|
112
|
+
extensions.startBlock.push(ext.start);
|
|
113
|
+
} else {
|
|
114
|
+
extensions.startBlock = [ext.start];
|
|
115
|
+
}
|
|
116
|
+
} else if (ext.level === 'inline') {
|
|
117
|
+
if (extensions.startInline) {
|
|
118
|
+
extensions.startInline.push(ext.start);
|
|
119
|
+
} else {
|
|
120
|
+
extensions.startInline = [ext.start];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (ext.childTokens) { // Child tokens to be visited by walkTokens
|
|
126
|
+
extensions.childTokens[ext.name] = ext.childTokens;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
opts.extensions = extensions;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ==-- Parse "overwrite" extensions --== //
|
|
133
|
+
if (pack.renderer) {
|
|
134
|
+
const renderer = this.defaults.renderer || new Renderer(this.defaults);
|
|
135
|
+
for (const prop in pack.renderer) {
|
|
136
|
+
const prevRenderer = renderer[prop];
|
|
137
|
+
// Replace renderer with func to run extension, but fall back if false
|
|
138
|
+
renderer[prop] = (...args) => {
|
|
139
|
+
let ret = pack.renderer[prop].apply(renderer, args);
|
|
140
|
+
if (ret === false) {
|
|
141
|
+
ret = prevRenderer.apply(renderer, args);
|
|
142
|
+
}
|
|
143
|
+
return ret;
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
opts.renderer = renderer;
|
|
147
|
+
}
|
|
148
|
+
if (pack.tokenizer) {
|
|
149
|
+
const tokenizer = this.defaults.tokenizer || new Tokenizer(this.defaults);
|
|
150
|
+
for (const prop in pack.tokenizer) {
|
|
151
|
+
const prevTokenizer = tokenizer[prop];
|
|
152
|
+
// Replace tokenizer with func to run extension, but fall back if false
|
|
153
|
+
tokenizer[prop] = (...args) => {
|
|
154
|
+
let ret = pack.tokenizer[prop].apply(tokenizer, args);
|
|
155
|
+
if (ret === false) {
|
|
156
|
+
ret = prevTokenizer.apply(tokenizer, args);
|
|
157
|
+
}
|
|
158
|
+
return ret;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
opts.tokenizer = tokenizer;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ==-- Parse Hooks extensions --== //
|
|
165
|
+
if (pack.hooks) {
|
|
166
|
+
const hooks = this.defaults.hooks || new Hooks();
|
|
167
|
+
for (const prop in pack.hooks) {
|
|
168
|
+
const prevHook = hooks[prop];
|
|
169
|
+
if (Hooks.passThroughHooks.has(prop)) {
|
|
170
|
+
hooks[prop] = (arg) => {
|
|
171
|
+
if (this.defaults.async) {
|
|
172
|
+
return Promise.resolve(pack.hooks[prop].call(hooks, arg)).then(ret => {
|
|
173
|
+
return prevHook.call(hooks, ret);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const ret = pack.hooks[prop].call(hooks, arg);
|
|
178
|
+
return prevHook.call(hooks, ret);
|
|
179
|
+
};
|
|
180
|
+
} else {
|
|
181
|
+
hooks[prop] = (...args) => {
|
|
182
|
+
let ret = pack.hooks[prop].apply(hooks, args);
|
|
183
|
+
if (ret === false) {
|
|
184
|
+
ret = prevHook.apply(hooks, args);
|
|
185
|
+
}
|
|
186
|
+
return ret;
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
opts.hooks = hooks;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ==-- Parse WalkTokens extensions --== //
|
|
194
|
+
if (pack.walkTokens) {
|
|
195
|
+
const walkTokens = this.defaults.walkTokens;
|
|
196
|
+
opts.walkTokens = function(token) {
|
|
197
|
+
let values = [];
|
|
198
|
+
values.push(pack.walkTokens.call(this, token));
|
|
199
|
+
if (walkTokens) {
|
|
200
|
+
values = values.concat(walkTokens.call(this, token));
|
|
201
|
+
}
|
|
202
|
+
return values;
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
this.defaults = { ...this.defaults, ...opts };
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
setOptions(opt) {
|
|
213
|
+
this.defaults = { ...this.defaults, ...opt };
|
|
214
|
+
return this;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
#parseMarkdown(lexer, parser) {
|
|
218
|
+
return (src, opt, callback) => {
|
|
219
|
+
if (typeof opt === 'function') {
|
|
220
|
+
callback = opt;
|
|
221
|
+
opt = null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const origOpt = { ...opt };
|
|
225
|
+
opt = { ...this.defaults, ...origOpt };
|
|
226
|
+
const throwError = this.#onError(opt.silent, opt.async, callback);
|
|
227
|
+
|
|
228
|
+
// throw error in case of non string input
|
|
229
|
+
if (typeof src === 'undefined' || src === null) {
|
|
230
|
+
return throwError(new Error('marked(): input parameter is undefined or null'));
|
|
231
|
+
}
|
|
232
|
+
if (typeof src !== 'string') {
|
|
233
|
+
return throwError(new Error('marked(): input parameter is of type '
|
|
234
|
+
+ Object.prototype.toString.call(src) + ', string expected'));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
checkDeprecations(opt, callback);
|
|
238
|
+
|
|
239
|
+
if (opt.hooks) {
|
|
240
|
+
opt.hooks.options = opt;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (callback) {
|
|
244
|
+
const highlight = opt.highlight;
|
|
245
|
+
let tokens;
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
if (opt.hooks) {
|
|
249
|
+
src = opt.hooks.preprocess(src);
|
|
250
|
+
}
|
|
251
|
+
tokens = lexer(src, opt);
|
|
252
|
+
} catch (e) {
|
|
253
|
+
return throwError(e);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const done = (err) => {
|
|
257
|
+
let out;
|
|
258
|
+
|
|
259
|
+
if (!err) {
|
|
260
|
+
try {
|
|
261
|
+
if (opt.walkTokens) {
|
|
262
|
+
this.walkTokens(tokens, opt.walkTokens);
|
|
263
|
+
}
|
|
264
|
+
out = parser(tokens, opt);
|
|
265
|
+
if (opt.hooks) {
|
|
266
|
+
out = opt.hooks.postprocess(out);
|
|
267
|
+
}
|
|
268
|
+
} catch (e) {
|
|
269
|
+
err = e;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
opt.highlight = highlight;
|
|
274
|
+
|
|
275
|
+
return err
|
|
276
|
+
? throwError(err)
|
|
277
|
+
: callback(null, out);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
if (!highlight || highlight.length < 3) {
|
|
281
|
+
return done();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
delete opt.highlight;
|
|
285
|
+
|
|
286
|
+
if (!tokens.length) return done();
|
|
287
|
+
|
|
288
|
+
let pending = 0;
|
|
289
|
+
this.walkTokens(tokens, (token) => {
|
|
290
|
+
if (token.type === 'code') {
|
|
291
|
+
pending++;
|
|
292
|
+
setTimeout(() => {
|
|
293
|
+
highlight(token.text, token.lang, (err, code) => {
|
|
294
|
+
if (err) {
|
|
295
|
+
return done(err);
|
|
296
|
+
}
|
|
297
|
+
if (code != null && code !== token.text) {
|
|
298
|
+
token.text = code;
|
|
299
|
+
token.escaped = true;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
pending--;
|
|
303
|
+
if (pending === 0) {
|
|
304
|
+
done();
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}, 0);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
if (pending === 0) {
|
|
312
|
+
done();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (opt.async) {
|
|
319
|
+
return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)
|
|
320
|
+
.then(src => lexer(src, opt))
|
|
321
|
+
.then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)
|
|
322
|
+
.then(tokens => parser(tokens, opt))
|
|
323
|
+
.then(html => opt.hooks ? opt.hooks.postprocess(html) : html)
|
|
324
|
+
.catch(throwError);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
try {
|
|
328
|
+
if (opt.hooks) {
|
|
329
|
+
src = opt.hooks.preprocess(src);
|
|
330
|
+
}
|
|
331
|
+
const tokens = lexer(src, opt);
|
|
332
|
+
if (opt.walkTokens) {
|
|
333
|
+
this.walkTokens(tokens, opt.walkTokens);
|
|
334
|
+
}
|
|
335
|
+
let html = parser(tokens, opt);
|
|
336
|
+
if (opt.hooks) {
|
|
337
|
+
html = opt.hooks.postprocess(html);
|
|
338
|
+
}
|
|
339
|
+
return html;
|
|
340
|
+
} catch (e) {
|
|
341
|
+
return throwError(e);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
#onError(silent, async, callback) {
|
|
347
|
+
return (e) => {
|
|
348
|
+
e.message += '\nPlease report this to https://github.com/markedjs/marked.';
|
|
349
|
+
|
|
350
|
+
if (silent) {
|
|
351
|
+
const msg = '<p>An error occurred:</p><pre>'
|
|
352
|
+
+ escape(e.message + '', true)
|
|
353
|
+
+ '</pre>';
|
|
354
|
+
if (async) {
|
|
355
|
+
return Promise.resolve(msg);
|
|
356
|
+
}
|
|
357
|
+
if (callback) {
|
|
358
|
+
callback(null, msg);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
return msg;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (async) {
|
|
365
|
+
return Promise.reject(e);
|
|
366
|
+
}
|
|
367
|
+
if (callback) {
|
|
368
|
+
callback(e);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
throw e;
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
}
|
package/src/Lexer.js
CHANGED
|
@@ -348,8 +348,8 @@ export class Lexer {
|
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
// Mask out escaped characters
|
|
351
|
-
while ((match = this.tokenizer.rules.inline.
|
|
352
|
-
maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.
|
|
351
|
+
while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {
|
|
352
|
+
maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
while (src) {
|
package/src/Tokenizer.js
CHANGED
|
@@ -613,7 +613,7 @@ export class Tokenizer {
|
|
|
613
613
|
|
|
614
614
|
const nextChar = match[1] || match[2] || '';
|
|
615
615
|
|
|
616
|
-
if (!nextChar ||
|
|
616
|
+
if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
|
|
617
617
|
const lLength = match[0].length - 1;
|
|
618
618
|
let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
|
|
619
619
|
|