summaryrefslogtreecommitdiff
path: root/packages/markdown-it-14.1.0/lib/renderer.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'packages/markdown-it-14.1.0/lib/renderer.mjs')
-rw-r--r--packages/markdown-it-14.1.0/lib/renderer.mjs322
1 files changed, 322 insertions, 0 deletions
diff --git a/packages/markdown-it-14.1.0/lib/renderer.mjs b/packages/markdown-it-14.1.0/lib/renderer.mjs
new file mode 100644
index 0000000..a58914c
--- /dev/null
+++ b/packages/markdown-it-14.1.0/lib/renderer.mjs
@@ -0,0 +1,322 @@
+/**
+ * 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