const Lexer = require('./Lexer.js'); const Parser = require('./Parser.js'); const Tokenizer = require('./Tokenizer.js'); const Renderer = require('./Renderer.js'); const TextRenderer = require('./TextRenderer.js'); const Slugger = require('./Slugger.js'); const { merge, checkSanitizeDeprecation, escape } = require('./helpers.js'); const { getDefaults, changeDefaults, defaults } = require('./defaults.js'); /** * Marked */ function marked(src, opt, callback) { // throw error in case of non string input if (typeof src === 'undefined' || src === null) { throw new Error('marked(): input parameter is undefined or null'); } if (typeof src !== 'string') { throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected'); } if (typeof opt === 'function') { callback = opt; opt = null; } opt = merge({}, marked.defaults, opt || {}); checkSanitizeDeprecation(opt); if (callback) { const highlight = opt.highlight; let tokens; try { tokens = Lexer.lex(src, opt); } catch (e) { return callback(e); } const done = function(err) { let out; if (!err) { try { out = Parser.parse(tokens, opt); } catch (e) { err = e; } } opt.highlight = highlight; return err ? callback(err) : callback(null, out); }; if (!highlight || highlight.length < 3) { return done(); } delete opt.highlight; if (!tokens.length) return done(); let pending = 0; marked.walkTokens(tokens, function(token) { if (token.type === 'code') { pending++; setTimeout(() => { highlight(token.text, token.lang, function(err, code) { if (err) { return done(err); } if (code != null && code !== token.text) { token.text = code; token.escaped = true; } pending--; if (pending === 0) { done(); } }); }, 0); } }); if (pending === 0) { done(); } return; } try { const tokens = Lexer.lex(src, opt); if (opt.walkTokens) { marked.walkTokens(tokens, opt.walkTokens); } return Parser.parse(tokens, opt); } catch (e) { e.message += '\nPlease report this to https://github.com/markedjs/marked.'; if (opt.silent) { return '
An error occurred:
'
+ escape(e.message + '', true)
+ '';
}
throw e;
}
}
/**
* Options
*/
marked.options =
marked.setOptions = function(opt) {
merge(marked.defaults, opt);
changeDefaults(marked.defaults);
return marked;
};
marked.getDefaults = getDefaults;
marked.defaults = defaults;
/**
* Use Extension
*/
marked.use = function(extension) {
const opts = merge({}, extension);
if (extension.renderer) {
const renderer = marked.defaults.renderer || new Renderer();
for (const prop in extension.renderer) {
const prevRenderer = renderer[prop];
renderer[prop] = (...args) => {
let ret = extension.renderer[prop].apply(renderer, args);
if (ret === false) {
ret = prevRenderer.apply(renderer, args);
}
return ret;
};
}
opts.renderer = renderer;
}
if (extension.tokenizer) {
const tokenizer = marked.defaults.tokenizer || new Tokenizer();
for (const prop in extension.tokenizer) {
const prevTokenizer = tokenizer[prop];
tokenizer[prop] = (...args) => {
let ret = extension.tokenizer[prop].apply(tokenizer, args);
if (ret === false) {
ret = prevTokenizer.apply(tokenizer, args);
}
return ret;
};
}
opts.tokenizer = tokenizer;
}
if (extension.walkTokens) {
const walkTokens = marked.defaults.walkTokens;
opts.walkTokens = (token) => {
extension.walkTokens(token);
if (walkTokens) {
walkTokens(token);
}
};
}
marked.setOptions(opts);
};
/**
* Run callback for every token
*/
marked.walkTokens = function(tokens, callback) {
for (const token of tokens) {
callback(token);
switch (token.type) {
case 'table': {
for (const cell of token.tokens.header) {
marked.walkTokens(cell, callback);
}
for (const row of token.tokens.cells) {
for (const cell of row) {
marked.walkTokens(cell, callback);
}
}
break;
}
case 'list': {
marked.walkTokens(token.items, callback);
break;
}
default: {
if (token.tokens) {
marked.walkTokens(token.tokens, callback);
}
}
}
}
};
/**
* Parse Inline
*/
marked.parseInline = function(src, opt) {
// throw error in case of non string input
if (typeof src === 'undefined' || src === null) {
throw new Error('marked.parseInline(): input parameter is undefined or null');
}
if (typeof src !== 'string') {
throw new Error('marked.parseInline(): input parameter is of type '
+ Object.prototype.toString.call(src) + ', string expected');
}
opt = merge({}, marked.defaults, opt || {});
checkSanitizeDeprecation(opt);
try {
const tokens = Lexer.lexInline(src, opt);
if (opt.walkTokens) {
marked.walkTokens(tokens, opt.walkTokens);
}
return Parser.parseInline(tokens, opt);
} catch (e) {
e.message += '\nPlease report this to https://github.com/markedjs/marked.';
if (opt.silent) {
return 'An error occurred:
'
+ escape(e.message + '', true)
+ '';
}
throw e;
}
};
/**
* Expose
*/
marked.Parser = Parser;
marked.parser = Parser.parse;
marked.Renderer = Renderer;
marked.TextRenderer = TextRenderer;
marked.Lexer = Lexer;
marked.lexer = Lexer.lex;
marked.Tokenizer = Tokenizer;
marked.Slugger = Slugger;
marked.parse = marked;
module.exports = marked;