Skip to content

Commit

Permalink
Refactor code-style
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Aug 13, 2021
1 parent 3dffd6a commit 8737eac
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 340 deletions.
72 changes: 25 additions & 47 deletions lib/ast-to-react.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
import React from 'react'
import ReactIs from 'react-is'
import {svg, find, hastToReact} from 'property-information'
import {stringify as spaces} from 'space-separated-tokens'
import {stringify as commas} from 'comma-separated-tokens'
import style from 'style-to-object'

/**
* @typedef {JSX.IntrinsicElements} IntrinsicElements
* @typedef {import('react').ReactNode} ReactNode
Expand All @@ -14,31 +7,15 @@ import style from 'style-to-object'
* @typedef {import('hast').Text} Text
* @typedef {import('hast').Comment} Comment
* @typedef {import('hast').DocType} Doctype
*/

/**
* @typedef Info
* @property {string?} space
* @property {string?} attribute
* @property {string?} property
* @property {boolean} boolean
* @property {boolean} booleanish
* @property {boolean} overloadedBoolean
* @property {boolean} number
* @property {boolean} commaSeparated
* @property {boolean} spaceSeparated
* @property {boolean} commaOrSpaceSeparated
* @property {boolean} mustUseProperty
* @property {boolean} defined
*
* @typedef {import('property-information').Info} Info
* @typedef {import('property-information').Schema} Schema
*
* @typedef Raw
* @property {'raw'} type
* @property {string} value
*
* @typedef Context
* @property {TransformOptions} options
* @property {Options} options
* @property {Schema} schema
* @property {number} listDepth
*
Expand Down Expand Up @@ -117,10 +94,8 @@ import style from 'style-to-object'
*
* @typedef {{[TagName in keyof IntrinsicElements]: TagName | ((props: IntrinsicElements[TagName] & ReactMarkdownProps) => ReactNode)}} NormalComponents
* @typedef {Partial<Omit<NormalComponents, keyof SpecialComponents> & SpecialComponents>} Components
*/

/**
* @typedef TransformOptions
*
* @typedef Options
* @property {boolean} [sourcePos=false]
* @property {boolean} [rawSourcePos=false]
* @property {boolean} [skipHtml=false]
Expand All @@ -131,6 +106,13 @@ import style from 'style-to-object'
* @property {Components} [components]
*/

import React from 'react'
import ReactIs from 'react-is'
import {svg, find, hastToReact} from 'property-information'
import {stringify as spaces} from 'space-separated-tokens'
import {stringify as commas} from 'comma-separated-tokens'
import style from 'style-to-object'

const own = {}.hasOwnProperty

