react.jsx
4.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import React from 'react'
import { ELEMENT_NODE, TEXT_NODE } from 'ultrahtml'
import { parseHtml, createMatcher, findNode } from 'astro-wt/html'
import { decode } from 'html-entities'
export const ReparseStaticChildren = (replacements, Component) => (props) => {
const { children = {}, ...rest } = props
const { props: { value: staticHtml } = {} } = children
if (!staticHtml) return <Component {...props}/>
const bodyToParse = String(staticHtml)
const ultra = Replace({
debug: 2,
html: bodyToParse,
replacements,
})
return <Component {...rest}>{ultra}</Component>
}
export const fixAttributes = (attributes) => {
const { class: className, srcset: srcSet, maxlength: maxLength, for: htmlFor, ...rest } = attributes
const result = rest
if (className !== undefined) result.className = className
if (srcSet !== undefined) result.srcSet = srcSet
if (maxLength !== undefined) result.maxLength = maxLength
if (htmlFor !== undefined) result.htmlFor = htmlFor
return result
return Object.fromEntries(Object.entries(result).map(([ key, value ]) => {
return [ key, decode(value) ]
}))
}
export const CreateReplacement = (Element, propsOrCreator) => (matchOptions) => {
const { debug, parent, node, index, replacers } = matchOptions
const props = propsOrCreator instanceof Function ? propsOrCreator(matchOptions) : propsOrCreator
return (
<Element key={index} {...fixAttributes({...node.attributes, ...props})}>
{Children({ debug, parent, children: node.children, replacers})}
</Element>
)
}
export const DeleteHandler = () => null
export const Replace = (props) => {
const { debug = 0, html, xpath, replacements } = props
const doc = props.node ? props.node : parseHtml(html, { react: false })
const node = xpath ? findNode(doc, xpath) : doc
const replacers = Object.entries(replacements).map(([ selector, Handler ]) => [ createMatcher(selector), Handler ])
const nextDebug = debug ? debug - 1 : 0
if (debug) console.log('Replace', { html, replacers, node })
const result = Match({ debug: nextDebug, node, replacers })
if (debug) console.log('Replace result', result)
return result
}
export const Match = (props) => {
const { debug = 0, parent = null, node, index = 0, replacers } = props
const nextDebug = debug ? debug - 1 : 0
for (const [ matcher, Handler ] of replacers) {
if (matcher(node, parent, index, false)) {
return Handler({ debug: nextDebug, parent, node, index, replacers })
}
}
if (debug) console.log('Match:nothing', {node})
return Node({ debug: nextDebug, parent, node, index, replacers })
}
export const RAW_TAGS = new Set(['script', 'style'])
export const Node = (props) => {
const { debug = 0, parent, node, index, replacers } = props
const { name: Name, attributes } = node
const nextDebug = debug ? debug - 1 : 0
if (node.type === TEXT_NODE) {
if (debug) console.log('Node:text', { value: node.value })
return node.value ? decode(node.value) : null
//return <React.Fragment dangerouslySetInnerHTML={{ __html: node.value }}/>
} else if (node.type === ELEMENT_NODE) {
const elementProps = fixAttributes(attributes)
if (node.isSelfClosingTag) {
if (debug) console.log('Node:selfClosing', { node })
return <Name key={index} {...elementProps}/>
} else {
if (debug) console.log('Node:element', { node, children: node.children })
let children = node.children
if (children.length === 1) {
const [ firstChild ] = children
if (firstChild.type === TEXT_NODE && !firstChild.value) children = null
}
if (Name === 'astro-island') console.log('astro-island', { attributes, elementProps })
if (Name === 'script') console.log('script', { node, children })
if (RAW_TAGS.has(Name) && children) {
if (Array.isArray(children) && children.length === 1) {
return <Name key={index} {...elementProps} dangerouslySetInnerHTML={{ __html: children[ 0 ].value } }/>
}
}
return (
<Name key={index} {...elementProps} children={children && Children({ debug: nextDebug, parent: node, children: node.children, replacers})}/>
)
}
} else {
if (debug) console.log('Node:children', { children: node.children })
return Children({ debug: nextDebug, parent: node, children: node.children, replacers })
}
}
export const Children = (props) => {
const { debug = 0, parent, children, replacers } = props
const nextDebug = debug ? debug - 1 : 0
if (Array.isArray(children)) {
const result = children.map((child, index) => {
return Match({ debug: nextDebug, parent, node: child, index, replacers })
})
if (result.length === 1) return result[0]
if (result.length === 0) return null
return result
} else if (!children) {
return ''
} else {
return Node({ debug: nextDebug, parent, node: children, index: 0, replacers })
}
}