diff options
Diffstat (limited to 'node_modules/marked/src/marked.js')
-rw-r--r-- | node_modules/marked/src/marked.js | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/node_modules/marked/src/marked.js b/node_modules/marked/src/marked.js new file mode 100644 index 0000000..36ec040 --- /dev/null +++ b/node_modules/marked/src/marked.js @@ -0,0 +1,416 @@ +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 { Hooks } from './Hooks.js'; +import { + checkSanitizeDeprecation, + escape +} from './helpers.js'; +import { + getDefaults, + changeDefaults, + defaults +} from './defaults.js'; + +function onError(silent, async, callback) { + return (e) => { + e.message += '\nPlease report this to https://github.com/markedjs/marked.'; + + if (silent) { + const msg = '<p>An error occurred:</p><pre>' + + escape(e.message + '', true) + + '</pre>'; + if (async) { + return Promise.resolve(msg); + } + if (callback) { + callback(null, msg); + return; + } + return msg; + } + + if (async) { + return Promise.reject(e); + } + if (callback) { + callback(e); + return; + } + throw e; + }; +} + +function parseMarkdown(lexer, parser) { + return (src, opt, callback) => { + if (typeof opt === 'function') { + callback = opt; + opt = null; + } + + const origOpt = { ...opt }; + opt = { ...marked.defaults, ...origOpt }; + const throwError = onError(opt.silent, opt.async, callback); + + // throw error in case of non string input + if (typeof src === 'undefined' || src === null) { + return throwError(new Error('marked(): input parameter is undefined or null')); + } + if (typeof src !== 'string') { + return throwError(new Error('marked(): input parameter is of type ' + + Object.prototype.toString.call(src) + ', string expected')); + } + + checkSanitizeDeprecation(opt); + + if (opt.hooks) { + opt.hooks.options = opt; + } + + if (callback) { + const highlight = opt.highlight; + let tokens; + + try { + if (opt.hooks) { + src = opt.hooks.preprocess(src); + } + tokens = lexer(src, opt); + } catch (e) { + return throwError(e); + } + + const done = function(err) { + let out; + + if (!err) { + try { + if (opt.walkTokens) { + marked.walkTokens(tokens, opt.walkTokens); + } + out = parser(tokens, opt); + if (opt.hooks) { + out = opt.hooks.postprocess(out); + } + } catch (e) { + err = e; + } + } + + opt.highlight = highlight; + + return err + ? throwError(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; + } + + if (opt.async) { + return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src) + .then(src => lexer(src, opt)) + .then(tokens => opt.walkTokens ? Promise.all(marked.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens) + .then(tokens => parser(tokens, opt)) + .then(html => opt.hooks ? opt.hooks.postprocess(html) : html) + .catch(throwError); + } + + try { + if (opt.hooks) { + src = opt.hooks.preprocess(src); + } + const tokens = lexer(src, opt); + if (opt.walkTokens) { + marked.walkTokens(tokens, opt.walkTokens); + } + let html = parser(tokens, opt); + if (opt.hooks) { + html = opt.hooks.postprocess(html); + } + return html; + } catch (e) { + return throwError(e); + } + }; +} + +/** + * Marked + */ +export function marked(src, opt, callback) { + return parseMarkdown(Lexer.lex, Parser.parse)(src, opt, callback); +} + +/** + * Options + */ + +marked.options = +marked.setOptions = function(opt) { + marked.defaults = { ...marked.defaults, ...opt }; + changeDefaults(marked.defaults); + return marked; +}; + +marked.getDefaults = getDefaults; + +marked.defaults = defaults; + +/** + * Use Extension + */ + +marked.use = function(...args) { + const extensions = marked.defaults.extensions || { renderers: {}, childTokens: {} }; + + args.forEach((pack) => { + // copy options to new object + const opts = { ...pack }; + + // set async to true if it was set to true before + opts.async = marked.defaults.async || opts.async || false; + + // ==-- Parse "addon" extensions --== // + if (pack.extensions) { + pack.extensions.forEach((ext) => { + if (!ext.name) { + throw new Error('extension name required'); + } + if (ext.renderer) { // Renderer extensions + const prevRenderer = extensions.renderers[ext.name]; + 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; + } + }); + opts.extensions = extensions; + } + + // ==-- 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 Hooks extensions --== // + if (pack.hooks) { + const hooks = marked.defaults.hooks || new Hooks(); + for (const prop in pack.hooks) { + const prevHook = hooks[prop]; + if (Hooks.passThroughHooks.has(prop)) { + hooks[prop] = (arg) => { + if (marked.defaults.async) { + return Promise.resolve(pack.hooks[prop].call(hooks, arg)).then(ret => { + return prevHook.call(hooks, ret); + }); + } + + const ret = pack.hooks[prop].call(hooks, arg); + return prevHook.call(hooks, ret); + }; + } else { + hooks[prop] = (...args) => { + let ret = pack.hooks[prop].apply(hooks, args); + if (ret === false) { + ret = prevHook.apply(hooks, args); + } + return ret; + }; + } + } + opts.hooks = hooks; + } + + // ==-- Parse WalkTokens extensions --== // + if (pack.walkTokens) { + const walkTokens = marked.defaults.walkTokens; + opts.walkTokens = function(token) { + let values = []; + values.push(pack.walkTokens.call(this, token)); + if (walkTokens) { + values = values.concat(walkTokens.call(this, token)); + } + return values; + }; + } + + marked.setOptions(opts); + }); +}; + +/** + * Run callback for every token + */ + +marked.walkTokens = function(tokens, callback) { + let values = []; + for (const token of tokens) { + values = values.concat(callback.call(marked, token)); + switch (token.type) { + case 'table': { + for (const cell of token.header) { + values = values.concat(marked.walkTokens(cell.tokens, callback)); + } + for (const row of token.rows) { + for (const cell of row) { + values = values.concat(marked.walkTokens(cell.tokens, callback)); + } + } + break; + } + case 'list': { + values = values.concat(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) { + values = values.concat(marked.walkTokens(token[childTokens], callback)); + }); + } else if (token.tokens) { + values = values.concat(marked.walkTokens(token.tokens, callback)); + } + } + } + } + return values; +}; + +/** + * Parse Inline + * @param {string} src + */ +marked.parseInline = parseMarkdown(Lexer.lexInline, Parser.parseInline); + +/** + * 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.Hooks = Hooks; +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'; +export { Hooks } from './Hooks.js'; |