UNPKG

dina-agi

Version:

DINA AGI - Dynamic Intelligence Network Architecture. 128 Autonomous Agents with Claude Flow, Swarms, and 300+ MCPs. True AGI System.

323 lines (271 loc) 8.93 kB
/** * class Renderer * * Generates HTML from parsed token stream. Each instance has independent * copy of rules. Those can be rewritten with ease. Also, you can add new * rules if you create plugin and adds new token types. **/ import { assign, unescapeAll, escapeHtml } from './common/utils.mjs' const default_rules = {} default_rules.code_inline = function (tokens, idx, options, env, slf) { const token = tokens[idx] return '<code' + slf.renderAttrs(token) + '>' + escapeHtml(token.content) + '</code>' } default_rules.code_block = function (tokens, idx, options, env, slf) { const token = tokens[idx] return '<pre' + slf.renderAttrs(token) + '><code>' + escapeHtml(tokens[idx].content) + '</code></pre>\n' } default_rules.fence = function (tokens, idx, options, env, slf) { const token = tokens[idx] const info = token.info ? unescapeAll(token.info).trim() : '' let langName = '' let langAttrs = '' if (info) { const arr = info.split(/(\s+)/g) langName = arr[0] langAttrs = arr.slice(2).join('') } let highlighted if (options.highlight) { highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content) } else { highlighted = escapeHtml(token.content) } if (highlighted.indexOf('<pre') === 0) { return highlighted + '\n' } // If language exists, inject class gently, without modifying original token. // May be, one day we will add .deepClone() for token and simplify this part, but // now we prefer to keep things local. if (info) { const i = token.attrIndex('class') const tmpAttrs = token.attrs ? token.attrs.slice() : [] if (i < 0) { tmpAttrs.push(['class', options.langPrefix + langName]) } else { tmpAttrs[i] = tmpAttrs[i].slice() tmpAttrs[i][1] += ' ' + options.langPrefix + langName } // Fake token just to render attributes const tmpToken = { attrs: tmpAttrs } return `<pre><code${slf.renderAttrs(tmpToken)}>${highlighted}</code></pre>\n` } return `<pre><code${slf.renderAttrs(token)}>${highlighted}</code></pre>\n` } default_rules.image = function (tokens, idx, options, env, slf) { const token = tokens[idx] // "alt" attr MUST be set, even if empty. Because it's mandatory and // should be placed on proper position for tests. // // Replace content with actual value token.attrs[token.attrIndex('alt')][1] = slf.renderInlineAsText(token.children, options, env) return slf.renderToken(tokens, idx, options) } default_rules.hardbreak = function (tokens, idx, options /*, env */) { return options.xhtmlOut ? '<br />\n' : '<br>\n' } default_rules.softbreak = function (tokens, idx, options /*, env */) { return options.breaks ? (options.xhtmlOut ? '<br />\n' : '<br>\n') : '\n' } default_rules.text = function (tokens, idx /*, options, env */) { return escapeHtml(tokens[idx].content) } default_rules.html_block = function (tokens, idx /*, options, env */) { return tokens[idx].content } default_rules.html_inline = function (tokens, idx /*, options, env */) { return tokens[idx].content } /** * new Renderer() * * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults. **/ function Renderer () { /** * Renderer#rules -> Object * * Contains render rules for tokens. Can be updated and extended. * * ##### Example * * ```javascript * var md = require('markdown-it')(); * * md.renderer.rules.strong_open = function () { return '<b>'; }; * md.renderer.rules.strong_close = function () { return '</b>'; }; * * var result = md.renderInline(...); * ``` * * Each rule is called as independent static function with fixed signature: * * ```javascript * function my_token_render(tokens, idx, options, env, renderer) { * // ... * return renderedHTML; * } * ``` * * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs) * for more details and examples. **/ this.rules = assign({}, default_rules) } /** * Renderer.renderAttrs(token) -> String * * Render token attributes to string. **/ Renderer.prototype.renderAttrs = function renderAttrs (token) { let i, l, result if (!token.attrs) { return '' } result = '' for (i = 0, l = token.attrs.length; i < l; i++) { result += ' ' + escapeHtml(token.attrs[i][0]) + '="' + escapeHtml(token.attrs[i][1]) + '"' } return result } /** * Renderer.renderToken(tokens, idx, options) -> String * - tokens (Array): list of tokens * - idx (Numbed): token index to render * - options (Object): params of parser instance * * Default token renderer. Can be overriden by custom function * in [[Renderer#rules]]. **/ Renderer.prototype.renderToken = function renderToken (tokens, idx, options) { const token = tokens[idx] let result = '' // Tight list paragraphs if (token.hidden) { return '' } // Insert a newline between hidden paragraph and subsequent opening // block-level tag. // // For example, here we should insert a newline before blockquote: // - a // > // if (token.block && token.nesting !== -1 && idx && tokens[idx - 1].hidden) { result += '\n' } // Add token name, e.g. `<img` result += (token.nesting === -1 ? '</' : '<') + token.tag // Encode attributes, e.g. `<img src="foo"` result += this.renderAttrs(token) // Add a slash for self-closing tags, e.g. `<img src="foo" /` if (token.nesting === 0 && options.xhtmlOut) { result += ' /' } // Check if we need to add a newline after this tag let needLf = false if (token.block) { needLf = true if (token.nesting === 1) { if (idx + 1 < tokens.length) { const nextToken = tokens[idx + 1] if (nextToken.type === 'inline' || nextToken.hidden) { // Block-level tag containing an inline tag. // needLf = false } else if (nextToken.nesting === -1 && nextToken.tag === token.tag) { // Opening tag + closing tag of the same type. E.g. `<li></li>`. // needLf = false } } } } result += needLf ? '>\n' : '>' return result } /** * Renderer.renderInline(tokens, options, env) -> String * - tokens (Array): list on block tokens to render * - options (Object): params of parser instance * - env (Object): additional data from parsed input (references, for example) * * The same as [[Renderer.render]], but for single token of `inline` type. **/ Renderer.prototype.renderInline = function (tokens, options, env) { let result = '' const rules = this.rules for (let i = 0, len = tokens.length; i < len; i++) { const type = tokens[i].type if (typeof rules[type] !== 'undefined') { result += rules[type](tokens, i, options, env, this) } else { result += this.renderToken(tokens, i, options) } } return result } /** internal * Renderer.renderInlineAsText(tokens, options, env) -> String * - tokens (Array): list on block tokens to render * - options (Object): params of parser instance * - env (Object): additional data from parsed input (references, for example) * * Special kludge for image `alt` attributes to conform CommonMark spec. * Don't try to use it! Spec requires to show `alt` content with stripped markup, * instead of simple escaping. **/ Renderer.prototype.renderInlineAsText = function (tokens, options, env) { let result = '' for (let i = 0, len = tokens.length; i < len; i++) { switch (tokens[i].type) { case 'text': result += tokens[i].content break case 'image': result += this.renderInlineAsText(tokens[i].children, options, env) break case 'html_inline': case 'html_block': result += tokens[i].content break case 'softbreak': case 'hardbreak': result += '\n' break default: // all other tokens are skipped } } return result } /** * Renderer.render(tokens, options, env) -> String * - tokens (Array): list on block tokens to render * - options (Object): params of parser instance * - env (Object): additional data from parsed input (references, for example) * * Takes token stream and generates HTML. Probably, you will never need to call * this method directly. **/ Renderer.prototype.render = function (tokens, options, env) { let result = '' const rules = this.rules for (let i = 0, len = tokens.length; i < len; i++) { const type = tokens[i].type if (type === 'inline') { result += this.renderInline(tokens[i].children, options, env) } else if (typeof rules[type] !== 'undefined') { result += rules[type](tokens, i, options, env, this) } else { result += this.renderToken(tokens, i, options, env) } } return result } export default Renderer