// The table-related elements that must not contain whitespace text according
Expand Down Expand Up @@ -163,9 +145,8 @@ export function childrenToReact(context, node) {
) {
children.push(child.value)
}
}
// @ts-expect-error `raw` nodes are non-standard
else if (child.type === 'raw' && !context.options.skipHtml) {
// @ts-expect-error `raw` nodes are non-standard
} else if (child.type === 'raw' && !context.options.skipHtml) {
// Default behavior is to show (encoded) HTML.
// @ts-expect-error `raw` nodes are non-standard
children.push(child.value)
Expand Down Expand Up @@ -198,10 +179,8 @@ function toReact(context, node, index, parent) {
context.schema = schema
}

/* istanbul ignore else - types say they’re optional. */
if (node.properties) {
for (property in node.properties) {
/* istanbul ignore else - prototype polution. */
if (own.call(node.properties, property)) {
addProperty(properties, property, node.properties[property], context)
}
Expand Down Expand Up @@ -249,17 +228,19 @@ function toReact(context, node, index, parent) {
if (name === 'a' && options.linkTarget) {
properties.target =
typeof options.linkTarget === 'function'
? // @ts-expect-error assume `href` is a string
options.linkTarget(properties.href, node.children, properties.title)
? options.linkTarget(
String(properties.href || ''),
node.children,
typeof properties.title === 'string' ? properties.title : null
)
: options.linkTarget
}

if (name === 'a' && options.transformLinkUri) {
properties.href = options.transformLinkUri(
// @ts-expect-error assume `href` is a string
properties.href,
String(properties.href || ''),
node.children,
properties.title
typeof properties.title === 'string' ? properties.title : null
)
}

Expand All @@ -281,15 +262,14 @@ function toReact(context, node, index, parent) {
name === 'h5' ||
name === 'h6')
) {
properties.level = parseInt(name.charAt(1), 10)
properties.level = Number.parseInt(name.charAt(1), 10)
}

if (name === 'img' && options.transformImageUri) {
properties.src = options.transformImageUri(
// @ts-expect-error assume `src` is a string
properties.src,
properties.alt,
properties.title
String(properties.src || ''),
String(properties.alt || ''),
typeof properties.title === 'string' ? properties.title : null
)
}

Expand Down Expand Up @@ -402,15 +382,13 @@ function addProperty(props, prop, value, ctx) {
// Accept `array`.
// Most props are space-separated.
if (Array.isArray(result)) {
// type-coverage:ignore-next-line remove when typed.
result = info.commaSeparated ? commas(result) : spaces(result)
}

if (info.property === 'style' && typeof result === 'string') {
result = parseStyle(result)
}

/* istanbul ignore else - types say they’re optional. */
if (info.space && info.property) {
props[
own.call(hastToReact, info.property)
Expand All @@ -432,7 +410,7 @@ function parseStyle(value) {

try {
style(value, iterator)
} catch (/** @type {unknown} */ _) {
} catch {
// Silent.
}

Expand Down
51 changes: 21 additions & 30 deletions lib/react-markdown.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import React from 'react'
import {VFile} from 'vfile'
import {unified} from 'unified'
import parse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import PropTypes from 'prop-types'
import {html} from 'property-information'
import rehypeFilter from './rehype-filter.js'
import {uriTransformer} from './uri-transformer.js'
import {childrenToReact} from './ast-to-react.js'

/**
* @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 {import('./rehype-filter.js').Options} FilterOptions
* @typedef {import('./ast-to-react.js').Options} TransformOptions
*
* @typedef CoreOptions
* @property {string} children
Expand All @@ -29,21 +18,28 @@ import {childrenToReact} from './ast-to-react.js'
* @property {string} [className]
*
* @typedef {CoreOptions & PluginOptions & LayoutOptions & FilterOptions & TransformOptions} ReactMarkdownOptions
*
* @typedef Deprecation
* @property {string} id
* @property {string} [to]
*/

import React from 'react'
import {VFile} from 'vfile'
import {unified} from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import PropTypes from 'prop-types'
import {html} from 'property-information'
import rehypeFilter from './rehype-filter.js'
import {uriTransformer} from './uri-transformer.js'
import {childrenToReact} from './ast-to-react.js'

const own = {}.hasOwnProperty
const changelog =
'https://github.com/remarkjs/react-markdown/blob/main/changelog.md'

/**
* @typedef Deprecation
* @property {string} id
* @property {string} [to]
*/

/**
* @type {Object.<string, Deprecation>}
*/
/** @type {Object.<string, Deprecation>} */
const deprecated = {
renderers: {to: 'components', id: 'change-renderers-to-components'},
astPlugins: {id: 'remove-buggy-html-in-markdown-parser'},
Expand Down Expand Up @@ -75,7 +71,6 @@ const deprecated = {
export 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 ${
Expand All @@ -87,14 +82,14 @@ export function ReactMarkdown(options) {
}

const processor = unified()
.use(parse)
.use(remarkParse)
// TODO: deprecate `plugins` in v7.0.0.
.use(options.remarkPlugins || options.plugins || [])
.use(remarkRehype, {allowDangerousHtml: true})
.use(options.rehypePlugins || [])
.use(rehypeFilter, options)

let file = new VFile()
const file = new VFile()

if (typeof options.children === 'string') {
file.value = options.children
Expand All @@ -104,8 +99,6 @@ export function ReactMarkdown(options) {
)
}

/** @type {Root} */
// @ts-expect-error we’ll throw if it isn’t a root next.
const hastNode = processor.runSync(processor.parse(file), file)

if (hastNode.type !== 'root') {
Expand All @@ -116,7 +109,7 @@ export function ReactMarkdown(options) {
let result = React.createElement(
React.Fragment,
{},
childrenToReact({options: options, schema: html, listDepth: 0}, hastNode)
childrenToReact({options, schema: html, listDepth: 0}, hastNode)
)

if (options.className) {
Expand All @@ -139,15 +132,13 @@ ReactMarkdown.propTypes = {
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,
Expand Down
58 changes: 24 additions & 34 deletions lib/rehype-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import {visit} from 'unist-util-visit'
* @param {Element|Root} parent
* @returns {boolean|undefined}
*
* @typedef RehypeFilterOptions
* @typedef Options
* @property {Array.<string>} [allowedElements]
* @property {Array.<string>} [disallowedElements=[]]
* @property {AllowElement} [allowElement]
* @property {boolean} [unwrapDisallowed=false]
*/

/**
* @type {import('unified').Plugin<[RehypeFilterOptions]>}
* @type {import('unified').Plugin<[Options], Root>}
*/
export default function rehypeFilter(options) {
if (options.allowedElements && options.disallowedElements) {
Expand All @@ -34,43 +34,33 @@ export default function rehypeFilter(options) {
options.allowElement
) {
return (tree) => {
const node = /** @type {Root} */ (tree)
visit(node, 'element', onelement)
}
}
visit(tree, 'element', (node, index, parent_) => {
const parent = /** @type {Element|Root} */ (parent_)
/** @type {boolean|undefined} */
let remove

/**
* @param {Node} node_
* @param {number|null|undefined} index
* @param {Node|null|undefined} parent_
* @returns {number|void}
*/
function onelement(node_, index, parent_) {
const node = /** @type {Element} */ (node_)
const parent = /** @type {Element|Root} */ (parent_)
/** @type {boolean|undefined} */
let remove
if (options.allowedElements) {
remove = !options.allowedElements.includes(node.tagName)
} else if (options.disallowedElements) {
remove = options.disallowedElements.includes(node.tagName)
}

if (options.allowedElements) {
remove = !options.allowedElements.includes(node.tagName)
} else if (options.disallowedElements) {
remove = options.disallowedElements.includes(node.tagName)
}
if (!remove && options.allowElement && typeof index === 'number') {
remove = !options.allowElement(node, index, parent)
}

if (!remove && options.allowElement && typeof index === 'number') {
remove = !options.allowElement(node, index, parent)
}
if (remove && typeof index === 'number') {
if (options.unwrapDisallowed && node.children) {
parent.children.splice(index, 1, ...node.children)
} else {
parent.children.splice(index, 1)
}

if (remove && typeof index === 'number') {
if (options.unwrapDisallowed && node.children) {
parent.children.splice(index, 1, ...node.children)
} else {
parent.children.splice(index, 1)
}
return index
}

return index
return undefined
})
}

return undefined
}
}
Loading

0 comments on commit 8737eac

Please sign in to comment.