@kontent-ai/delivery-sdk
Version:
Official Kontent.AI Delivery API SDK
340 lines • 17 kB
JavaScript
"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