UNPKG

6.03 kBJavaScriptView Raw
1const Lexer = require('./Lexer.js');
2const Parser = require('./Parser.js');
3const Tokenizer = require('./Tokenizer.js');
4const Renderer = require('./Renderer.js');
5const TextRenderer = require('./TextRenderer.js');
6const Slugger = require('./Slugger.js');
7const {
8 merge,
9 checkSanitizeDeprecation,
10 escape
11} = require('./helpers.js');
12const {
13 getDefaults,
14 changeDefaults,
15 defaults
16} = require('./defaults.js');
17
18/**
19 * Marked
20 */
21function marked(src, opt, callback) {
22 // throw error in case of non string input
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 out = Parser.parse(tokens, opt);
55 } catch (e) {
56 err = e;
57 }
58 }
59
60 opt.highlight = highlight;
61
62 return err
63 ? callback(err)
64 : callback(null, out);
65 };
66
67 if (!highlight || highlight.length < 3) {
68 return done();
69 }
70
71 delete opt.highlight;
72
73 if (!tokens.length) return done();
74
75 let pending = 0;
76 marked.walkTokens(tokens, function(token) {
77 if (token.type === 'code') {
78 pending++;
79 setTimeout(() => {
80 highlight(token.text, token.lang, function(err, code) {
81 if (err) {
82 return done(err);
83 }
84 if (code != null && code !== token.text) {
85 token.text = code;
86 token.escaped = true;
87 }
88
89 pending--;
90 if (pending === 0) {
91 done();
92 }
93 });
94 }, 0);
95 }
96 });
97
98 if (pending === 0) {
99 done();
100 }
101
102 return;
103 }
104
105 try {
106 const tokens = Lexer.lex(src, opt);
107 if (opt.walkTokens) {
108 marked.walkTokens(tokens, opt.walkTokens);
109 }
110 return Parser.parse(tokens, opt);
111 } catch (e) {
112 e.message += '\nPlease report this to https://github.com/markedjs/marked.';
113 if (opt.silent) {
114 return '<p>An error occurred:</p><pre>'
115 + escape(e.message + '', true)
116 + '</pre>';
117 }
118 throw e;
119 }
120}
121
122/**
123 * Options
124 */
125
126marked.options =
127marked.setOptions = function(opt) {
128 merge(marked.defaults, opt);
129 changeDefaults(marked.defaults);
130 return marked;
131};
132
133marked.getDefaults = getDefaults;
134
135marked.defaults = defaults;
136
137/**
138 * Use Extension
139 */
140
141marked.use = function(extension) {
142 const opts = merge({}, extension);
143 if (extension.renderer) {
144 const renderer = marked.defaults.renderer || new Renderer();
145 for (const prop in extension.renderer) {
146 const prevRenderer = renderer[prop];
147 renderer[prop] = (...args) => {
148 let ret = extension.renderer[prop].apply(renderer, args);
149 if (ret === false) {
150 ret = prevRenderer.apply(renderer, args);
151 }
152 return ret;
153 };
154 }
155 opts.renderer = renderer;
156 }
157 if (extension.tokenizer) {
158 const tokenizer = marked.defaults.tokenizer || new Tokenizer();
159 for (const prop in extension.tokenizer) {
160 const prevTokenizer = tokenizer[prop];
161 tokenizer[prop] = (...args) => {
162 let ret = extension.tokenizer[prop].apply(tokenizer, args);
163 if (ret === false) {
164 ret = prevTokenizer.apply(tokenizer, args);
165 }
166 return ret;
167 };
168 }
169 opts.tokenizer = tokenizer;
170 }
171 if (extension.walkTokens) {
172 const walkTokens = marked.defaults.walkTokens;
173 opts.walkTokens = (token) => {
174 extension.walkTokens(token);
175 if (walkTokens) {
176 walkTokens(token);
177 }
178 };
179 }
180 marked.setOptions(opts);
181};
182
183/**
184 * Run callback for every token
185 */
186
187marked.walkTokens = function(tokens, callback) {
188 for (const token of tokens) {
189 callback(token);
190 switch (token.type) {
191 case 'table': {
192 for (const cell of token.tokens.header) {
193 marked.walkTokens(cell, callback);
194 }
195 for (const row of token.tokens.cells) {
196 for (const cell of row) {
197 marked.walkTokens(cell, callback);
198 }
199 }
200 break;
201 }
202 case 'list': {
203 marked.walkTokens(token.items, callback);
204 break;
205 }
206 default: {
207 if (token.tokens) {
208 marked.walkTokens(token.tokens, callback);
209 }
210 }
211 }
212 }
213};
214
215/**
216 * Parse Inline
217 */
218marked.parseInline = function(src, opt) {
219 // throw error in case of non string input
220 if (typeof src === 'undefined' || src === null) {
221 throw new Error('marked.parseInline(): input parameter is undefined or null');
222 }
223 if (typeof src !== 'string') {
224 throw new Error('marked.parseInline(): input parameter is of type '
225 + Object.prototype.toString.call(src) + ', string expected');
226 }
227
228 opt = merge({}, marked.defaults, opt || {});
229 checkSanitizeDeprecation(opt);
230
231 try {
232 const tokens = Lexer.lexInline(src, opt);
233 if (opt.walkTokens) {
234 marked.walkTokens(tokens, opt.walkTokens);
235 }
236 return Parser.parseInline(tokens, opt);
237 } catch (e) {
238 e.message += '\nPlease report this to https://github.com/markedjs/marked.';
239 if (opt.silent) {
240 return '<p>An error occurred:</p><pre>'
241 + escape(e.message + '', true)
242 + '</pre>';
243 }
244 throw e;
245 }
246};
247
248/**
249 * Expose
250 */
251
252marked.Parser = Parser;
253marked.parser = Parser.parse;
254
255marked.Renderer = Renderer;
256marked.TextRenderer = TextRenderer;
257
258marked.Lexer = Lexer;
259marked.lexer = Lexer.lex;
260
261marked.Tokenizer = Tokenizer;
262
263marked.Slugger = Slugger;
264
265marked.parse = marked;
266
267module.exports = marked;