UNPKG

datocms-html-to-structured-text

Version:

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

575 lines 27.4 kB
"use strict"; 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 }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveUrl = exports.wrapText = exports.wrapListItems = exports.handlers = exports.withMark = exports.noop = exports.extractInlineStyles = exports.base = exports.head = exports.highlight = exports.strikethrough = exports.underline = exports.italic = exports.strong = exports.inlineCode = exports.newLine = exports.span = exports.link = exports.listItem = exports.list = exports.blockquote = exports.code = exports.heading = exports.thematicBreak = exports.paragraph = exports.root = void 0; /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-nocheck var convert_1 = __importDefault(require("hast-util-is-element/convert")); var hast_util_to_text_1 = __importDefault(require("hast-util-to-text")); var hast_util_has_property_1 = __importDefault(require("hast-util-has-property")); var datocms_structured_text_utils_1 = require("datocms-structured-text-utils"); var visit_children_1 = __importDefault(require("./visit-children")); var wrap_1 = require("./wrap"); 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*/, visit_children_1.default(createNode, node, __assign(__assign({}, context), { parentNodeType: 'root' }))]; case 1: children = _a.sent(); if (Array.isArray(children) && children.some(function (child) { return child && !datocms_structured_text_utils_1.allowedChildren.root.includes(child.type); })) { children = wrap_1.wrap(children); } if (!Array.isArray(children) || children.length === 0) { return [2 /*return*/, null]; } return [2 /*return*/, createNode('root', { children: Array.isArray(children) ? children : [], })]; } }); }); }; exports.root = root; 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 = datocms_structured_text_utils_1.allowedChildren[context.parentNodeType].includes('paragraph'); return [4 /*yield*/, visit_children_1.default(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]; } }); }); }; exports.paragraph = paragraph; var thematicBreak = function thematicBreak(createNode, node, context) { return __awaiter(this, void 0, void 0, function () { var isAllowedChild; return __generator(this, function (_a) { isAllowedChild = datocms_structured_text_utils_1.allowedChildren[context.parentNodeType].includes('thematicBreak'); return [2 /*return*/, isAllowedChild ? createNode('thematicBreak', {}) : undefined]; }); }); }; exports.thematicBreak = thematicBreak; 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 = datocms_structured_text_utils_1.allowedChildren[context.parentNodeType].includes('heading') && context.allowedBlocks.includes('heading') && context.allowedHeadingLevels.includes(level); return [4 /*yield*/, visit_children_1.default(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]; } }); }); }; exports.heading = heading; 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 = datocms_structured_text_utils_1.allowedChildren[context.parentNodeType].includes('code'); if (!isAllowedChild) { return [2 /*return*/, exports.inlineCode(createNode, node, context)]; } if (!context.allowedBlocks.includes('code')) { return [2 /*return*/, visit_children_1.default(createNode, node, context)]; } prefix = typeof context.codePrefix === 'string' ? context.codePrefix : 'language-'; isPre = convert_1.default('pre'); isCode = convert_1.default('code'); children = node.children; index = -1; classList = null; language = {}; if (isPre(node)) { while (++index < children.length) { if (typeof children[index] === 'object' && isCode(children[index]) && hast_util_has_property_1.default(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) && hast_util_has_property_1.default(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, hast_util_to_text_1.default(node))).replace(/\n+$/, '') }))]; }); }); }; exports.code = code; 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 = datocms_structured_text_utils_1.allowedChildren[context.parentNodeType].includes('blockquote') && context.allowedBlocks.includes('blockquote'); return [4 /*yield*/, visit_children_1.default(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_1.wrap(children) }) : children]; } return [2 /*return*/, undefined]; } }); }); }; exports.blockquote = blockquote; 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 = datocms_structured_text_utils_1.allowedChildren[context.parentNodeType].includes('list') && context.allowedBlocks.includes('list'); if (!!isAllowedChild) return [3 /*break*/, 2]; return [4 /*yield*/, visit_children_1.default(createNode, node, context)]; case 1: return [2 /*return*/, _a.sent()]; case 2: return [4 /*yield*/, exports.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]; } }); }); }; exports.list = list; 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 = datocms_structured_text_utils_1.allowedChildren[context.parentNodeType].includes('listItem') && context.allowedBlocks.includes('list'); return [4 /*yield*/, visit_children_1.default(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_1.wrap(children), }) : children]; } return [2 /*return*/, undefined]; } }); }); }; exports.listItem = listItem; 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*/, visit_children_1.default(createNode, node, context)]; } isAllowedChild = false; if (datocms_structured_text_utils_1.allowedChildren[context.parentNodeType] === 'inlineNodes') { isAllowedChild = datocms_structured_text_utils_1.inlineNodeTypes.includes('link'); } else if (Array.isArray(datocms_structured_text_utils_1.allowedChildren[context.parentNodeType])) { isAllowedChild = datocms_structured_text_utils_1.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*/, visit_children_1.default(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]; } }); }); }; exports.link = link; 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))]; }); }); }; exports.span = span; 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', })]; }); }); }; exports.newLine = newLine; exports.inlineCode = withMark('code'); exports.strong = withMark('strong'); exports.italic = withMark('emphasis'); exports.underline = withMark('underline'); exports.strikethrough = withMark('strikethrough'); exports.highlight = withMark('highlight'); 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*/]; }); }); }; exports.head = head; 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*/]; }); }); }; exports.base = base; 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*/, visit_children_1.default(createNode, node, __assign(__assign({}, context), marks))]; }); }); }; exports.extractInlineStyles = extractInlineStyles; // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/explicit-module-boundary-types function noop() { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/]; }); }); } exports.noop = noop; function withMark(type) { return function markHandler(createNode, node, context) { if (!context.allowedMarks.includes(type)) { return visit_children_1.default(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 visit_children_1.default(createNode, node, __assign(__assign({}, context), marks)); }; } exports.withMark = withMark; exports.handlers = { root: exports.root, p: exports.paragraph, summary: exports.paragraph, h1: exports.heading, h2: exports.heading, h3: exports.heading, h4: exports.heading, h5: exports.heading, h6: exports.heading, ul: exports.list, ol: exports.list, dir: exports.list, dt: exports.listItem, dd: exports.listItem, li: exports.listItem, listing: exports.code, plaintext: exports.code, pre: exports.code, xmp: exports.code, blockquote: exports.blockquote, a: exports.link, code: exports.code, kbd: exports.code, samp: exports.code, tt: exports.code, var: exports.code, strong: exports.strong, b: exports.strong, em: exports.italic, i: exports.italic, u: exports.underline, strike: exports.strikethrough, s: exports.strikethrough, mark: exports.highlight, base: exports.base, span: exports.extractInlineStyles, text: exports.span, br: exports.newLine, hr: exports.thematicBreak, head: exports.head, comment: noop, script: noop, style: noop, title: noop, video: noop, audio: noop, embed: noop, iframe: noop, }; 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*/, visit_children_1.default(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: [ datocms_structured_text_utils_1.allowedChildren.listItem.includes(children[index].type) ? children[index] : createNode('paragraph', { children: [children[index]] }), ], }; } } return [2 /*return*/, children]; } }); }); }; exports.wrapListItems = wrapListItems; function wrapText(context, value) { return context.wrapText ? value : value.replace(/\r?\n|\r/g, ' '); } exports.wrapText = wrapText; 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; } exports.resolveUrl = resolveUrl; //# sourceMappingURL=handlers.js.map