UNPKG

datocms-html-to-structured-text

Version:

Convert HTML (or a `hast` syntax tree) to a valid DatoCMS Structured Text `dast` document

550 lines 25.2 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-nocheck import convert from 'hast-util-is-element/convert'; import toText from 'hast-util-to-text'; import has from 'hast-util-has-property'; import { allowedChildren, inlineNodeTypes, } from 'datocms-structured-text-utils'; import visitChildren from './visit-children'; import { wrap } from './wrap'; export var root = function root(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var children; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, visitChildren(createNode, node, __assign(__assign({}, context), { parentNodeType: 'root' }))]; case 1: children = _a.sent(); if (Array.isArray(children) && children.some(function (child) { return child && !allowedChildren.root.includes(child.type); })) { children = wrap(children); } if (!Array.isArray(children) || children.length === 0) { return [2 /*return*/, null]; } return [2 /*return*/, createNode('root', { children: Array.isArray(children) ? children : [], })]; } }); }); }; export var paragraph = function paragraph(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var isAllowedChild, children; return __generator(this, function (_a) { switch (_a.label) { case 0: isAllowedChild = allowedChildren[context.parentNodeType].includes('paragraph'); return [4 /*yield*/, visitChildren(createNode, node, __assign(__assign({}, context), { parentNodeType: isAllowedChild ? 'paragraph' : context.parentNodeType }))]; case 1: children = _a.sent(); if (Array.isArray(children) && children.length) { return [2 /*return*/, isAllowedChild ? createNode('paragraph', { children: children }) : children]; } return [2 /*return*/, undefined]; } }); }); }; export var thematicBreak = function thematicBreak(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var isAllowedChild; return __generator(this, function (_a) { isAllowedChild = allowedChildren[context.parentNodeType].includes('thematicBreak'); return [2 /*return*/, isAllowedChild ? createNode('thematicBreak', {}) : undefined]; }); }); }; export var heading = function heading(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var level, isAllowedChild, children; return __generator(this, function (_a) { switch (_a.label) { case 0: level = Number(node.tagName.charAt(1)) || 1; isAllowedChild = allowedChildren[context.parentNodeType].includes('heading') && context.allowedBlocks.includes('heading') && context.allowedHeadingLevels.includes(level); return [4 /*yield*/, visitChildren(createNode, node, __assign(__assign({}, context), { parentNodeType: isAllowedChild ? 'heading' : context.parentNodeType, wrapText: isAllowedChild ? false : context.wrapText }))]; case 1: children = _a.sent(); if (Array.isArray(children) && children.length) { return [2 /*return*/, isAllowedChild ? createNode('heading', { level: level, children: children, }) : children]; } return [2 /*return*/, undefined]; } }); }); }; export var code = function code(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var isAllowedChild, prefix, isPre, isCode, children, index, classList, language; return __generator(this, function (_a) { isAllowedChild = allowedChildren[context.parentNodeType].includes('code'); if (!isAllowedChild) { return [2 /*return*/, inlineCode(createNode, node, context)]; } if (!context.allowedBlocks.includes('code')) { return [2 /*return*/, visitChildren(createNode, node, context)]; } prefix = typeof context.codePrefix === 'string' ? context.codePrefix : 'language-'; isPre = convert('pre'); isCode = convert('code'); children = node.children; index = -1; classList = null; language = {}; if (isPre(node)) { while (++index < children.length) { if (typeof children[index] === 'object' && isCode(children[index]) && has(children[index], 'className')) { // error TS2339: Property 'properties' does not exist on type 'HastNode'. // Property 'properties' does not exist on type 'HastTextNode' // isCode (convert) checks that the node is an element and therefore it'll have properties // @ts-ignore classList = children[index].properties.className; break; } } } else if (isCode(node) && has(node, 'className')) { classList = node.properties.className; } if (Array.isArray(classList)) { index = -1; while (++index < classList.length) { if (classList[index].slice(0, prefix.length) === prefix) { language = { language: classList[index].slice(prefix.length) }; break; } } } return [2 /*return*/, createNode('code', __assign(__assign({}, language), { code: String(wrapText(context, toText(node))).replace(/\n+$/, '') }))]; }); }); }; export var blockquote = function blockquote(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var isAllowedChild, children; return __generator(this, function (_a) { switch (_a.label) { case 0: isAllowedChild = allowedChildren[context.parentNodeType].includes('blockquote') && context.allowedBlocks.includes('blockquote'); return [4 /*yield*/, visitChildren(createNode, node, __assign(__assign({}, context), { parentNodeType: isAllowedChild ? 'blockquote' : context.parentNodeType }))]; case 1: children = _a.sent(); if (Array.isArray(children) && children.length) { return [2 /*return*/, isAllowedChild ? createNode('blockquote', { children: wrap(children) }) : children]; } return [2 /*return*/, undefined]; } }); }); }; export var list = function list(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var isAllowedChild, children; return __generator(this, function (_a) { switch (_a.label) { case 0: isAllowedChild = allowedChildren[context.parentNodeType].includes('list') && context.allowedBlocks.includes('list'); if (!!isAllowedChild) return [3 /*break*/, 2]; return [4 /*yield*/, visitChildren(createNode, node, context)]; case 1: return [2 /*return*/, _a.sent()]; case 2: return [4 /*yield*/, wrapListItems(createNode, node, __assign(__assign({}, context), { parentNodeType: 'list' }))]; case 3: children = _a.sent(); if (Array.isArray(children) && children.length) { return [2 /*return*/, createNode('list', { children: children, style: node.tagName === 'ol' ? 'numbered' : 'bulleted', })]; } return [2 /*return*/, undefined]; } }); }); }; export var listItem = function listItem(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var isAllowedChild, children; return __generator(this, function (_a) { switch (_a.label) { case 0: isAllowedChild = allowedChildren[context.parentNodeType].includes('listItem') && context.allowedBlocks.includes('list'); return [4 /*yield*/, visitChildren(createNode, node, __assign(__assign({}, context), { parentNodeType: isAllowedChild ? 'listItem' : context.parentNodeType }))]; case 1: children = _a.sent(); if (Array.isArray(children) && children.length) { return [2 /*return*/, isAllowedChild ? createNode('listItem', { children: wrap(children), }) : children]; } return [2 /*return*/, undefined]; } }); }); }; export var link = function link(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var isAllowedChild, allowedChildrenWrapped, wrapsHeadings, i_1, splitChildren_1, children, props, meta_1; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!context.allowedBlocks.includes('link')) { return [2 /*return*/, visitChildren(createNode, node, context)]; } isAllowedChild = false; if (allowedChildren[context.parentNodeType] === 'inlineNodes') { isAllowedChild = inlineNodeTypes.includes('link'); } else if (Array.isArray(allowedChildren[context.parentNodeType])) { isAllowedChild = allowedChildren[context.parentNodeType].includes('link'); } if (!isAllowedChild) { allowedChildrenWrapped = ['root', 'list', 'listItem']; isAllowedChild = allowedChildrenWrapped.includes(context.parentNodeType); } wrapsHeadings = node.children.some(function (child) { return child.type === 'element' && child.tagName.startsWith('h'); }); if (wrapsHeadings) { i_1 = 0; splitChildren_1 = []; node.children.forEach(function (child) { if (child.type === 'element' && child.tagName.startsWith('h')) { if (splitChildren_1.length > 0) { i_1++; } splitChildren_1.push(__assign(__assign({}, child), { children: [ __assign(__assign({}, node), { children: child.children }), ] })); i_1++; } else if (splitChildren_1[i_1]) { splitChildren_1[i_1].children.push(child); } else { splitChildren_1[i_1] = __assign(__assign({}, node), { children: [child] }); } }); node.children = splitChildren_1; isAllowedChild = false; } return [4 /*yield*/, visitChildren(createNode, node, __assign(__assign({}, context), { parentNodeType: isAllowedChild ? 'link' : context.parentNodeType }))]; case 1: children = _a.sent(); if (Array.isArray(children) && children.length) { if (!isAllowedChild) { return [2 /*return*/, children]; } props = { url: resolveUrl(context, node.properties.href), children: children, }; meta_1 = []; if (node.properties) { ['target', 'rel', 'title'].forEach(function (attr) { var value = Array.isArray(node.properties[attr]) ? node.properties[attr].join(' ') : node.properties[attr]; if (value) { meta_1.push({ id: attr, value: value }); } }); } if (meta_1.length > 0) { props.meta = meta_1; } return [2 /*return*/, createNode('link', props)]; } return [2 /*return*/, undefined]; } }); }); }; export var span = function span(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var marks, allowedMarks; return __generator(this, function (_a) { marks = {}; if (Array.isArray(context.marks)) { allowedMarks = context.marks.filter(function (mark) { return context.allowedMarks.includes(mark); }); if (allowedMarks.length > 0) { marks.marks = allowedMarks; } } return [2 /*return*/, createNode('span', __assign({ value: wrapText(context, node.value) }, marks))]; }); }); }; export var newLine = function newLine(createNode) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, createNode('span', { value: '\n', })]; }); }); }; export var inlineCode = withMark('code'); export var strong = withMark('strong'); export var italic = withMark('emphasis'); export var underline = withMark('underline'); export var strikethrough = withMark('strikethrough'); export var highlight = withMark('highlight'); export var head = function head(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var baseElement; return __generator(this, function (_a) { baseElement = node.children.find(function (child) { return child.tagName === 'base'; }); if (baseElement) { return [2 /*return*/, context.handlers.base(createNode, baseElement, context)]; } else { return [2 /*return*/, undefined]; } return [2 /*return*/]; }); }); }; export var base = function base(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { if (!context.global.baseUrlFound && typeof node.properties === 'object' && node.properties.href) { context.global.baseUrl = node.properties.href.replace(/\/$/, ''); context.global.baseUrlFound = true; } return [2 /*return*/]; }); }); }; export var extractInlineStyles = function extractInlineStyles(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var marks, newMarks_1; return __generator(this, function (_a) { marks = { marks: Array.isArray(context.marks) ? context.marks : [] }; if (node.properties && typeof node.properties.style === 'string') { newMarks_1 = []; node.properties.style.split(';').forEach(function (declaration) { var _a = declaration.split(':'), firstChunk = _a[0], otherChunks = _a.slice(1); var prop = firstChunk.trim(); var value = otherChunks.join(':').trim(); switch (prop) { case 'font-weight': if (value === 'bold' || Number(value) > 400) { newMarks_1.push('strong'); } break; case 'font-style': if (value === 'italic') { newMarks_1.push('emphasis'); } break; case 'text-decoration': if (value === 'underline') { newMarks_1.push('underline'); } break; default: break; } }); if (newMarks_1.length > 0) { marks.marks = marks.marks.concat(newMarks_1.filter(function (mark) { return !marks.marks.includes(mark) && context.allowedMarks.includes(mark); })); } } if (marks.marks.length === 0) { marks = {}; } return [2 /*return*/, visitChildren(createNode, node, __assign(__assign({}, context), marks))]; }); }); }; // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/explicit-module-boundary-types export function noop() { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/]; }); }); } export function withMark(type) { return function markHandler(createNode, node, context) { if (!context.allowedMarks.includes(type)) { return visitChildren(createNode, node, context); } var marks = { marks: [type] }; if (Array.isArray(context.marks)) { marks = { marks: context.marks.includes(type) ? context.marks : context.marks.concat([type]), }; } return visitChildren(createNode, node, __assign(__assign({}, context), marks)); }; } export var handlers = { root: root, p: paragraph, summary: paragraph, h1: heading, h2: heading, h3: heading, h4: heading, h5: heading, h6: heading, ul: list, ol: list, dir: list, dt: listItem, dd: listItem, li: listItem, listing: code, plaintext: code, pre: code, xmp: code, blockquote: blockquote, a: link, code: code, kbd: code, samp: code, tt: code, var: code, strong: strong, b: strong, em: italic, i: italic, u: underline, strike: strikethrough, s: strikethrough, mark: highlight, base: base, span: extractInlineStyles, text: span, br: newLine, hr: thematicBreak, head: head, comment: noop, script: noop, style: noop, title: noop, video: noop, audio: noop, embed: noop, iframe: noop, }; export var wrapListItems = function wrapListItems(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var children, index; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, visitChildren(createNode, node, context)]; case 1: children = _a.sent(); if (!Array.isArray(children)) { return [2 /*return*/, []]; } index = -1; while (++index < children.length) { if (typeof children[index] !== 'undefined' && children[index].type !== 'listItem') { children[index] = { type: 'listItem', children: [ allowedChildren.listItem.includes(children[index].type) ? children[index] : createNode('paragraph', { children: [children[index]] }), ], }; } } return [2 /*return*/, children]; } }); }); }; export function wrapText(context, value) { return context.wrapText ? value : value.replace(/\r?\n|\r/g, ' '); } export function resolveUrl(context, url) { if (url === null || url === undefined) { return ''; } if (context.global.baseUrl && typeof URL !== 'undefined') { var isRelative = /^\.?\//.test(url); var parsed = new URL(url, context.global.baseUrl); if (isRelative) { var parsedBase = new URL(context.global.baseUrl); if (!parsed.pathname.startsWith(parsedBase.pathname)) { parsed.pathname = "" + parsedBase.pathname + parsed.pathname; } } return parsed.toString(); } return url; } //# sourceMappingURL=handlers.js.map