DatoCMS
The most complete, user-friendly and performant Headless CMS.
The most complete, user-friendly and performant Headless CMS.
tag.
async function p(createDastNode, hastNode, context) {
return createDastNode('paragraph', {
children: await visitChildren(createDastNode, hastNode, context),
});
}
```
Handlers can return either a promise that resolves to a `dast` node, an array of `dast` Nodes or `undefined` to skip the current node.
To ensure that a valid `dast` is generated the default handlers also check that the current `hastNode` is a valid `dast` node for its parent and, if not, they ignore the current node and continue visiting its children.
Information about the parent `dast` node name is available in `context.parentNodeType`.
Please take a look at the [default handlers implementation](./handlers.ts) for examples.
The default handlers are available on `context.defaultHandlers`.
### context
Every handler receives a `context` object that includes the following information:
```js
export interface GlobalContext {
// Whether the library has found a convert this to an h1 to
findAll(tree, (node) => {
if (node.type === 'element' && node.tagName === 'p') {
node.tagName = 'h1';
}
});
},
}).then((structuredText) => {
console.log(structuredText);
});
```
### Examples
Split a node that contains an image.
In `dast` images can be presented as `Block` nodes but these are not allowed inside of `ListItem` nodes (ul/ol lists). In this example we will split the list in 3 pieces and lift up the image.
The same approach can be used to split other types of branches and lift up nodes to become root nodes.
```js
import { visit } from 'unist-utils-core';
const html = `
`;
const dast = await htmlToStructuredText(html, {
preprocess: (tree) => {
const liftedImages = new WeakSet();
const body = find(tree, (node) => node.tagName === 'body');
visit(body, (node, index, parents) => {
if (
!node ||
node.tagName !== 'img' ||
liftedImages.has(node) ||
parents.length === 1 // is a top level img
) {
return;
}
// remove image
const imgParent = parents[parents.length - 1];
imgParent.children.splice(index, 1);
let i = parents.length;
let splitChildrenIndex = index;
let childrenAfterSplitPoint = [];
while (--i > 0) {
// Example: i == 2
// [ 'body', 'div', 'h1' ]
const /* h1 */ parent = parents[i];
const /* div */ parentsParent = parents[i - 1];
// Delete the siblings after the image and save them in a variable
childrenAfterSplitPoint /* [ 'h1.2' ] */ = parent.children.splice(
splitChildrenIndex,
);
// parent.children is now == [ 'h1.1' ]
// parentsParent.children = [ 'h1' ]
splitChildrenIndex = parentsParent.children.indexOf(parent);
// splitChildrenIndex = 0
let nodeInserted = false;
// If we reached the 'div' add the image's node
if (i === 1) {
splitChildrenIndex += 1;
parentsParent.children.splice(splitChildrenIndex, 0, node);
liftedImages.add(node);
nodeInserted = true;
}
splitChildrenIndex += 1;
// Create a new branch with childrenAfterSplitPoint if we have any i.e.
// 
h1.2
if (childrenAfterSplitPoint.length > 0) {
parentsParent.children.splice(splitChildrenIndex, 0, {
...parent,
children: childrenAfterSplitPoint,
});
}
// Remove the parent if empty
if (parent.children.length === 0) {
splitChildrenIndex -= 1;
parentsParent.children.splice(
nodeInserted ? splitChildrenIndex - 1 : splitChildrenIndex,
1,
);
}
}
});
},
handlers: {
img: async (createNode, node, context) => {
// In a real scenario you would upload the image to Dato and get back an id.
const item = '123';
return createNode('block', {
item,
});
},
},
});
```
Lift up an image node
```js
import { visit, CONTINUE } from 'unist-utils-core';
const html = `
`;
const dast = await htmlToStructuredText(html, {
preprocess: (tree) => {
visit(tree, (node, index, parents) => {
if (node.tagName === 'img' && parents.length > 1) {
const parent = parents[parents.length - 1];
tree.children.push(node);
parent.children.splice(index, 1);
return [CONTINUE, index];
}
});
},
handlers: {
img: async (createNode, node, context) => {
// In a real scenario you would upload the image to Dato and get back an id.
const item = '123';
return createNode('block', { item });
},
},
});
```
item 2