marked
marked 使用了单例模式
marked 提供了一个插件式开发的基座,
function marked{}const markedInstance = new Marked;marked.use =function ...args: MarkedExtension[]{ markedInstance.use...args;}use 方法
class Marked { constructor...args: MarkedExtension[]{ this.use...args } use...args: MarkedExtension[] { const extensions: MarkedOptions['extensions'] = this.defaults.extensions { renderers: {}, childTokens: {} }; args.forEachpack => { const opts = { ...pack } as MarkedOptions; opts.async = this.defaults.async opts.async false; ifpack.extensions{ pack.extensions.forEachext => { if !ext.name { throw new Error'extension name required'; } if"renderer" in ext{ const prevRenderer = extensions.renderers[ext.name]; ifprevRenderer{ extensions.renderers[ext.name] = function...args{ let ret = ext.renderer.applythis, args; ifret === false{ ret = prevRenderer.applythis, args; } return ret; } } else { extensions.renderers[ext.name] = ext.renderer } } } } } }}parse 文档解析处理
- 词法分析可以分为2中类型,一种是仅有行内的规则,一种是包含块级规则的
- 如果hooks存在,则优先从hooks中获取词法分析函数
- 如果是异步的则返回promise
执行顺序
- 优先执行钩子函数中的pregrocess
- 进行词法分析Lexer
- 对词法分析后的token执行钩子函数中的processAllTokens
- 对词法分析后的token执行walkTokens函数处理
- 进行语法解析parse
- 对语法分析后的结果进行钩子中的postprocess函数
class Marked { parse = this.parseMarkdowntrue; parseInline = this.parseMarkdownfalse; private parseMarkdownblockType: boolean{ type overloadedParse = { src: string, options: MarkedOptions & { async: true }: Promise<string>; src: string, options: MarkedOptions & { async: false }: string; src: string, options?: MarkedOptions null: string Promise<string>; }; const parse: overloadedParse = src: string, options: MarkedOptions null: any => { const origOpt = { ...options }; const opt = { ...this.defaults, ...origOpt }; const throwError = this.onError!!opt.silent, !!opt.async; if this.defaults.async === true && origOpt.async === false { return throwErrornew Error'marked: The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.'; } if typeof src === 'undefined' src === null { return throwErrornew Error'marked: input parameter is undefined or null'; } if typeof src !== 'string' { return throwErrornew Error'marked: input parameter is of type ' + Object.prototype.toString.callsrc + ', string expected'; } if opt.hooks { opt.hooks.options = opt; opt.hooks.block = blockType; } const lexer = opt.hooks ? opt.hooks.provideLexer : blockType ? _Lexer.lex : _Lexer.lexInline; const parser = opt.hooks ? opt.hooks.provideParser : blockType ? _Parser.parse : _Parser.parseInline; if opt.async { return Promise.resolveopt.hooks ? opt.hooks.preprocesssrc : src .thensrc => lexersrc, opt .thentokens => opt.hooks ? opt.hooks.processAllTokenstokens : tokens .thentokens => opt.walkTokens ? Promise.allthis.walkTokenstokens, opt.walkTokens.then => tokens : tokens .thentokens => parsertokens, opt .thenhtml => opt.hooks ? opt.hooks.postprocesshtml : html .catchthrowError; } try { if opt.hooks { src = opt.hooks.preprocesssrc as string; } let tokens = lexersrc, opt; if opt.hooks { tokens = opt.hooks.processAllTokenstokens; } if opt.walkTokens { this.walkTokenstokens, opt.walkTokens; } let html = parsertokens, opt; if opt.hooks { html = opt.hooks.postprocesshtml as string; } return html; } catch e { return throwErrore as Error; } } return parse; } private onErrorsilent: boolean, async: boolean { return e: Error: string Promise<string> => { e.message += '\nPlease report this to https://github.com/markedjs/marked.'; if silent { const msg = '<p>An error occurred:</p><pre>' + escapee.message + '', true + '</pre>'; if async { return Promise.resolvemsg; } return msg; } if async { return Promise.rejecte; } throw e; }; }}