UNPKG

6.13 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 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 * Options
127 */
128
129marked.options =
130marked.setOptions = function(opt) {
131 merge(marked.defaults, opt);
132 changeDefaults(marked.defaults);
133 return marked;
134};
135
136marked.getDefaults = getDefaults;
137
138marked.defaults = defaults;
139
140/**
141 * Use Extension
142 */
143
144marked.use = function(extension) {
145 const opts = merge({}, extension);
146 if (extension.renderer) {
147 const renderer = marked.defaults.renderer || new Renderer();
148 for (const prop in extension.renderer) {
149 const prevRenderer = renderer[prop];
150 renderer[prop] = (...args) => {
151 let ret = extension.renderer[prop].apply(renderer, args);
152 if (ret === false) {
153 ret = prevRenderer.apply(renderer, args);
154 }
155 return ret;
156 };
157 }
158 opts.renderer = renderer;
159 }
160 if (extension.tokenizer) {
161 const tokenizer = marked.defaults.tokenizer || new Tokenizer();
162 for (const prop in extension.tokenizer) {
163 const prevTokenizer = tokenizer[prop];
164 tokenizer[prop] = (...args) => {
165 let ret = extension.tokenizer[prop].apply(tokenizer, args);
166 if (ret === false) {
167 ret = prevTokenizer.apply(tokenizer, args);
168 }
169 return ret;
170 };
171 }
172 opts.tokenizer = tokenizer;
173 }
174 if (extension.walkTokens) {
175 const walkTokens = marked.defaults.walkTokens;
176 opts.walkTokens = (token) => {
177 extension.walkTokens(token);
178 if (walkTokens) {
179 walkTokens(token);
180 }
181 };
182 }
183 marked.setOptions(opts);
184};
185
186/**
187 * Run callback for every token
188 */
189
190marked.walkTokens = function(tokens, callback) {
191 for (const token of tokens) {
192 callback(token);
193 switch (token.type) {
194 case 'table': {
195 for (const cell of token.tokens.header) {
196 marked.walkTokens(cell, callback);
197 }
198 for (const row of token.tokens.cells) {
199 for (const cell of row) {
200 marked.walkTokens(cell, callback);
201 }
202 }
203 break;
204 }
205 case 'list': {
206 marked.walkTokens(token.items, callback);
207 break;
208 }
209 default: {
210 if (token.tokens) {
211 marked.walkTokens(token.tokens, callback);
212 }
213 }
214 }
215 }
216};
217
218/**
219 * Parse Inline
220 */
221marked.parseInline = function(src, opt) {
222 // throw error in case of non string input
223 if (typeof src === 'undefined' || src === null) {
224 throw new Error('marked.parseInline(): input parameter is undefined or null');
225 }
226 if (typeof src !== 'string') {
227 throw new Error('marked.parseInline(): input parameter is of type '
228 + Object.prototype.toString.call(src) + ', string expected');
229 }
230
231 opt = merge({}, marked.defaults, opt || {});
232 checkSanitizeDeprecation(opt);
233
234 try {
235 const tokens = Lexer.lexInline(src, opt);
236 if (opt.walkTokens) {
237 marked.walkTokens(tokens, opt.walkTokens);
238 }
239 return Parser.parseInline(tokens, opt);
240 } catch (e) {
241 e.message += '\nPlease report this to https://github.com/markedjs/marked.';
242 if (opt.silent) {
243 return '<p>An error occurred:</p><pre>'
244 + escape(e.message + '', true)
245 + '</pre>';
246 }
247 throw e;
248 }
249};
250
251/**
252 * Expose
253 */
254
255marked.Parser = Parser;
256marked.parser = Parser.parse;
257
258marked.Renderer = Renderer;
259marked.TextRenderer = TextRenderer;
260
261marked.Lexer = Lexer;
262marked.lexer = Lexer.lex;
263
264marked.Tokenizer = Tokenizer;
265
266marked.Slugger = Slugger;
267
268marked.parse = marked;
269
270module.exports = marked;