From d607ac12097afb5cb6f398a4e7b5cf4316efedc6 Mon Sep 17 00:00:00 2001 From: altaf-creator Date: Sun, 12 May 2024 12:14:02 +0700 Subject: self host --- packages/markdown-it-14.1.0/lib/index.mjs | 565 ++++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 packages/markdown-it-14.1.0/lib/index.mjs (limited to 'packages/markdown-it-14.1.0/lib/index.mjs') diff --git a/packages/markdown-it-14.1.0/lib/index.mjs b/packages/markdown-it-14.1.0/lib/index.mjs new file mode 100644 index 0000000..8a8af9d --- /dev/null +++ b/packages/markdown-it-14.1.0/lib/index.mjs @@ -0,0 +1,565 @@ +// Main parser class + +import * as utils from './common/utils.mjs' +import * as helpers from './helpers/index.mjs' +import Renderer from './renderer.mjs' +import ParserCore from './parser_core.mjs' +import ParserBlock from './parser_block.mjs' +import ParserInline from './parser_inline.mjs' +import LinkifyIt from 'linkify-it' +import * as mdurl from 'mdurl' +import punycode from 'punycode.js' + +import cfg_default from './presets/default.mjs' +import cfg_zero from './presets/zero.mjs' +import cfg_commonmark from './presets/commonmark.mjs' + +const config = { + default: cfg_default, + zero: cfg_zero, + commonmark: cfg_commonmark +} + +// +// This validator can prohibit more than really needed to prevent XSS. It's a +// tradeoff to keep code simple and to be secure by default. +// +// If you need different setup - override validator method as you wish. Or +// replace it with dummy function and use external sanitizer. +// + +const BAD_PROTO_RE = /^(vbscript|javascript|file|data):/ +const GOOD_DATA_RE = /^data:image\/(gif|png|jpeg|webp);/ + +function validateLink (url) { + // url should be normalized at this point, and existing entities are decoded + const str = url.trim().toLowerCase() + + return BAD_PROTO_RE.test(str) ? GOOD_DATA_RE.test(str) : true +} + +const RECODE_HOSTNAME_FOR = ['http:', 'https:', 'mailto:'] + +function normalizeLink (url) { + const parsed = mdurl.parse(url, true) + + if (parsed.hostname) { + // Encode hostnames in urls like: + // `http://host/`, `https://host/`, `mailto:user@host`, `//host/` + // + // We don't encode unknown schemas, because it's likely that we encode + // something we shouldn't (e.g. `skype:name` treated as `skype:host`) + // + if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) { + try { + parsed.hostname = punycode.toASCII(parsed.hostname) + } catch (er) { /**/ } + } + } + + return mdurl.encode(mdurl.format(parsed)) +} + +function normalizeLinkText (url) { + const parsed = mdurl.parse(url, true) + + if (parsed.hostname) { + // Encode hostnames in urls like: + // `http://host/`, `https://host/`, `mailto:user@host`, `//host/` + // + // We don't encode unknown schemas, because it's likely that we encode + // something we shouldn't (e.g. `skype:name` treated as `skype:host`) + // + if (!parsed.protocol || RECODE_HOSTNAME_FOR.indexOf(parsed.protocol) >= 0) { + try { + parsed.hostname = punycode.toUnicode(parsed.hostname) + } catch (er) { /**/ } + } + } + + // add '%' to exclude list because of https://github.com/markdown-it/markdown-it/issues/720 + return mdurl.decode(mdurl.format(parsed), mdurl.decode.defaultChars + '%') +} + +/** + * class MarkdownIt + * + * Main parser/renderer class. + * + * ##### Usage + * + * ```javascript + * // node.js, "classic" way: + * var MarkdownIt = require('markdown-it'), + * md = new MarkdownIt(); + * var result = md.render('# markdown-it rulezz!'); + * + * // node.js, the same, but with sugar: + * var md = require('markdown-it')(); + * var result = md.render('# markdown-it rulezz!'); + * + * // browser without AMD, added to "window" on script load + * // Note, there are no dash. + * var md = window.markdownit(); + * var result = md.render('# markdown-it rulezz!'); + * ``` + * + * Single line rendering, without paragraph wrap: + * + * ```javascript + * var md = require('markdown-it')(); + * var result = md.renderInline('__markdown-it__ rulezz!'); + * ``` + **/ + +/** + * new MarkdownIt([presetName, options]) + * - presetName (String): optional, `commonmark` / `zero` + * - options (Object) + * + * Creates parser instanse with given config. Can be called without `new`. + * + * ##### presetName + * + * MarkdownIt provides named presets as a convenience to quickly + * enable/disable active syntax rules and options for common use cases. + * + * - ["commonmark"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.mjs) - + * configures parser to strict [CommonMark](http://commonmark.org/) mode. + * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.mjs) - + * similar to GFM, used when no preset name given. Enables all available rules, + * but still without html, typographer & autolinker. + * - ["zero"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.mjs) - + * all rules disabled. Useful to quickly setup your config via `.enable()`. + * For example, when you need only `bold` and `italic` markup and nothing else. + * + * ##### options: + * + * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful! + * That's not safe! You may need external sanitizer to protect output from XSS. + * It's better to extend features via plugins, instead of enabling HTML. + * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags + * (`
`). This is needed only for full CommonMark compatibility. In real + * world you will need HTML output. + * - __breaks__ - `false`. Set `true` to convert `\n` in paragraphs into `
`. + * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks. + * Can be useful for external highlighters. + * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links. + * - __typographer__ - `false`. Set `true` to enable [some language-neutral + * replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.mjs) + + * quotes beautification (smartquotes). + * - __quotes__ - `“”‘’`, String or Array. Double + single quotes replacement + * pairs, when typographer enabled and smartquotes on. For example, you can + * use `'«»„“'` for Russian, `'„“‚‘'` for German, and + * `['«\xA0', '\xA0»', '‹\xA0', '\xA0›']` for French (including nbsp). + * - __highlight__ - `null`. Highlighter function for fenced code blocks. + * Highlighter `function (str, lang)` should return escaped HTML. It can also + * return empty string if the source was not changed and should be escaped + * externaly. If result starts with ` or ``): + * + * ```javascript + * var hljs = require('highlight.js') // https://highlightjs.org/ + * + * // Actual default values + * var md = require('markdown-it')({ + * highlight: function (str, lang) { + * if (lang && hljs.getLanguage(lang)) { + * try { + * return '
' +
+ *                hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +
+ *                '
'; + * } catch (__) {} + * } + * + * return '
' + md.utils.escapeHtml(str) + '
'; + * } + * }); + * ``` + * + **/ +function MarkdownIt (presetName, options) { + if (!(this instanceof MarkdownIt)) { + return new MarkdownIt(presetName, options) + } + + if (!options) { + if (!utils.isString(presetName)) { + options = presetName || {} + presetName = 'default' + } + } + + /** + * MarkdownIt#inline -> ParserInline + * + * Instance of [[ParserInline]]. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.inline = new ParserInline() + + /** + * MarkdownIt#block -> ParserBlock + * + * Instance of [[ParserBlock]]. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.block = new ParserBlock() + + /** + * MarkdownIt#core -> Core + * + * Instance of [[Core]] chain executor. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.core = new ParserCore() + + /** + * MarkdownIt#renderer -> Renderer + * + * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering + * rules for new token types, generated by plugins. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * function myToken(tokens, idx, options, env, self) { + * //... + * return result; + * }; + * + * md.renderer.rules['my_token'] = myToken + * ``` + * + * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs). + **/ + this.renderer = new Renderer() + + /** + * MarkdownIt#linkify -> LinkifyIt + * + * [linkify-it](https://github.com/markdown-it/linkify-it) instance. + * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.mjs) + * rule. + **/ + this.linkify = new LinkifyIt() + + /** + * MarkdownIt#validateLink(url) -> Boolean + * + * Link validation function. CommonMark allows too much in links. By default + * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas + * except some embedded image types. + * + * You can change this behaviour: + * + * ```javascript + * var md = require('markdown-it')(); + * // enable everything + * md.validateLink = function () { return true; } + * ``` + **/ + this.validateLink = validateLink + + /** + * MarkdownIt#normalizeLink(url) -> String + * + * Function used to encode link url to a machine-readable format, + * which includes url-encoding, punycode, etc. + **/ + this.normalizeLink = normalizeLink + + /** + * MarkdownIt#normalizeLinkText(url) -> String + * + * Function used to decode link url to a human-readable format` + **/ + this.normalizeLinkText = normalizeLinkText + + // Expose utils & helpers for easy acces from plugins + + /** + * MarkdownIt#utils -> utils + * + * Assorted utility functions, useful to write plugins. See details + * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.mjs). + **/ + this.utils = utils + + /** + * MarkdownIt#helpers -> helpers + * + * Link components parser functions, useful to write plugins. See details + * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers). + **/ + this.helpers = utils.assign({}, helpers) + + this.options = {} + this.configure(presetName) + + if (options) { this.set(options) } +} + +/** chainable + * MarkdownIt.set(options) + * + * Set parser options (in the same format as in constructor). Probably, you + * will never need it, but you can change options after constructor call. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .set({ html: true, breaks: true }) + * .set({ typographer, true }); + * ``` + * + * __Note:__ To achieve the best possible performance, don't modify a + * `markdown-it` instance options on the fly. If you need multiple configurations + * it's best to create multiple instances and initialize each with separate + * config. + **/ +MarkdownIt.prototype.set = function (options) { + utils.assign(this.options, options) + return this +} + +/** chainable, internal + * MarkdownIt.configure(presets) + * + * Batch load of all options and compenent settings. This is internal method, + * and you probably will not need it. But if you will - see available presets + * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets) + * + * We strongly recommend to use presets instead of direct config loads. That + * will give better compatibility with next versions. + **/ +MarkdownIt.prototype.configure = function (presets) { + const self = this + + if (utils.isString(presets)) { + const presetName = presets + presets = config[presetName] + if (!presets) { throw new Error('Wrong `markdown-it` preset "' + presetName + '", check name') } + } + + if (!presets) { throw new Error('Wrong `markdown-it` preset, can\'t be empty') } + + if (presets.options) { self.set(presets.options) } + + if (presets.components) { + Object.keys(presets.components).forEach(function (name) { + if (presets.components[name].rules) { + self[name].ruler.enableOnly(presets.components[name].rules) + } + if (presets.components[name].rules2) { + self[name].ruler2.enableOnly(presets.components[name].rules2) + } + }) + } + return this +} + +/** chainable + * MarkdownIt.enable(list, ignoreInvalid) + * - list (String|Array): rule name or list of rule names to enable + * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. + * + * Enable list or rules. It will automatically find appropriate components, + * containing rules with given names. If rule not found, and `ignoreInvalid` + * not set - throws exception. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .enable(['sub', 'sup']) + * .disable('smartquotes'); + * ``` + **/ +MarkdownIt.prototype.enable = function (list, ignoreInvalid) { + let result = [] + + if (!Array.isArray(list)) { list = [list] } + + ['core', 'block', 'inline'].forEach(function (chain) { + result = result.concat(this[chain].ruler.enable(list, true)) + }, this) + + result = result.concat(this.inline.ruler2.enable(list, true)) + + const missed = list.filter(function (name) { return result.indexOf(name) < 0 }) + + if (missed.length && !ignoreInvalid) { + throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed) + } + + return this +} + +/** chainable + * MarkdownIt.disable(list, ignoreInvalid) + * - list (String|Array): rule name or list of rule names to disable. + * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. + * + * The same as [[MarkdownIt.enable]], but turn specified rules off. + **/ +MarkdownIt.prototype.disable = function (list, ignoreInvalid) { + let result = [] + + if (!Array.isArray(list)) { list = [list] } + + ['core', 'block', 'inline'].forEach(function (chain) { + result = result.concat(this[chain].ruler.disable(list, true)) + }, this) + + result = result.concat(this.inline.ruler2.disable(list, true)) + + const missed = list.filter(function (name) { return result.indexOf(name) < 0 }) + + if (missed.length && !ignoreInvalid) { + throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed) + } + return this +} + +/** chainable + * MarkdownIt.use(plugin, params) + * + * Load specified plugin with given params into current parser instance. + * It's just a sugar to call `plugin(md, params)` with curring. + * + * ##### Example + * + * ```javascript + * var iterator = require('markdown-it-for-inline'); + * var md = require('markdown-it')() + * .use(iterator, 'foo_replace', 'text', function (tokens, idx) { + * tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar'); + * }); + * ``` + **/ +MarkdownIt.prototype.use = function (plugin /*, params, ... */) { + const args = [this].concat(Array.prototype.slice.call(arguments, 1)) + plugin.apply(plugin, args) + return this +} + +/** internal + * MarkdownIt.parse(src, env) -> Array + * - src (String): source string + * - env (Object): environment sandbox + * + * Parse input string and return list of block tokens (special token type + * "inline" will contain list of inline tokens). You should not call this + * method directly, until you write custom renderer (for example, to produce + * AST). + * + * `env` is used to pass data between "distributed" rules and return additional + * metadata like reference info, needed for the renderer. It also can be used to + * inject data in specific cases. Usually, you will be ok to pass `{}`, + * and then pass updated object to renderer. + **/ +MarkdownIt.prototype.parse = function (src, env) { + if (typeof src !== 'string') { + throw new Error('Input data should be a String') + } + + const state = new this.core.State(src, this, env) + + this.core.process(state) + + return state.tokens +} + +/** + * MarkdownIt.render(src [, env]) -> String + * - src (String): source string + * - env (Object): environment sandbox + * + * Render markdown string into html. It does all magic for you :). + * + * `env` can be used to inject additional metadata (`{}` by default). + * But you will not need it with high probability. See also comment + * in [[MarkdownIt.parse]]. + **/ +MarkdownIt.prototype.render = function (src, env) { + env = env || {} + + return this.renderer.render(this.parse(src, env), this.options, env) +} + +/** internal + * MarkdownIt.parseInline(src, env) -> Array + * - src (String): source string + * - env (Object): environment sandbox + * + * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the + * block tokens list with the single `inline` element, containing parsed inline + * tokens in `children` property. Also updates `env` object. + **/ +MarkdownIt.prototype.parseInline = function (src, env) { + const state = new this.core.State(src, this, env) + + state.inlineMode = true + this.core.process(state) + + return state.tokens +} + +/** + * MarkdownIt.renderInline(src [, env]) -> String + * - src (String): source string + * - env (Object): environment sandbox + * + * Similar to [[MarkdownIt.render]] but for single paragraph content. Result + * will NOT be wrapped into `

` tags. + **/ +MarkdownIt.prototype.renderInline = function (src, env) { + env = env || {} + + return this.renderer.render(this.parseInline(src, env), this.options, env) +} + +export default MarkdownIt -- cgit v1.2.3