UNPKG

react-markdown

Version:
164 lines (147 loc) 5.06 kB
'use strict' const React = require('react') const unified = require('unified') const parse = require('remark-parse') const remarkRehype = require('remark-rehype') const PropTypes = require('prop-types') // @ts-ignore remove when typed const html = require('property-information/html') const filter = require('./rehype-filter') const uriTransformer = require('./uri-transformer') const childrenToReact = require('./ast-to-react.js').hastChildrenToReact /** * @typedef {import('react').ReactNode} ReactNode * @typedef {import('react').ReactElement<{}>} ReactElement * @typedef {import('unified').PluggableList} PluggableList * @typedef {import('hast').Root} Root * @typedef {import('./rehype-filter.js').RehypeFilterOptions} FilterOptions * @typedef {import('./ast-to-react.js').TransformOptions} TransformOptions * * @typedef {Object} CoreOptions * @property {string} children * * @typedef {Object} PluginOptions * @property {PluggableList} [plugins=[]] **deprecated**: use `remarkPlugins` instead * @property {PluggableList} [remarkPlugins=[]] * @property {PluggableList} [rehypePlugins=[]] * * @typedef {Object} LayoutOptions * @property {string} [className] * * @typedef {CoreOptions & PluginOptions & LayoutOptions & FilterOptions & TransformOptions} ReactMarkdownOptions */ module.exports = ReactMarkdown const own = {}.hasOwnProperty const changelog = 'https://github.com/remarkjs/react-markdown/blob/main/changelog.md' /** * @typedef {Object} Deprecation * @property {string} id * @property {string} [to] */ /** * @type {Object.<string, Deprecation>} */ const deprecated = { renderers: {to: 'components', id: 'change-renderers-to-components'}, astPlugins: {id: 'remove-buggy-html-in-markdown-parser'}, allowDangerousHtml: {id: 'remove-buggy-html-in-markdown-parser'}, escapeHtml: {id: 'remove-buggy-html-in-markdown-parser'}, source: {to: 'children', id: 'change-source-to-children'}, allowNode: { to: 'allowElement', id: 'replace-allownode-allowedtypes-and-disallowedtypes' }, allowedTypes: { to: 'allowedElements', id: 'replace-allownode-allowedtypes-and-disallowedtypes' }, disallowedTypes: { to: 'disallowedElements', id: 'replace-allownode-allowedtypes-and-disallowedtypes' }, includeNodeIndex: { to: 'includeElementIndex', id: 'change-includenodeindex-to-includeelementindex' } } /** * @param {ReactMarkdownOptions} options * @returns {ReactElement} */ function ReactMarkdown(options) { for (const key in deprecated) { if (own.call(deprecated, key) && own.call(options, key)) { /** @type {Deprecation} */ const deprecation = deprecated[key] console.warn( `[react-markdown] Warning: please ${ deprecation.to ? `use \`${deprecation.to}\` instead of` : 'remove' } \`${key}\` (see <${changelog}#${deprecation.id}> for more info)` ) delete deprecated[key] } } const processor = unified() .use(parse) // TODO: deprecate `plugins` in v7.0.0. .use(options.remarkPlugins || options.plugins || []) .use(remarkRehype, {allowDangerousHtml: true}) .use(options.rehypePlugins || []) .use(filter, options) /** @type {Root} */ // @ts-ignore we’ll throw if it isn’t a root next. const hastNode = processor.runSync(processor.parse(options.children || '')) if (hastNode.type !== 'root') { throw new TypeError('Expected a `root` node') } /** @type {ReactElement} */ let result = React.createElement( React.Fragment, {}, childrenToReact({options: options, schema: html, listDepth: 0}, hastNode) ) if (options.className) { result = React.createElement('div', {className: options.className}, result) } return result } ReactMarkdown.defaultProps = {transformLinkUri: uriTransformer} ReactMarkdown.propTypes = { // Core options: children: PropTypes.string, // Layout options: className: PropTypes.string, // Filter options: allowElement: PropTypes.func, allowedElements: PropTypes.arrayOf(PropTypes.string), disallowedElements: PropTypes.arrayOf(PropTypes.string), unwrapDisallowed: PropTypes.bool, // Plugin options: // type-coverage:ignore-next-line remarkPlugins: PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.object, PropTypes.func, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.func])) ]) ), // type-coverage:ignore-next-line rehypePlugins: PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.object, PropTypes.func, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.func])) ]) ), // Transform options: sourcePos: PropTypes.bool, rawSourcePos: PropTypes.bool, skipHtml: PropTypes.bool, includeElementIndex: PropTypes.bool, transformLinkUri: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), linkTarget: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), transformImageUri: PropTypes.func, components: PropTypes.object } ReactMarkdown.uriTransformer = uriTransformer