"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PropertyMetadataProcessor = void 0;
var tslib_1 = require("tslib");
var lodash = (0, tslib_1.__importStar)(require("@microsoft/sp-lodash-subset"));
/**
 * The processor to serialize and deserialize the server processed content and component properties
 * based on component metadata.
 *
 * @internal
 */
var PropertyMetadataProcessor = /** @class */ (function () {
    function PropertyMetadataProcessor() {
    }
    /**
     * Serialize the properties into server processed content as declared in metadata.
     *
     * @param properties - The component properties. This object will be modified during serialization.
     * @param propertiesMetadata - The component properties metadata.
     * @param serverProcessedContent - The serialized server processed content. This object will be modified.
     */
    PropertyMetadataProcessor.serializeServerProcessedData = function (propertiesMetadata, properties, serverProcessedContent) {
        var _this = this;
        this._forEachPropertyWithMetaData(propertiesMetadata, properties, function (propPath, metadata, iteration) {
            // Remove fields with shouldNotPersist metadata
            if (metadata.shouldNotPersist) {
                lodash.set(properties, propPath, undefined);
            }
            // Use the property path as the key in server-processed content maps
            var key = propPath;
            // WARNING: This is critical code. Please do not modify without fully understanding the data pipeline
            var value = lodash.get(properties, propPath);
            // Skip if the property is non-string or undefined
            if (serverProcessedContent && typeof value === 'string' && value) {
                if (serverProcessedContent.htmlStrings && metadata.isHtmlString) {
                    serverProcessedContent.htmlStrings[key] = value;
                }
                else if (serverProcessedContent.searchablePlainTexts && metadata.isSearchablePlainText) {
                    serverProcessedContent.searchablePlainTexts[key] = value;
                }
                else if (serverProcessedContent.links && metadata.isLink) {
                    serverProcessedContent.links[key] = value;
                }
                else if (serverProcessedContent.imageSources && metadata.isImageSource) {
                    serverProcessedContent.imageSources[key] = value;
                }
                else if (metadata.isComponentDependency) {
                    if (!serverProcessedContent.componentDependencies) {
                        serverProcessedContent.componentDependencies = {};
                    }
                    serverProcessedContent.componentDependencies[key] = value;
                }
                if (metadata.customMetadata) {
                    // Build custom metadata for the given property path
                    var customMetadata_1 = {};
                    if (metadata && metadata.customMetadata) {
                        for (var propName in metadata.customMetadata) {
                            /* tslint:disable-line:forin */
                            var customMetadataPropPath = metadata.customMetadata[propName];
                            if (iteration !== undefined && customMetadataPropPath.indexOf('*') !== -1) {
                                // Custom metadata should be resolved with current iteration of wildcard
                                customMetadataPropPath = customMetadataPropPath.replace('*', iteration.toString());
                            }
                            _this._validateAndIteratePath(customMetadataPropPath, properties, function (fixedPropPath, customIteration) {
                                // Custom metadata should be resolved without iteration
                                if (customIteration === undefined && metadata.customMetadata) {
                                    var customValue = lodash.get(properties, fixedPropPath);
                                    if (serverProcessedContent && customValue !== undefined) {
                                        // Insert custom metadata key and value
                                        customMetadata_1[fixedPropPath] = customValue;
                                    }
                                }
                            });
                        }
                    }
                    if (!serverProcessedContent.customMetadata) {
                        serverProcessedContent.customMetadata = {};
                    }
                    // Store serialized custom metadata for the given the property path.
                    serverProcessedContent.customMetadata[key] = customMetadata_1;
                }
                // Unset the extracted property to avoid duplication
                lodash.set(properties, propPath, undefined);
            }
        });
    };
    /**
     * Reapply the serialized server processed content on the properties based on the metadata.
     * This process will result in the properties bag as it was when the serialization happened.
     *
     * @param properties - The component properties. This object will be modified during serialization.
     * @param propertiesMetadata - The component properties metadata.
     * @param serverProcessedContent - The serialized server processed content.
     * @param manifest - The optional component manifest.
     */
    PropertyMetadataProcessor.reInstateServerProcessedData = function (propertiesMetadata, properties, serverProcessedContent, manifest) {
        if (manifest) {
            // @privateRemarks Clear out the properties with isHtmlString metadata for security reasons. We only want to
            // propagate values from the serverProcessed content as they are security sanitized by the server. Note, there is a
            // scenario when an end user can update the list item with whatever data they like. In that case, they can
            // eliminate the serverProcessed content and that can cause a potential security hole. Hence, we always want
            // clear out the property values that have isHtmlString metadata.
            this._forEachPropertyWithMetaData(propertiesMetadata, properties, function (propPath, metadata) {
                // This is a temporary hack to make sure that the webparts published using the Mobile app keep rendering.
                // Currently, for those pages, the DocumentEmbedWebPart does not have HTMLProperties pupulated. Hence,
                // we are doing this work around to not unset the property bag.
                // (SPPPLAT VSO#289988) tracks removal of this code.
                if (manifest.id !== 'b7dd04e1-19ce-4b24-9132-b60a1c2b910d' && metadata.isHtmlString) {
                    lodash.set(properties, propPath, undefined);
                }
            });
        }
        if (serverProcessedContent) {
            // Re-instate the server processed values in the specified path in the property bag.
            // There is a change that the new shape of the property bag is different. But the
            // the purpose of the inbuilt deserialization is to provide the same properties object
            // back to the web part that has the same shape as when the serialization happened.
            var htmlMaps = [
                serverProcessedContent.htmlStrings,
                serverProcessedContent.searchablePlainTexts,
                serverProcessedContent.imageSources,
                serverProcessedContent.links,
                serverProcessedContent.componentDependencies
            ];
            for (var _i = 0, htmlMaps_1 = htmlMaps; _i < htmlMaps_1.length; _i++) {
                var htmlMap = htmlMaps_1[_i];
                if (htmlMap) {
                    for (var propPath in htmlMap) {
                        /* tslint:disable-line:forin */
                        // WARNING: This is critical code. Please do not modify without fully understanding the data pipeline
                        var value = htmlMap[propPath];
                        if (typeof value === 'string') {
                            lodash.set(properties, propPath, value);
                        }
                    }
                }
            }
        }
    };
    /**
     * Iterates and validates each metadata property before calling metadata processor.
     *
     * @param properties - Component properties.
     * @param propertiesMetadata - Component properties metadata.
     * @param metadataProcessor - Callback handler to to process validated metadata.
     *
     * @internal
     */
    PropertyMetadataProcessor._forEachPropertyWithMetaData = function (propertiesMetadata, properties, metadataProcessor) {
        if (propertiesMetadata) {
            var _loop_1 = function (propPath) {
                /* tslint:disable-line:forin */
                var metadata = propertiesMetadata[propPath];
                this_1._validateAndIteratePath(propPath, properties, function (fixedPropPath, index) {
                    metadataProcessor(fixedPropPath, metadata, index);
                });
            };
            var this_1 = this;
            for (var propPath in propertiesMetadata) {
                _loop_1(propPath);
            }
        }
    };
    /**
     * Validates path and iterate over one or multiple wildcard paths
     *
     * @param propPath - Original property path provided in metadata
     * @param properties - Properties to look for the given path.
     * @param propertyPathHandler - Handler to process validated and fixed path
     */
    PropertyMetadataProcessor._validateAndIteratePath = function (propPath, properties, propertyPathHandler) {
        var wildcardCount = (propPath.match(/\*/g) || []).length;
        if (wildcardCount > 1) {
            // Skip if there are more than one asterisks in the path (not supported)
            console.warn("Invalid property path: Multiple wildcards are not supported in property paths.\nEntry with path '".concat(propPath, "' got ignored in the properties metadata."));
            return;
        }
        else if (wildcardCount === 1) {
            var index = propPath.indexOf('[*]');
            if (index < -1) {
                console.warn("Invalid property path: Wildcards are only supported inside brackets to select array\nindices as in 'foo[*].bar'. Entry with path '".concat(propPath, "' got ignored in the properties metadata."));
                // Skip if the wildcard is not used for an array (not supported)
                return;
            }
            else {
                // Handle the array wildcard by generating each individual property path
                var arrayPath = propPath.substr(0, index);
                var arrayInstance = lodash.get(properties, arrayPath);
                if (!arrayInstance) {
                    console.warn("Invalid property path: Could not find an array named '".concat(arrayPath, "' in the properties.\nEntry with path '").concat(propPath, "' got ignored in the properties metadata."));
                    return;
                }
                else {
                    for (var i = 0; i < arrayInstance.length; i++) {
                        var fixedPropPath = propPath.replace('*', "".concat(i));
                        propertyPathHandler(fixedPropPath, i);
                    }
                }
            }
        }
        else {
            propertyPathHandler(propPath);
        }
    };
    return PropertyMetadataProcessor;
}());
exports.PropertyMetadataProcessor = PropertyMetadataProcessor;
//# sourceMappingURL=PropertyMetadataProcessor.js.map