datocms-html-to-structured-text
Version:
Convert HTML (or a `hast` syntax tree) to a valid DatoCMS Structured Text `dast` document
109 lines (95 loc) • 2.85 kB
text/typescript
/* eslint-disable @typescript-eslint/ban-ts-comment */
// @ts-nocheck
// @ts-ignore
import minify from 'rehype-minify-whitespace';
import { CreateNodeFunction, Handler, HastRootNode } from './types';
import visitNode from './visit-node';
import visitChildren from './visit-children';
import { handlers } from './handlers';
import parse5 from 'parse5';
import parse5DocumentToHast from 'hast-util-from-parse5';
import documentToHast from 'hast-util-from-dom';
import {
Document,
defaultMarks,
Mark,
BlockquoteType,
CodeType,
HeadingType,
LinkType,
ListType,
Heading,
} from 'datocms-structured-text-utils';
export type Options = Partial<{
newlines: boolean;
handlers: Record<string, Handler>;
preprocess: (hast: HastRootNode) => void;
allowedBlocks: Array<
BlockquoteType | CodeType | HeadingType | LinkType | ListType
>;
allowedHeadingLevels: Heading['level'][];
allowedMarks: Mark[];
}>;
export async function htmlToStructuredText(
html: string,
options: Options = {},
): Promise<Document | null> {
if (typeof DOMParser === 'undefined') {
throw new Error(
'DOMParser is not available. Consider using `parse5ToStructuredText` instead!',
);
}
const document = new DOMParser().parseFromString(html, 'text/html');
const tree = documentToHast(document);
return hastToStructuredText(tree, options);
}
export async function parse5ToStructuredText(
document: parse5.Document,
options: Options = {},
): Promise<Document | null> {
const tree = parse5DocumentToHast(document);
return hastToStructuredText(tree, options);
}
export async function hastToStructuredText(
tree: HastRootNode,
options: Options = {},
): Promise<Document | null> {
minify({ newlines: options.newlines === true })(tree);
const createNode: CreateNodeFunction = (type, props) => {
props.type = type;
return props;
};
if (typeof options.preprocess === 'function') {
options.preprocess(tree);
}
const rootNode = await visitNode(createNode, tree, {
parentNodeType: 'root',
parentNode: null,
defaultHandlers: handlers,
handlers: Object.assign({}, handlers, options.handlers || {}),
wrapText: true,
allowedBlocks: Array.isArray(options.allowedBlocks)
? options.allowedBlocks
: ['blockquote', 'code', 'heading', 'link', 'list'],
allowedMarks: Array.isArray(options.allowedMarks)
? options.allowedMarks
: defaultMarks,
allowedHeadingLevels: Array.isArray(options.allowedHeadingLevels)
? options.allowedHeadingLevels
: [1, 2, 3, 4, 5, 6],
global: {
baseUrl: null,
baseUrlFound: false,
...(options.shared || {}),
},
});
if (rootNode) {
return {
schema: 'dast',
document: rootNode,
};
}
return null;
}
export { visitNode, visitChildren };
export * from './types';