Skip to content

Commit

Permalink
refactor: moving things around
Browse files Browse the repository at this point in the history
  • Loading branch information
quantizor committed Apr 19, 2024
1 parent aa020c5 commit 13f1470
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 81 deletions.
9 changes: 6 additions & 3 deletions index.cjs.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import Markdown, { compiler } from './'
Object.assign(Markdown, { compiler })
export default Markdown as typeof Markdown & { compiler: typeof compiler }
import Markdown, { createMarkdown } from './'

Object.assign(Markdown, { createMarkdown })
export default Markdown as typeof Markdown & {
createMarkdown: typeof createMarkdown
}
167 changes: 89 additions & 78 deletions index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,30 @@ function attributeValueToJSXPropValue(
return value
}

function attrStringToMap(str: string): JSX.IntrinsicAttributes {
const attributes = str.match(ATTR_EXTRACTOR_R)
if (!attributes) {
return null
}

return attributes.reduce(function (map, raw, index) {
const delimiterIdx = raw.indexOf('=')

if (delimiterIdx !== -1) {
const key = raw
.slice(0, delimiterIdx)
.trim() as keyof React.AllHTMLAttributes<Element>
const value = unquote(raw.slice(delimiterIdx + 1).trim())

map[key] = attributeValueToJSXPropValue(key, value)
} else if (raw !== 'style') {
map[raw] = true
}

return map
}, {})
}

function normalizeWhitespace(source: string): string {
return source
.replace(CR_NEWLINE_R, '\n')
Expand Down Expand Up @@ -930,7 +954,10 @@ function captureNothing() {
return {}
}

function reactOutput(options: MarkdownToJSX.Options) {
function reactOutput(
options: MarkdownToJSX.Options,
compiler: (input: string) => React.ReactNode
) {
const createElementFn = options.createElement || React.createElement

// JSX custom pragma
Expand All @@ -957,6 +984,20 @@ function reactOutput(options: MarkdownToJSX.Options) {
)
}

function finalizeAttrs(attrs: JSX.IntrinsicAttributes) {
for (const key in attrs) {
if (
typeof attrs[key] === 'string' &&
(HTML_BLOCK_ELEMENT_R.test(attrs[key]) ||
HTML_SELF_CLOSING_ELEMENT_R.test(attrs[key]))
) {
attrs[key] = compiler(attrs[key].trim())
}
}

return attrs
}

return function (
node: MarkdownToJSX.ParserResult,
/**
Expand Down Expand Up @@ -1045,14 +1086,14 @@ function reactOutput(options: MarkdownToJSX.Options) {

case RuleType.htmlBlock: {
return (
<node.tag key={context.key} {...node.attrs}>
<node.tag key={context.key} {...finalizeAttrs(node.attrs)}>
{node.text || output(node.children, context)}
</node.tag>
)
}

case RuleType.htmlSelfClosing: {
return <node.tag {...node.attrs} key={context.key} />
return <node.tag {...finalizeAttrs(node.attrs)} key={context.key} />
}

case RuleType.image: {
Expand Down Expand Up @@ -1229,13 +1270,16 @@ function reactFor(render) {
}
}

function createRenderer(options: MarkdownToJSX.Options) {
function createRenderer(
options: MarkdownToJSX.Options,
compiler: (input: string) => React.ReactNode
) {
return function renderRule(
ast: MarkdownToJSX.ParserResult,
render: MarkdownToJSX.RuleOutput,
context: MarkdownToJSX.Context
): React.ReactNode {
const renderer = reactOutput(options)
const renderer = reactOutput(options, compiler)

return options.renderRule
? options.renderRule(
Expand Down Expand Up @@ -1321,74 +1365,6 @@ export function createMarkdown(options: MarkdownToJSX.Options = {}) {
return inline
}

function attrStringToMap(str: string): JSX.IntrinsicAttributes {
const attributes = str.match(ATTR_EXTRACTOR_R)
if (!attributes) {
return null
}

return attributes.reduce(function (map, raw, index) {
const delimiterIdx = raw.indexOf('=')

if (delimiterIdx !== -1) {
const key = raw
.slice(0, delimiterIdx)
.trim() as keyof React.AllHTMLAttributes<Element>
const value = unquote(raw.slice(delimiterIdx + 1).trim())

const normalizedValue = (map[key] = attributeValueToJSXPropValue(
key,
value
))

if (
typeof normalizedValue === 'string' &&
(HTML_BLOCK_ELEMENT_R.test(normalizedValue) ||
HTML_SELF_CLOSING_ELEMENT_R.test(normalizedValue))
) {
map[key] = React.cloneElement(compiler(normalizedValue.trim()), {
key: index,
})
}
} else if (raw !== 'style') {
map[raw] = true
}

return map
}, {})
}

function compiler(input: string = '') {
const inline = isInline(input)
const { ast, context } = parser(input)
const arr = emitter(ast, context)
const createElementFn = options.createElement || React.createElement

while (
typeof arr[arr.length - 1] === 'string' &&
!arr[arr.length - 1].trim()
) {
arr.pop()
}

if (options.wrapper === null) {
return arr
}

const wrapper = options.wrapper || (inline ? 'span' : 'div')
let jsx

if (arr.length > 1 || options.forceWrapper) {
jsx = arr
} else if (arr.length === 1) {
return arr[0]
} else {
return null
}

return createElementFn(wrapper, { key: 'outer' }, jsx)
}

/**
* each rule's react() output function goes through our custom
* h() JSX pragma; this allows the override functionality to be
Expand Down Expand Up @@ -1888,7 +1864,38 @@ export function createMarkdown(options: MarkdownToJSX.Options = {}) {
return { ast, context }
}

const emitter: Function = reactFor(createRenderer(options))
function compiler(input: string = ''): React.ReactNode {
const inline = isInline(input)
const { ast, context } = parser(input)
const arr = emitter(ast, context)
const createElementFn = options.createElement || React.createElement

while (
typeof arr[arr.length - 1] === 'string' &&
!arr[arr.length - 1].trim()
) {
arr.pop()
}

if (options.wrapper === null) {
return arr
}

const wrapper = options.wrapper || (inline ? 'span' : 'div')
let jsx

if (arr.length > 1 || options.forceWrapper) {
jsx = arr
} else if (arr.length === 1) {
return arr[0]
} else {
return null
}

return createElementFn(wrapper, { key: 'outer' }, jsx)
}

const emitter: Function = reactFor(createRenderer(options, compiler))

function Markdown({
children = '',
Expand All @@ -1908,9 +1915,13 @@ export function createMarkdown(options: MarkdownToJSX.Options = {}) {

const result = compiler(children)

return React.isValidElement(result)
? React.cloneElement(compiler(children), props as JSX.IntrinsicAttributes)
: result
return React.createElement(
React.Fragment,
{},
React.isValidElement(result)
? React.cloneElement(result, props as JSX.IntrinsicAttributes)
: result
)
}

return {
Expand All @@ -1934,7 +1945,7 @@ function Markdown(props: {
[props.options]
)

return React.createElement(M, props)
return M(props)
}

export namespace MarkdownToJSX {
Expand Down

0 comments on commit 13f1470

Please sign in to comment.