123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- import { Lexer } from './Lexer.js';
- import { Parser } from './Parser.js';
- import { Tokenizer } from './Tokenizer.js';
- import { Renderer } from './Renderer.js';
- import { TextRenderer } from './TextRenderer.js';
- import { Slugger } from './Slugger.js';
- import {
- merge,
- checkSanitizeDeprecation,
- escape
- } from './helpers.js';
- import {
- getDefaults,
- changeDefaults,
- defaults
- } from './defaults.js';
- /**
- * Marked
- */
- export 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 {
- if (opt.walkTokens) {
- marked.walkTokens(tokens, opt.walkTokens);
- }
- 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 '<p>An error occurred:</p><pre>'
- + escape(e.message + '', true)
- + '</pre>';
- }
- 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(...args) {
- const opts = merge({}, ...args);
- const extensions = marked.defaults.extensions || { renderers: {}, childTokens: {} };
- let hasExtensions;
- args.forEach((pack) => {
- // ==-- Parse "addon" extensions --== //
- if (pack.extensions) {
- hasExtensions = true;
- pack.extensions.forEach((ext) => {
- if (!ext.name) {
- throw new Error('extension name required');
- }
- if (ext.renderer) { // Renderer extensions
- const prevRenderer = extensions.renderers ? extensions.renderers[ext.name] : null;
- if (prevRenderer) {
- // Replace extension with func to run new extension but fall back if false
- extensions.renderers[ext.name] = function(...args) {
- let ret = ext.renderer.apply(this, args);
- if (ret === false) {
- ret = prevRenderer.apply(this, args);
- }
- return ret;
- };
- } else {
- extensions.renderers[ext.name] = ext.renderer;
- }
- }
- if (ext.tokenizer) { // Tokenizer Extensions
- if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
- throw new Error("extension level must be 'block' or 'inline'");
- }
- if (extensions[ext.level]) {
- extensions[ext.level].unshift(ext.tokenizer);
- } else {
- extensions[ext.level] = [ext.tokenizer];
- }
- if (ext.start) { // Function to check for start of token
- if (ext.level === 'block') {
- if (extensions.startBlock) {
- extensions.startBlock.push(ext.start);
- } else {
- extensions.startBlock = [ext.start];
- }
- } else if (ext.level === 'inline') {
- if (extensions.startInline) {
- extensions.startInline.push(ext.start);
- } else {
- extensions.startInline = [ext.start];
- }
- }
- }
- }
- if (ext.childTokens) { // Child tokens to be visited by walkTokens
- extensions.childTokens[ext.name] = ext.childTokens;
- }
- });
- }
- // ==-- Parse "overwrite" extensions --== //
- if (pack.renderer) {
- const renderer = marked.defaults.renderer || new Renderer();
- for (const prop in pack.renderer) {
- const prevRenderer = renderer[prop];
- // Replace renderer with func to run extension, but fall back if false
- renderer[prop] = (...args) => {
- let ret = pack.renderer[prop].apply(renderer, args);
- if (ret === false) {
- ret = prevRenderer.apply(renderer, args);
- }
- return ret;
- };
- }
- opts.renderer = renderer;
- }
- if (pack.tokenizer) {
- const tokenizer = marked.defaults.tokenizer || new Tokenizer();
- for (const prop in pack.tokenizer) {
- const prevTokenizer = tokenizer[prop];
- // Replace tokenizer with func to run extension, but fall back if false
- tokenizer[prop] = (...args) => {
- let ret = pack.tokenizer[prop].apply(tokenizer, args);
- if (ret === false) {
- ret = prevTokenizer.apply(tokenizer, args);
- }
- return ret;
- };
- }
- opts.tokenizer = tokenizer;
- }
- // ==-- Parse WalkTokens extensions --== //
- if (pack.walkTokens) {
- const walkTokens = marked.defaults.walkTokens;
- opts.walkTokens = function(token) {
- pack.walkTokens.call(this, token);
- if (walkTokens) {
- walkTokens.call(this, token);
- }
- };
- }
- if (hasExtensions) {
- opts.extensions = extensions;
- }
- marked.setOptions(opts);
- });
- };
- /**
- * Run callback for every token
- */
- marked.walkTokens = function(tokens, callback) {
- for (const token of tokens) {
- callback.call(marked, token);
- switch (token.type) {
- case 'table': {
- for (const cell of token.header) {
- marked.walkTokens(cell.tokens, callback);
- }
- for (const row of token.rows) {
- for (const cell of row) {
- marked.walkTokens(cell.tokens, callback);
- }
- }
- break;
- }
- case 'list': {
- marked.walkTokens(token.items, callback);
- break;
- }
- default: {
- if (marked.defaults.extensions && marked.defaults.extensions.childTokens && marked.defaults.extensions.childTokens[token.type]) { // Walk any extensions
- marked.defaults.extensions.childTokens[token.type].forEach(function(childTokens) {
- marked.walkTokens(token[childTokens], callback);
- });
- } else 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 '<p>An error occurred:</p><pre>'
- + escape(e.message + '', true)
- + '</pre>';
- }
- 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;
- export const options = marked.options;
- export const setOptions = marked.setOptions;
- export const use = marked.use;
- export const walkTokens = marked.walkTokens;
- export const parseInline = marked.parseInline;
- export const parse = marked;
- export const parser = Parser.parse;
- export const lexer = Lexer.lex;
- export { defaults, getDefaults } from './defaults.js';
- export { Lexer } from './Lexer.js';
- export { Parser } from './Parser.js';
- export { Tokenizer } from './Tokenizer.js';
- export { Renderer } from './Renderer.js';
- export { TextRenderer } from './TextRenderer.js';
- export { Slugger } from './Slugger.js';
|