Skip to content

Instantly share code, notes, and snippets.

@vramdal
Created March 16, 2018 12:33
Show Gist options
  • Save vramdal/ac326a5bf5a4f2755dfe5e64125fceb1 to your computer and use it in GitHub Desktop.
Save vramdal/ac326a5bf5a4f2755dfe5e64125fceb1 to your computer and use it in GitHub Desktop.
const objectAssign = require('object-assign')
const getImageUrl = require('./getImageUrl')
var serializerMap = {};
module.exports = h => {
if (serializerMap.h) {
return serializerMap.h;
}
// Low-level block serializer
function BlockSerializer(props) {
const {node, serializers, options, isInline, children} = props
const blockType = node._type
const serializer = serializers.types[blockType]
if (!serializer) {
throw new Error(
`Unknown block type "${blockType}", please specify a serializer for it in the \`serializers.types\` prop`
)
}
return h(serializer, {node, options, isInline}, children)
}
// Low-level span serializer
function SpanSerializer(props) {
const {mark, children} = props.node
const isPlain = typeof mark === 'string'
const markType = isPlain ? mark : mark._type
const serializer = props.serializers.marks[markType]
if (!serializer) {
// @todo Revert back to throwing errors?
// eslint-disable-next-line no-console
console.warn(
`Unknown mark type "${markType}", please specify a serializer for it in the \`serializers.marks\` prop`
)
return h('span', null, children)
}
return h(serializer, props.node, children)
}
// Low-level list serializer
function ListSerializer(props) {
const tag = props.type === 'bullet' ? 'ul' : 'ol'
return h(tag, null, props.children)
}
// Low-level list item serializer
function ListItemSerializer(props) {
return h('li', null, props.children)
}
// Renderer of an actual block of type `block`. Confusing, we know.
function BlockTypeSerializer(props) {
const style = props.node.style || 'normal'
if (/^h\d/.test(style)) {
return h(style, null, props.children)
}
return style === 'blockquote'
? h('blockquote', null, props.children)
: h('p', null, props.children)
}
// Serializers for things that can be directly attributed to a tag without any props
// We use partial application to do this, passing the tag name as the first argument
function RawMarkSerializer(tag, props) {
return h(tag, null, props.children)
}
function UnderlineSerializer(props) {
return h('span', {style: {textDecoration: 'underline'}}, props.children)
}
function StrikeThroughSerializer(props) {
return h('del', null, props.children)
}
function LinkSerializer(props) {
return h('a', {href: props.mark.href}, props.children)
}
function ImageSerializer(props) {
const img = h('img', {src: getImageUrl(props)})
return props.isInline ? img : h('figure', null, img)
}
// Serializer that recursively calls itself, producing a hyperscript tree of spans
function serializeSpan(span, serializers, index, options) {
if (span === '\n' && serializers.hardBreak) {
return h(serializers.hardBreak, {key: `hb-${index}`})
}
if (typeof span === 'string') {
return span
}
let children
if (span.children) {
children = {
children: span.children.map((child, i) =>
options.serializeNode(child, i, span.children, true)
)
}
}
const serializedNode = objectAssign({}, span, children)
return h(serializers.span, {
key: span._key || `span-${index}`,
node: serializedNode,
serializers
})
}
const HardBreakSerializer = () => h('br')
const defaultMarkSerializers = {
strong: RawMarkSerializer.bind(null, 'strong'),
em: RawMarkSerializer.bind(null, 'em'),
code: RawMarkSerializer.bind(null, 'code'),
underline: UnderlineSerializer,
'strike-through': StrikeThroughSerializer,
link: LinkSerializer
}
const defaultSerializers = {
// Common overrides
types: {
block: BlockTypeSerializer,
image: ImageSerializer
},
marks: defaultMarkSerializers,
// Less common overrides
list: ListSerializer,
listItem: ListItemSerializer,
block: BlockSerializer,
span: SpanSerializer,
hardBreak: HardBreakSerializer
}
let returnValue = {
defaultSerializers,
serializeSpan
};
serializerMap.h = returnValue;
return returnValue
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment