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