slate-serializers
Advanced tools
Comparing version 0.0.9 to 0.0.10
export { htmlToSlate } from './serializers/htmlToSlate'; | ||
export { slateToDom, slateToHtml } from './serializers/slatetoHtml'; | ||
export { config as slateToDomConfig, Config as SlateToDomConfig } from './config/slatetoDom/default'; | ||
export { config as payloadSlateToDomConfig } from './config/slatetoDom/payload'; | ||
export { config as htmlToSlateConfig, Config as HtmlToSlateConfig } from './config/htmlToSlate/default'; | ||
export { config as payloadHtmlToSlateConfig } from './config/htmlToSlate/payload'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.slateToHtml = exports.slateToDom = exports.htmlToSlate = void 0; | ||
exports.payloadHtmlToSlateConfig = exports.htmlToSlateConfig = exports.payloadSlateToDomConfig = exports.slateToDomConfig = exports.slateToHtml = exports.slateToDom = exports.htmlToSlate = void 0; | ||
// Serializers | ||
var htmlToSlate_1 = require("./serializers/htmlToSlate"); | ||
@@ -9,1 +10,10 @@ Object.defineProperty(exports, "htmlToSlate", { enumerable: true, get: function () { return htmlToSlate_1.htmlToSlate; } }); | ||
Object.defineProperty(exports, "slateToHtml", { enumerable: true, get: function () { return slatetoHtml_1.slateToHtml; } }); | ||
// Configuration objects | ||
var default_1 = require("./config/slatetoDom/default"); | ||
Object.defineProperty(exports, "slateToDomConfig", { enumerable: true, get: function () { return default_1.config; } }); | ||
var payload_1 = require("./config/slatetoDom/payload"); | ||
Object.defineProperty(exports, "payloadSlateToDomConfig", { enumerable: true, get: function () { return payload_1.config; } }); | ||
var default_2 = require("./config/htmlToSlate/default"); | ||
Object.defineProperty(exports, "htmlToSlateConfig", { enumerable: true, get: function () { return default_2.config; } }); | ||
var payload_2 = require("./config/htmlToSlate/payload"); | ||
Object.defineProperty(exports, "payloadHtmlToSlateConfig", { enumerable: true, get: function () { return payload_2.config; } }); |
@@ -1,4 +0,2 @@ | ||
import { IattributeMap } from '../../types'; | ||
export declare const htmlToSlate: (html: string, { attributeMap, }?: { | ||
attributeMap?: IattributeMap[] | undefined; | ||
}) => undefined; | ||
import { Config } from '../../config/htmlToSlate/default'; | ||
export declare const htmlToSlate: (html: string, config?: Config) => undefined; |
@@ -9,31 +9,4 @@ "use strict"; | ||
const utilities_1 = require("../../utilities"); | ||
const ELEMENT_TAGS = { | ||
a: (el) => ({ | ||
type: 'link', | ||
newTab: el && (0, domutils_1.getAttributeValue)(el, 'target') === '_blank', | ||
url: el && (0, domutils_1.getAttributeValue)(el, 'href'), | ||
}), | ||
blockquote: () => ({ type: 'blockquote' }), | ||
h1: () => ({ type: 'h1' }), | ||
h2: () => ({ type: 'h2' }), | ||
h3: () => ({ type: 'h3' }), | ||
h4: () => ({ type: 'h4' }), | ||
h5: () => ({ type: 'h5' }), | ||
h6: () => ({ type: 'h6' }), | ||
li: () => ({ type: 'li' }), | ||
ol: () => ({ type: 'ol' }), | ||
p: () => ({ type: 'p' }), | ||
ul: () => ({ type: 'ul' }), | ||
}; | ||
const TEXT_TAGS = { | ||
code: () => ({ code: true }), | ||
pre: () => ({ code: true }), | ||
del: () => ({ strikethrough: true }), | ||
em: () => ({ italic: true }), | ||
i: () => ({ italic: true }), | ||
s: () => ({ strikethrough: true }), | ||
strong: () => ({ bold: true }), | ||
u: () => ({ underline: true }), | ||
}; | ||
const deserialize = (el, { attributeMap = [], } = {}) => { | ||
const default_1 = require("../../config/htmlToSlate/default"); | ||
const deserialize = (el, config = default_1.config) => { | ||
if (el.type !== htmlparser2_1.ElementType.Tag && el.type !== htmlparser2_1.ElementType.Text) { | ||
@@ -47,21 +20,11 @@ return null; | ||
const nodeName = (0, domutils_1.getName)(parent); | ||
const children = parent.childNodes ? parent.childNodes.map((node) => deserialize(node, { attributeMap })).flat() : []; | ||
const children = parent.childNodes ? parent.childNodes.map((node) => deserialize(node, config)).flat() : []; | ||
if ((0, domutils_1.getName)(parent) === 'body') { | ||
return (0, slate_hyperscript_1.jsx)('fragment', {}, children); | ||
} | ||
if (ELEMENT_TAGS[nodeName]) { | ||
let attrs = ELEMENT_TAGS[nodeName](parent); | ||
// tslint:disable-next-line no-unused-expression | ||
attributeMap.map((map) => { | ||
const value = (0, domutils_1.getAttributeValue)(parent, map.htmlAttr); | ||
if (value) { | ||
attrs = { | ||
[map.slateAttr]: value, | ||
...attrs, | ||
}; | ||
} | ||
}); | ||
if (config.elementTags[nodeName]) { | ||
const attrs = config.elementTags[nodeName](parent); | ||
return (0, slate_hyperscript_1.jsx)('element', attrs, children); | ||
} | ||
if (TEXT_TAGS[nodeName] || el.type === htmlparser2_1.ElementType.Text) { | ||
if (config.textTags[nodeName] || el.type === htmlparser2_1.ElementType.Text) { | ||
const text = (0, domutils_1.textContent)(el); | ||
@@ -75,3 +38,3 @@ if (!(0, utilities_1.hasLineBreak)(text) && text.trim() === '') { | ||
}; | ||
const gatherTextMarkAttributes = (el) => { | ||
const gatherTextMarkAttributes = (el, config = default_1.config) => { | ||
let allAttrs = {}; | ||
@@ -83,3 +46,3 @@ // tslint:disable-next-line no-unused-expression | ||
const name = (0, domutils_1.getName)(child); | ||
const attrs = TEXT_TAGS[name] ? TEXT_TAGS[name](child) : {}; | ||
const attrs = config.textTags[name] ? config.textTags[name](child) : {}; | ||
const text = (0, domutils_1.textContent)(child); | ||
@@ -95,3 +58,3 @@ allAttrs = { | ||
const name = (0, domutils_1.getName)(el); | ||
const attrs = TEXT_TAGS[name] ? TEXT_TAGS[name](el) : {}; | ||
const attrs = config.textTags[name] ? config.textTags[name](el) : {}; | ||
const text = (0, domutils_1.textContent)(el); | ||
@@ -105,3 +68,3 @@ allAttrs = { | ||
}; | ||
const htmlToSlate = (html, { attributeMap = [], } = {}) => { | ||
const htmlToSlate = (html, config = default_1.config) => { | ||
let slateContent; | ||
@@ -115,3 +78,3 @@ const handler = new domhandler_1.DomHandler((error, dom) => { | ||
slateContent = dom | ||
.map((node) => deserialize(node, { attributeMap })) // run the deserializer | ||
.map((node) => deserialize(node, config)) // run the deserializer | ||
.filter((element) => element) // filter out null elements | ||
@@ -118,0 +81,0 @@ .map((element) => { |
@@ -1,10 +0,7 @@ | ||
import { Document, Element } from 'domhandler'; | ||
import { IattributeMap } from '../../types'; | ||
export declare const slateToHtml: (node: any[], { enforceTopLevelPTags, attributeMap, }?: { | ||
enforceTopLevelPTags?: boolean | undefined; | ||
attributeMap?: IattributeMap[] | undefined; | ||
}) => string; | ||
export declare const slateToDom: (node: any[], { enforceTopLevelPTags, attributeMap, }?: { | ||
enforceTopLevelPTags?: boolean | undefined; | ||
attributeMap?: IattributeMap[] | undefined; | ||
}) => Document | Element | import("domhandler").Text; | ||
import { AnyNode } from 'domhandler'; | ||
import { Config } from '../../config/slatetoDom/default'; | ||
type SlateToHtml = (node: any[], config?: Config) => string; | ||
type SlateToDom = (node: any[], config?: Config) => AnyNode | ArrayLike<AnyNode>; | ||
export declare const slateToHtml: SlateToHtml; | ||
export declare const slateToDom: SlateToDom; | ||
export {}; |
@@ -9,26 +9,11 @@ "use strict"; | ||
const dom_serializer_1 = require("dom-serializer"); | ||
// Map Slate element names to HTML tag names | ||
// Only to be used for standard 'wrapper' elements | ||
const ELEMENT_NAME_TAG_MAP = new Map([ | ||
['p', 'p'], | ||
['paragraph', 'p'], | ||
['h1', 'h1'], | ||
['h2', 'h2'], | ||
['h3', 'h3'], | ||
['h4', 'h4'], | ||
['h5', 'h5'], | ||
['h6', 'h6'], | ||
['ul', 'ul'], | ||
['ol', 'ol'], | ||
['li', 'li'], | ||
['blockquote', 'blockquote'], | ||
]); | ||
const slateToHtml = (node, { enforceTopLevelPTags = false, attributeMap = [], } = {}) => { | ||
const document = (0, exports.slateToDom)(node, { attributeMap, enforceTopLevelPTags }); | ||
const default_1 = require("../../config/slatetoDom/default"); | ||
const slateToHtml = (node, config = default_1.config) => { | ||
const document = (0, exports.slateToDom)(node, config); | ||
return (0, dom_serializer_1.default)(document); | ||
}; | ||
exports.slateToHtml = slateToHtml; | ||
const slateToDom = (node, { enforceTopLevelPTags = false, attributeMap = [], } = {}) => { | ||
const slateToDom = (node, config = default_1.config) => { | ||
const nodeWithTopLevelPElements = node.map((el) => { | ||
if (!el.type && enforceTopLevelPTags) { | ||
if (!el.type && config.enforceTopLevelPTags) { | ||
return { | ||
@@ -42,53 +27,27 @@ ...el, | ||
const slateNode = { children: nodeWithTopLevelPElements }; | ||
const document = slateNodeToHtml(slateNode, { attributeMap }); | ||
const document = slateNodeToHtml(slateNode, config); | ||
return document; | ||
}; | ||
exports.slateToDom = slateToDom; | ||
const slateNodeToHtml = (node, { attributeMap = [], } = {}) => { | ||
const slateNodeToHtml = (node, config = default_1.config) => { | ||
if (slate_1.Text.isText(node)) { | ||
const str = (0, html_escaper_1.escape)(node.text); | ||
const markElements = []; | ||
if (node.strikethrough) { | ||
markElements.push('s'); | ||
} | ||
if (node.bold) { | ||
markElements.push('strong'); | ||
} | ||
if (node.underline) { | ||
markElements.push('u'); | ||
} | ||
if (node.italic) { | ||
markElements.push('i'); | ||
} | ||
if (node.code) { | ||
markElements.push('pre', 'code'); | ||
} | ||
Object.keys(config.markMap).forEach((key) => { | ||
if (node[key]) { | ||
markElements.push(...config.markMap[key]); | ||
} | ||
}); | ||
return (0, domhandler_2.nestedMarkElements)(markElements, str); | ||
} | ||
const children = node.children ? node.children.map((n) => slateNodeToHtml(n, { attributeMap })) : []; | ||
const attrs = {}; | ||
// tslint:disable-next-line no-unused-expression | ||
attributeMap.forEach((map) => { | ||
if (node[map.slateAttr]) { | ||
attrs[map.htmlAttr] = node[map.slateAttr]; | ||
} | ||
}); | ||
if (ELEMENT_NAME_TAG_MAP.has(node.type)) { | ||
return new domhandler_1.Element(ELEMENT_NAME_TAG_MAP.get(node.type) || '', attrs, children); | ||
const children = node.children ? node.children.map((n) => slateNodeToHtml(n, config)) : []; | ||
// straightforward node to element | ||
if (config.elementMap[node.type]) { | ||
return new domhandler_1.Element(config.elementMap[node.type], {}, children); | ||
} | ||
switch (node.type) { | ||
case 'quote': | ||
const p = [new domhandler_1.Element('p', {}, children)]; | ||
return new domhandler_1.Element('blockquote', attrs, p); | ||
case 'link': | ||
if (node.newTab) { | ||
attrs.target = '_blank'; | ||
} | ||
return new domhandler_1.Element('a', { | ||
href: (0, html_escaper_1.escape)(node.url), | ||
...attrs, | ||
}, children); | ||
default: | ||
return new domhandler_1.Document(children); | ||
// more complex transforms | ||
if (config.elementTransforms[node.type]) { | ||
return config.elementTransforms[node.type](node, children); | ||
} | ||
return new domhandler_1.Document(children); | ||
}; |
{ | ||
"name": "slate-serializers", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"description": "Serialize Slate JSON objects to HTML and vice versa. Define rules to modify the end result.", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
105
README.md
@@ -19,4 +19,10 @@ # slate-serializers | ||
Example usage: | ||
## Usage | ||
The following examples use a default configuration, which may not transform your data effectively. | ||
One of the principles of Slate is its [**schema-less core**](https://docs.slatejs.org/#principles). | ||
Refer to the [Details](#details) section to learn how to modify the configuration to include your schema/rules. | ||
```ts | ||
@@ -52,5 +58,23 @@ import { slateToHtml, htmlToSlate } from 'slate-serializers' | ||
Both serializers support an `attributeMap` option, which maps Slate attributes to HTML attributes and vice versa. This is supported for element tags only. | ||
## Details | ||
### slateToDom | ||
`slateToHtml` is a simple wrapper that runs [`dom-serializer`](https://www.npmjs.com/package/dom-serializer) on the output from `slateToDom`. | ||
`slateToDom` is made available in case you wish to work woth the DOM output yourself or run `dom-serializer` using any of the available options. | ||
It accepts the same configuration object as [slateToHtml](#slatetohtml). | ||
### slateToHtml | ||
#### Configuration | ||
By default, `slateToHtml` incorporates transformation rules based on the example in [Deserializing | Serializing | Slate](https://docs.slatejs.org/concepts/10-serializing#deserializing). | ||
If you are using [Payload CMS](https://payloadcms.com/), you are in luck. Import the Payload configuration file and pass it as a parameter to the serializer. | ||
```ts | ||
import { payloadSlateToDomConfig } from 'slate-serializers' | ||
const slate = [ | ||
@@ -60,54 +84,16 @@ { | ||
{ | ||
type: 'link', | ||
linkType: "custom", | ||
url: 'https://github.com/thompsonsj/slate-serializers', | ||
newTab: true, | ||
children: [ | ||
{ | ||
text: 'slate-serializers | GitHub', | ||
}, | ||
], | ||
text: 'Heading 1', | ||
}, | ||
], | ||
type: 'p', | ||
} | ||
type: 'h1', | ||
}, | ||
] | ||
const html = slateToHtml(slate, | ||
{ | ||
attributeMap: [ | ||
{ | ||
slateAttr: 'linkType', | ||
htmlAttr: 'data-link-type' | ||
} | ||
] | ||
} | ||
) | ||
// output | ||
// <p><a href="https://github.com/thompsonsj/slate-serializers" target="_blank" data-link-type="custom">slate-serializers | GitHub</a></p> | ||
// using the same attributeMap for htmlToSlate will ensure the linkType attribute is preserved in the Slate JSON object. | ||
const slateReserialized = htmlToSlate(html, | ||
{ | ||
attributeMap: [ | ||
{ | ||
slateAttr: 'linkType', | ||
htmlAttr: 'data-link-type' | ||
} | ||
] | ||
} | ||
) | ||
const serializedToHtml = slateToHtml(slate, payloadSlateToDomConfig) | ||
``` | ||
## Details | ||
You can create your own configuration file that implements your schema. See [src/config/slatetoDom/payload.ts](src/config/slatetoDom/payload.ts) for an example of how to extend the default configuration or copy [src/config/slatetoDom/default.ts](src/config/slatetoDom/default.ts) and rewrite it as appropriate. | ||
### slateToDom | ||
#### Implementation details | ||
`slateToHtml` is a simple wrapper that runs [`dom-serializer`](https://www.npmjs.com/package/dom-serializer) on the output from `slateToDom`. | ||
`slateToDom` is made available in case you wish to work woth the DOM output yourself or run `dom-serializer` using any of the available options. | ||
### slateToHtml | ||
Based on logic in [Deserializing | Serializing | Slate](https://docs.slatejs.org/concepts/10-serializing#deserializing). | ||
@@ -123,2 +109,29 @@ | ||
#### Configuration | ||
By default, `htmlToSlate` incorporates transformation rules based on the example in [HTML | Serializing | Slate](https://docs.slatejs.org/concepts/10-serializing#html). | ||
If you are using [Payload CMS](https://payloadcms.com/), you are in luck. Import the Payload configuration file and pass it as a parameter to the serializer. | ||
```ts | ||
import { payloadHtmlToSlateConfig } from 'slate-serializers' | ||
const slate = [ | ||
{ | ||
children: [ | ||
{ | ||
text: 'Heading 1', | ||
}, | ||
], | ||
type: 'h1', | ||
}, | ||
] | ||
const serializedToHtml = slateToHtml(slate, payloadHtmlToSlateConfig) | ||
``` | ||
You can create your own configuration file that implements your schema. See [src/config/htmlToSlate/payload.ts](src/config/htmlToSlate/payload.ts) for an example of how to extend the default configuration or copy [src/config/htmlToSlate/default.ts](src/config/htmlToSlate/default.ts) and rewrite it as appropriate. | ||
#### Implementation details | ||
Based on logic in [HTML | Serializing | Slate](https://docs.slatejs.org/concepts/10-serializing#html). | ||
@@ -125,0 +138,0 @@ |
36581
32
937
149