UNPKG

@kontent-ai/delivery-sdk

Version:
340 lines 17 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ElementMapper = void 0; const utilities_1 = require("../utilities"); const elements_1 = require("../elements"); class ElementMapper { constructor(config) { this.config = config; } mapElements(data) { // return processed item to avoid infinite recursion const processedItem = data.processedItems[utilities_1.codenameHelper.escapeCodenameInCodenameIndexer(data.dataToMap.item.system.codename)]; if (processedItem) { // item was already resolved return { item: processedItem, processedItems: data.processedItems, preparedItems: data.preparedItems, processingStartedForCodenames: data.processingStartedForCodenames }; } const preparedItem = data.preparedItems[utilities_1.codenameHelper.escapeCodenameInCodenameIndexer(data.dataToMap.item.system.codename)]; const itemInstance = preparedItem === null || preparedItem === void 0 ? void 0 : preparedItem.item; if (!itemInstance) { // item is not present in response return undefined; } // mapp elements const elementCodenames = Object.getOwnPropertyNames(data.dataToMap.rawItem.elements); for (const elementCodename of elementCodenames) { const elementWrapper = { system: data.dataToMap.item.system, rawElement: data.dataToMap.rawItem.elements[elementCodename], element: elementCodename }; const mappedElement = this.mapElement({ elementWrapper: elementWrapper, item: itemInstance, preparedItems: data.preparedItems, processingStartedForCodenames: data.processingStartedForCodenames, processedItems: data.processedItems }); // set mapped elements itemInstance.elements[elementCodename] = mappedElement; } return { item: itemInstance, processedItems: data.processedItems, preparedItems: data.preparedItems, processingStartedForCodenames: data.processingStartedForCodenames }; } mapElement(data) { const elementType = utilities_1.enumHelper.getEnumFromValue(elements_1.ElementType, data.elementWrapper.rawElement.type); if (elementType) { if (elementType === elements_1.ElementType.ModularContent) { return this.mapLinkedItemsElement({ elementWrapper: data.elementWrapper, preparedItems: data.preparedItems, processingStartedForCodenames: data.processingStartedForCodenames, processedItems: data.processedItems }); } if (elementType === elements_1.ElementType.Text) { return this.mapTextElement(data.elementWrapper); } if (elementType === elements_1.ElementType.Asset) { return this.mapAssetsElement(data.elementWrapper); } if (elementType === elements_1.ElementType.Number) { return this.mapNumberElement(data.elementWrapper); } if (elementType === elements_1.ElementType.MultipleChoice) { return this.mapMultipleChoiceElement(data.elementWrapper); } if (elementType === elements_1.ElementType.DateTime) { return this.mapDateTimeElement(data.elementWrapper); } if (elementType === elements_1.ElementType.RichText) { // add to parent items return this.mapRichTextElement(data.elementWrapper, data.processedItems, data.processingStartedForCodenames, data.preparedItems); } if (elementType === elements_1.ElementType.UrlSlug) { return this.mapUrlSlugElement(data.elementWrapper); } if (elementType === elements_1.ElementType.Taxonomy) { return this.mapTaxonomyElement(data.elementWrapper); } if (elementType === elements_1.ElementType.Custom) { return this.mapCustomElement(data.elementWrapper); } } console.warn(`Could not map element '${data.elementWrapper.rawElement.name}' of type '${data.elementWrapper.rawElement.type}'. Returning unknown element instead.`); return this.mapUnknowElement(data.elementWrapper); } mapRichTextElement(elementWrapper, processedItems, processingStartedForCodenames, preparedItems) { const rawElement = elementWrapper.rawElement; // get all linked items and linked items codenames nested in rich text const richTextLinkedItems = []; const richTextLinkedItemsCodenames = []; // The Kontent Delivery API is not guaranteed to return rich-text modular_content array items in the same order in which they appear inside the `value` property. // We extract the modular_content codenames in the rich-text value and sort the raw modular_content based on that order instead. const rawModularContentCodenamesMatches = rawElement.value.matchAll(/<object[^>]+data-codename="(?<codename>[a-z0-9_]*)".*?>/g); const rawModularContentCodenamesSorted = Array.from(rawModularContentCodenamesMatches).reduce((acc, match) => { if (match.groups && match.groups.codename) { acc.push(match.groups.codename); } return acc; }, []); const rawModularContentCodenames = [...rawElement.modular_content].sort(function (a, b) { return rawModularContentCodenamesSorted.indexOf(a) - rawModularContentCodenamesSorted.indexOf(b); }); for (const codename of rawModularContentCodenames) { richTextLinkedItemsCodenames.push(codename); // get linked item and check if it exists (it might not be included in response due to 'Depth' parameter) const preparedData = preparedItems[codename]; // first try to get existing item if (this.canMapLinkedItems()) { const existingLinkedItem = this.getOrSaveLinkedItemForElement(codename, rawElement, processedItems, processingStartedForCodenames, preparedItems); if (existingLinkedItem) { // item was found, add it to linked items richTextLinkedItems.push(existingLinkedItem); } else { // item was not found or not yet resolved if (preparedData) { const mappedLinkedItemResult = this.mapElements({ dataToMap: preparedData, preparedItems: preparedItems, processingStartedForCodenames: processingStartedForCodenames, processedItems: processedItems }); // add mapped linked item to result if (mappedLinkedItemResult) { richTextLinkedItems.push(mappedLinkedItemResult.item); } } } } } // get rich text images const richTextImagesResult = this.getRichTextImages(rawElement.images); // extract and map links & images const links = this.mapRichTextLinks(rawElement.links); const images = richTextImagesResult.richTextImages; // replace asset urls in html const richTextHtml = this.getRichTextHtml(rawElement.value, richTextImagesResult.imageUrlRecords); return { images: images, linkedItemCodenames: richTextLinkedItemsCodenames, linkedItems: richTextLinkedItems, links: links, name: rawElement.name, type: elements_1.ElementType.RichText, value: richTextHtml }; } mapDateTimeElement(elementWrapper) { var _a; const rawElement = elementWrapper.rawElement; return Object.assign(Object.assign({}, this.buildElement(elementWrapper, elements_1.ElementType.DateTime, () => rawElement.value)), { displayTimeZone: (_a = rawElement.display_timezone) !== null && _a !== void 0 ? _a : null }); } mapMultipleChoiceElement(elementWrapper) { return this.buildElement(elementWrapper, elements_1.ElementType.MultipleChoice, () => elementWrapper.rawElement.value); } mapNumberElement(elementWrapper) { return this.buildElement(elementWrapper, elements_1.ElementType.Number, () => { if (elementWrapper.rawElement.value === 0) { return 0; } else if (elementWrapper.rawElement.value) { return +elementWrapper.rawElement.value; } return null; }); } mapTextElement(elementWrapper) { return this.buildElement(elementWrapper, elements_1.ElementType.Text, () => elementWrapper.rawElement.value); } mapAssetsElement(elementWrapper) { return this.buildElement(elementWrapper, elements_1.ElementType.Asset, () => { var _a; const assetContracts = elementWrapper.rawElement.value; const assets = []; for (const assetContract of assetContracts) { let renditions = null; // get asset url (custom domain may be configured) const assetUrl = this.config.assetsDomain ? utilities_1.deliveryUrlHelper.replaceAssetDomain(assetContract.url, this.config.assetsDomain) : assetContract.url; if (assetContract.renditions) { renditions = {}; for (const renditionPresetKey of Object.keys(assetContract.renditions)) { const rendition = assetContract.renditions[renditionPresetKey]; renditions[renditionPresetKey] = Object.assign(Object.assign({}, rendition), { url: `${assetUrl}?${rendition.query}` // enhance rendition with absolute url }); } } const renditionToBeApplied = (this.config.defaultRenditionPreset && (renditions === null || renditions === void 0 ? void 0 : renditions[this.config.defaultRenditionPreset])) || null; const finalUrl = (_a = renditionToBeApplied === null || renditionToBeApplied === void 0 ? void 0 : renditionToBeApplied.url) !== null && _a !== void 0 ? _a : assetUrl; const asset = Object.assign(Object.assign({}, assetContract), { url: finalUrl, // use custom url of asset which may contain custom domain and applied rendition renditions }); assets.push(asset); } return assets; }); } mapTaxonomyElement(elementWrapper) { var _a; return Object.assign(Object.assign({}, this.buildElement(elementWrapper, elements_1.ElementType.Taxonomy, () => elementWrapper.rawElement.value)), { taxonomyGroup: (_a = elementWrapper.rawElement.taxonomy_group) !== null && _a !== void 0 ? _a : '' }); } mapUnknowElement(elementWrapper) { return this.buildElement(elementWrapper, elements_1.ElementType.Unknown, () => elementWrapper.rawElement.value); } mapCustomElement(elementWrapper) { // try to find element resolver if (this.config.elementResolver) { const elementResolverValue = this.config.elementResolver(elementWrapper); if (elementResolverValue) { return this.buildElement(elementWrapper, elements_1.ElementType.Custom, () => elementResolverValue); } } return this.buildElement(elementWrapper, elements_1.ElementType.Custom, () => elementWrapper.rawElement.value); } mapUrlSlugElement(elementWrapper) { return this.buildElement(elementWrapper, elements_1.ElementType.UrlSlug, () => elementWrapper.rawElement.value); } mapLinkedItemsElement(data) { // prepare linked items const linkedItems = []; // value = array of item codenames const linkedItemCodenames = data.elementWrapper.rawElement.value; for (const codename of linkedItemCodenames) { if (this.canMapLinkedItems()) { const linkedItem = this.getOrSaveLinkedItemForElement(codename, data.elementWrapper.rawElement, data.processedItems, data.processingStartedForCodenames, data.preparedItems); if (linkedItem) { // add item to result linkedItems.push(linkedItem); } } } return Object.assign(Object.assign({}, this.buildElement(data.elementWrapper, elements_1.ElementType.ModularContent, () => linkedItemCodenames)), { linkedItems: linkedItems }); } getOrSaveLinkedItemForElement(codename, element, processedItems, mappingStartedForCodenames, preparedItems) { const escapedCodename = utilities_1.codenameHelper.escapeCodenameInCodenameIndexer(codename); // first check if item was already resolved and return it if it was const processedItem = processedItems[escapedCodename]; if (processedItem) { // item was already resolved return processedItem; } const preparedItem = preparedItems[escapedCodename]; if (mappingStartedForCodenames.includes(codename)) { return preparedItem === null || preparedItem === void 0 ? void 0 : preparedItem.item; } mappingStartedForCodenames.push(codename); // throw error if item is not in response and errors are not skipped if (!preparedItem) { return undefined; } let mappedLinkedItem; // original resolving if item is still undefined const mappedLinkedItemResult = this.mapElements({ dataToMap: preparedItem, preparedItems: preparedItems, processingStartedForCodenames: mappingStartedForCodenames, processedItems: processedItems }); if (mappedLinkedItemResult) { mappedLinkedItem = mappedLinkedItemResult.item; // add to processed items processedItems[escapedCodename] = mappedLinkedItem; } return mappedLinkedItem; } mapRichTextLinks(linksJson) { const links = []; for (const linkId of Object.keys(linksJson)) { const linkRaw = linksJson[linkId]; links.push({ codename: linkRaw.codename, linkId: linkId, urlSlug: linkRaw.url_slug, type: linkRaw.type }); } return links; } getRichTextHtml(richTextHtml, richTextImageRecords) { for (const richTextImageRecord of richTextImageRecords) { // replace rich text image url if it differs if (richTextImageRecord.newUrl !== richTextImageRecord.originalUrl) { richTextHtml = richTextHtml.replace(new RegExp(richTextImageRecord.originalUrl, 'g'), richTextImageRecord.newUrl); } } return richTextHtml; } getRichTextImages(imagesJson) { var _a, _b, _c; const images = []; const imageUrlRecords = []; for (const imageId of Object.keys(imagesJson)) { const imageRaw = imagesJson[imageId]; // image may contain custom asset domain const imageUrl = this.config.assetsDomain ? utilities_1.deliveryUrlHelper.replaceAssetDomain(imageRaw.url, this.config.assetsDomain) : imageRaw.url; images.push({ description: (_a = imageRaw.description) !== null && _a !== void 0 ? _a : null, imageId: imageRaw.image_id, url: imageUrl, height: (_b = imageRaw.height) !== null && _b !== void 0 ? _b : null, width: (_c = imageRaw.width) !== null && _c !== void 0 ? _c : null }); imageUrlRecords.push({ originalUrl: imageRaw.url, newUrl: imageUrl }); } return { imageUrlRecords: imageUrlRecords, richTextImages: images }; } buildElement(elementWrapper, type, valueFactory) { return { name: elementWrapper.rawElement.name, type: type, value: valueFactory() }; } canMapLinkedItems() { if (!this.config.linkedItemsReferenceHandler) { return true; } return this.config.linkedItemsReferenceHandler === 'map'; } } exports.ElementMapper = ElementMapper; //# sourceMappingURL=element.mapper.js.map