"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DATA_FIELD_FOR_ACTION_GROUP = void 0;
exports.addExtensionToArray = addExtensionToArray;
exports.addEnumForProperties = addEnumForProperties;
exports.addCustomColumnDefinition = addCustomColumnDefinition;
exports.addActionRecordToSchema = addActionRecordToSchema;
exports.addGroupActionRecordToSchema = addGroupActionRecordToSchema;
exports.addLineItemActionDefinition = addLineItemActionDefinition;
exports.addLineItemRecordToSchema = addLineItemRecordToSchema;
exports.appendLineItemsToSchema = appendLineItemsToSchema;
exports.addLineItemsTypeToSchema = addLineItemsTypeToSchema;
exports.addFragmentEnumForAnchor = addFragmentEnumForAnchor;
exports.addEnumForActionAnchor = addEnumForActionAnchor;
exports.findPageV4 = findPageV4;
exports.alignSchemaWithTemplateType = alignSchemaWithTemplateType;
exports.addCustomActionDefinition = addCustomActionDefinition;
exports.addHeaderFooterCustomActionDefinition = addHeaderFooterCustomActionDefinition;
exports.getManifestPage = getManifestPage;
exports.getPageCustomExtensionFile = getPageCustomExtensionFile;
exports.getPageCustomViewFile = getPageCustomViewFile;
exports.addCustomSectionDefinition = addCustomSectionDefinition;
exports.addCustomFilterFieldDefinition = addCustomFilterFieldDefinition;
exports.importActionSettingsOfReference = importActionSettingsOfReference;
exports.addCustomFieldDefinition = addCustomFieldDefinition;
const utils_1 = require("../../common/utils");
const StableIdHelper_1 = require("./StableIdHelper");
const common_1 = require("../../common");
const i18next_1 = __importDefault(require("i18next"));
const __1 = require("../../..");
const ux_specification_types_1 = require("@sap/ux-specification-types");
const ux_specification_types_2 = require("@sap/ux-specification-types");
const path_1 = require("path");
const DataFieldStrategy_1 = require("../../common/DataFieldStrategy");
const utils_2 = require("../import/utils");
exports.DATA_FIELD_FOR_ACTION_GROUP = 'DataFieldForActionGroup';
/**
 * Returns a comparator function to sort objects by their property index.
 *
 * @returns A comparator function that compares two objects based on their property index.
 */
function sortByPropertyIndex() {
    return ([_key1, value1], [_key2, value2]) => value1[ux_specification_types_2.SchemaTag.propertyIndex] - value2[ux_specification_types_2.SchemaTag.propertyIndex];
}
/**
 * Sort function for properties in schema definitions.
 *
 * @param definition - definition which contains list of properties, unsorted
 * @returns - list of properties, sorted by property index
 */
function sortPropertiesRecords(definition) {
    definition = typeof definition === 'object' ? definition : {};
    const unsortedObjArr = [...Object.entries(definition.properties)];
    if (!definition.properties || Object.keys(definition.properties).length === 0) {
        return unsortedObjArr;
    }
    return unsortedObjArr.sort(sortByPropertyIndex());
}
/**
 * Method receives extension object and returns title/text.
 *
 * @param extension - custom extension object from manifest.
 * @returns Title/text of custom extension.
 */
function getExtensionText(extension) {
    let text;
    if (typeof extension === 'object') {
        if ('header' in extension) {
            text = extension.header;
        }
        else if ('text' in extension) {
            text = extension.text;
        }
        else if ('title' in extension) {
            text = extension.title;
        }
        else if ('label' in extension) {
            text = extension.label;
        }
    }
    else if (typeof extension === 'string') {
        text = extension;
    }
    return text;
}
/**
 * Adds a custom extension to the right position of a sorted array.
 *
 * @param extension - custom extension
 * @param sortedExtensionsArray - array of all entries(annotation entries and extensions), to be enhanced
 * @param targetIndex - index of the anchor entry
 * @param extId - ID of the new custom extension
 * @param newExtensionReference - schema reference of the new extension
 * @param newExtensionReference.$ref - The reference to the schema definition for the new extension.
 * @param newExtensionReference.description - A description of the new extension.
 */
function addExtensionToSortedArray(extension, sortedExtensionsArray, targetIndex, extId, newExtensionReference) {
    const placement = extension.position?.placement || ux_specification_types_2.v4.Placement.After;
    if (placement === ux_specification_types_2.v4.Placement.Before) {
        sortedExtensionsArray.splice(targetIndex, 0, [extId, newExtensionReference]);
    }
    else {
        sortedExtensionsArray.splice(targetIndex + 1, 0, [extId, newExtensionReference]);
    }
}
/**
 * Adds remaining custom extensions that might self-reference and were not added in previous steps.
 *
 * @param {CustomExtensions} remainingExtensions - list of custom extensions that are left for post-processing
 * @param {string} extId - current id of remaining extensions
 * @param {CustomExtension} extension - current extension of remaining custom extensions
 * @param {[string, unknown]} sortedExtArray - sorted array of annotation-based extensions, to be updated
 * @param newCustomExt - description based on extension in manifest
 * @param newCustomExt.$ref - The reference to the schema definition for the new extension.
 * @param newCustomExt.description - A description of the new custom extension.
 * @param newCustomExt.keys - An array of key objects, each containing a name and value for the custom extension.
 */
function addRemainingTargetByBefore(remainingExtensions, extId, extension, sortedExtArray, newCustomExt) {
    const targetRemainingIndex = Object.entries(remainingExtensions)
        .filter(([key]) => key !== extId)
        .findIndex(([_key, entry]) => entry.position?.placement === 'Before' && entry.position?.anchor === extension.position?.anchor);
    if (targetRemainingIndex === -1) {
        sortedExtArray.splice(sortedExtArray.length, 0, [extId, newCustomExt]);
        delete remainingExtensions[extId];
    }
}
/**
 * Returns custom extension details like $ref, description, keys and action type.
 *
 * @param extension - custom extensions config
 * @param extensionDefinitionName - custom extension definition name, different in LR and OP
 * @param extId - custom extension id
 * @param actionType - action type
 * @returns Custom extension details
 */
function getExtensionDetails(extension, extensionDefinitionName, extId, actionType) {
    const refDefinition = extensionDefinitionName.includes(ux_specification_types_2.DefinitionName.ObjectPageCustomSectionFragment)
        ? `${extensionDefinitionName}<${extId}>`
        : extensionDefinitionName;
    const description = getExtensionText(extension);
    return {
        $ref: `${utils_1.DEFINITION_LINK_PREFIX}${refDefinition}`,
        description,
        keys: [{ name: ux_specification_types_2.SchemaKeyName.key, value: `${extId}` }],
        ...(actionType !== undefined && { actionType })
    };
}
/**
 * Post-processing of custom extensions that are left after the first loop of adding extensions, i.e. custom extensions referring to other custom extensions.
 *
 * @param remainingExtensions - list of custom extensions that are left for post-processing
 * @param extensionDefinitionName - custom extension definition name, different in LR and OP
 * @param sortedExtArray - sorted array of annotation-based extensions, to be updated
 * @param logger - logger for error messages
 * @param {boolean} forceAdd - add self-referencing custom extensions after other additions
 */
function adjustCustomExtReferringToCustomExt(remainingExtensions, extensionDefinitionName, sortedExtArray, logger, forceAdd = false) {
    const initialRemaining = Object.entries(remainingExtensions).length;
    for (const extId of Object.keys(remainingExtensions)) {
        const extension = remainingExtensions[extId];
        // Detect description based on extension in manifest
        const newCustomExt = getExtensionDetails(extension, extensionDefinitionName, extId);
        if (extension.position?.anchor && extension.position?.placement) {
            const targetIndex = sortedExtArray.findIndex((element) => element[0] === extension.position.anchor);
            if (targetIndex > -1) {
                addExtensionToSortedArray(extension, sortedExtArray, targetIndex, extId, newCustomExt);
                delete remainingExtensions[extId];
            }
            else if (extId === extension.position.anchor ||
                Object.keys(remainingExtensions).indexOf(extension.position.anchor) === -1) {
                (0, __1.log)(logger, {
                    severity: "error" /* LogSeverity.Error */,
                    message: i18next_1.default.t('INVALIDANCHOR', { id: extId, anchor: extension.position.anchor }),
                    location: {
                        path: ux_specification_types_2.MANIFESTPATH,
                        range: [ux_specification_types_2.ManifestSection.ui5]
                    }
                });
                sortedExtArray.splice(sortedExtArray.length, 0, [extId, newCustomExt]);
                delete remainingExtensions[extId];
            }
            else if (forceAdd) {
                addRemainingTargetByBefore(remainingExtensions, extId, extension, sortedExtArray, newCustomExt);
            }
        }
        else if (forceAdd) {
            addExtensionToSortedArray(extension, sortedExtArray, sortedExtArray.length, extId, newCustomExt);
            delete remainingExtensions[extId];
        }
    }
    const endRemaining = Object.entries(remainingExtensions).length;
    if (endRemaining > 0 && initialRemaining !== endRemaining) {
        adjustCustomExtReferringToCustomExt(remainingExtensions, extensionDefinitionName, sortedExtArray, logger);
    }
    else if (endRemaining > 0) {
        adjustCustomExtReferringToCustomExt(remainingExtensions, extensionDefinitionName, sortedExtArray, logger, true);
    }
}
/**
 * Returns anchor for extension. Priority:
 * 1. 'anchor' property in extension;
 * 2. When 'anchor' is not defined in extension and does calculation based placement and current list of extension and annotation entries.
 *
 * @param extension - extension in manifest
 * @param sortedExtensionsArray - sorted array of annotation-based nodes, to be enhanced by extensions
 * @returns Anchor for extension
 */
function getExtensionAnchor(extension, sortedExtensionsArray) {
    // Default placement is After
    const placement = extension.position?.placement || ux_specification_types_2.v4.Placement.After;
    let anchor = extension.position?.anchor;
    if (!anchor) {
        // Simulate runtime behavior - if there no anchor, then logic uses first or last annotation node
        // In some cases last extension can be previously inserted extension - in such case we still need use annotation node
        const index = placement === ux_specification_types_2.v4.Placement.Before ? 0 : sortedExtensionsArray.length - 1;
        anchor = sortedExtensionsArray[index] ? sortedExtensionsArray[index][0] : undefined;
    }
    return anchor;
}
/**
 * Preprocesses and returns list of local extension ids that needs to be skipped from addition.
 *
 * @param {CustomExtensions} localExtensions - list of extensions in manifest
 * @param {[string, unknown][]} annotationEntries - sorted array of annotation-based nodes, to be enhanced by extensions
 * @returns List of local extensions that has no annotation based anchor
 */
function getLocalExtensionsToSkip(localExtensions, annotationEntries) {
    // collect local extensions that has no annotation based anchor
    const ignoredIds = [];
    for (const extensionId in localExtensions) {
        const anchor = localExtensions[extensionId].position?.anchor;
        const hasAnnotationAnchor = annotationEntries.some((annotationEntry) => annotationEntry[0] === anchor);
        if (anchor && !hasAnnotationAnchor) {
            ignoredIds.push(extensionId);
        }
    }
    return ignoredIds;
}
/**
 * Method returns position of passed extension using calculation for merged annotation nodes approach.
 * Currently is used for custom subsections - annotation merges subsection if there is no any child collecation facet.
 *
 * @param extension - custom extension
 * @param extensions - list of extensions in manifest
 * @param sortedExtensionsArray - array of all entries(annotation entries and extensions), to be enhanced
 * @returns Index of extension using merged annotation nodes approach.
 */
function getExtensionIndexByMergedApproach(extension, extensions, sortedExtensionsArray) {
    const placement = extension.position?.placement || ux_specification_types_2.v4.Placement.After;
    const originalAnchor = extension.position?.anchor;
    if (originalAnchor) {
        // Custom extension is anchored to any extension
        return sortedExtensionsArray.length;
    }
    // Custom extension is not anchored to any extension
    // Inner method to find next available index before or after annotation node
    const findNextIndex = (index, condition) => {
        for (const sortExtension of sortedExtensionsArray) {
            const innerExtension = extensions[sortExtension[0]];
            if (condition(innerExtension)) {
                // Condition is fulfilled - no need to increase index
                break;
            }
            // Increase index and check next ordered extension
            index++;
        }
        return index;
    };
    let index = 0;
    if (placement === ux_specification_types_2.v4.Placement.Before) {
        // Special case when no anchor but placement is "Before" - then rendered as very first
        // Find index before first annotation node
        index = findNextIndex(0, (innerExtension) => !innerExtension);
    }
    else {
        // Special case when no anchor but placement is "After" - then rendered right after last annotation node
        index = findNextIndex(-1, (innerExtension) => !!(innerExtension &&
            // Ignore extension without anchor but with position "Before"
            (innerExtension?.position?.anchor || innerExtension?.position?.placement !== ux_specification_types_2.v4.Placement.Before)));
    }
    return index > -1 ? index : 0;
}
/**
 *
 * @param extension - custom extension
 * @param extensions - list of extensions in manifest
 * @param sortedExtensionsArray - array of all entries(annotation entries and extensions), to be enhanced
 * @param anchor - target anchor to check
 * @param ignoreAnnotationAnchors - calculation should ignore anchors referenced to annotation nodes. Used when annotations sections are merged
 * @returns Index of extension using merged annotation nodes approach.
 */
function getExtensionIndex(extension, extensions, sortedExtensionsArray, anchor, ignoreAnnotationAnchors = false) {
    return !ignoreAnnotationAnchors
        ? sortedExtensionsArray.findIndex((element) => element[0] === anchor)
        : getExtensionIndexByMergedApproach(extension, extensions, sortedExtensionsArray);
}
/**
 * Error handler for invalid extensions.
 *
 * @param logger - logger for error messages
 * @param extensionId - ID of the extension
 * @param sortedExtensionsArray - sorted array of annotation-based nodes, to be enhanced by extensions
 * @param newExtensionReference - schema reference that had been prepared before
 * @param newExtensionReference.$ref - The reference to the schema definition for the new extension.
 * @param newExtensionReference.description - A description of the new extension.
 * @param newExtensionReference.keys - An array of key objects, each containing a name and value for the custom extension.
 * @param newExtensionReference.actionType - The action type associated with the new extension.
 * @param localExtensions - list of extensions for processing
 */
function handleInvalidExtension(logger, extensionId, sortedExtensionsArray, newExtensionReference, localExtensions) {
    (0, __1.log)(logger, {
        severity: "error" /* LogSeverity.Error */,
        message: i18next_1.default.t('INVALIDEXTENSION', { id: extensionId }),
        location: {
            path: ux_specification_types_2.MANIFESTPATH
        }
    });
    sortedExtensionsArray.push([extensionId, newExtensionReference]);
    delete localExtensions[extensionId];
}
/**
 * Adds extension at the right position of the sorted array of annotation-based nodes.
 *
 * @param extensions - list of extensions in manifest
 * @param sortedExtensionsArray - sorted array of annotation-based nodes, to be enhanced by extensions
 * @param extensionDefinitionName - extension definition name, different in LR and OP
 * @param templatePropertyName - The name of the property in the template to be used for processing.
 * @param logger - logger for error messages
 * @param ignoreAnnotationAnchors - calculation should ignore anchors referenced to annotation nodes. Used when annotations sections are merged.
 * @returns Sorted array of annotation-based nodes, enhanced by extensions
 */
function addExtensionToArray(extensions, sortedExtensionsArray, extensionDefinitionName, templatePropertyName = 'template', logger, ignoreAnnotationAnchors = false) {
    const annotationEntries = [...sortedExtensionsArray];
    const localExtensions = { ...extensions };
    const localExtensionsToSkip = getLocalExtensionsToSkip(localExtensions, annotationEntries);
    if (!localExtensions) {
        return [];
    }
    for (const extensionId of Object.keys(localExtensions)) {
        const extension = localExtensions[extensionId];
        if (localExtensionsToSkip?.includes(extensionId)) {
            continue;
        }
        const newExtensionReference = getExtensionDetails(extension, extensionDefinitionName, extensionId, ux_specification_types_2.ActionType.Custom);
        if (typeof extension !== 'object') {
            handleInvalidExtension(logger, extensionId, sortedExtensionsArray, newExtensionReference, localExtensions);
            continue;
        }
        if (!(templatePropertyName in extension)) {
            // Skip regular entries(columns, actions, etc.)
            delete localExtensions[extensionId];
            continue;
        }
        const anchor = getExtensionAnchor(extension, annotationEntries);
        if (anchor) {
            const targetIndex = getExtensionIndex(extension, extensions, sortedExtensionsArray, anchor, ignoreAnnotationAnchors);
            if (targetIndex > -1) {
                addExtensionToSortedArray(extension, sortedExtensionsArray, targetIndex, extensionId, newExtensionReference);
                delete localExtensions[extensionId];
            }
        }
        else {
            // Empty array - no any anchor to reference to
            sortedExtensionsArray.push([extensionId, newExtensionReference]);
            delete localExtensions[extensionId];
        }
    }
    if (Object.keys(localExtensions).length > 0) {
        //Second loop is necessary for custom columns that refer to custom columns
        adjustCustomExtReferringToCustomExt(localExtensions, extensionDefinitionName, sortedExtensionsArray, logger);
    }
    return sortedExtensionsArray;
}
/**
 * Adds enum values to the properties definition of a custom column.
 *
 * @param lineItems - current lineItems definition, with all records
 * @param customColumnDefinition - current custom column definition, in the app schema
 */
function addEnumForProperties(lineItems, customColumnDefinition) {
    const columnEnum = [];
    for (const key of Object.keys(lineItems.properties)) {
        if (key.indexOf('::') > -1) {
            columnEnum.push(key.substring(key.indexOf('::') + 2));
        }
    }
    customColumnDefinition.properties.properties.items['enum'] = columnEnum;
}
/**
 * Adds the propertyIndex to each column and adds the enum values for properties of custom columns.
 *
 * @param sortedColumnsArray - sorted array of all columns
 * @param {Definition} appSchema - app specific JSON schema
 * @param lineItems - content of the line item annotation
 * @param {DefinitionName} customColumnDefinitionName - custom column definition name, distinguishes LR from OP
 */
function addColumnPropertyIndexAndEnum(sortedColumnsArray, appSchema, lineItems, customColumnDefinitionName = ux_specification_types_2.DefinitionName.CustomColumn) {
    if (customColumnDefinitionName === ux_specification_types_2.DefinitionName.CustomColumn ||
        customColumnDefinitionName.indexOf(ux_specification_types_2.DefinitionName.ViewCustomColumn) > -1) {
        //Table custom column: Add enum for properties
        const customColumnDefinition = appSchema.definitions[customColumnDefinitionName];
        addEnumForProperties(lineItems, customColumnDefinition);
    }
    //Add property index
    for (let index = 0; index < sortedColumnsArray.length; index++) {
        const column = sortedColumnsArray[index][1];
        column[ux_specification_types_2.SchemaTag.propertyIndex] = index;
    }
}
/**
 * Common function for enhancing the LineItems definition of app schema by custom columns.
 *
 * @param appSchema - app-specific JSON schema
 * @param v4Page - actual page in the manifest
 * @param logger - logger for error messages
 * @param customColumnDefinitionName - custom column definition name, distinguishes LR from OP
 * @param sectionId - identifier of the current object page section in schema
 * @param sectionIdInManifest - identifier of the current object page section in manifest
 */
function addCustomColumnDefinition(appSchema, v4Page, logger, customColumnDefinitionName = ux_specification_types_2.DefinitionName.CustomColumn, sectionId, sectionIdInManifest) {
    const lineItemId = sectionId || ux_specification_types_2.DefinitionName.LineItems;
    const lineItems = appSchema.definitions[lineItemId];
    if (!lineItems) {
        return;
    }
    //sort line items
    let sortedColumnsArray = sortPropertiesRecords(lineItems);
    const id = sectionIdInManifest ? sectionIdInManifest.replace(/::/g, '/') : `@${"com.sap.vocabularies.UI.v1.LineItem" /* UIAnnotationTerms.LineItem */}`;
    const columns = v4Page.options?.settings?.controlConfiguration?.[id]?.['columns'];
    if (columns) {
        sortedColumnsArray = addExtensionToArray(columns, sortedColumnsArray, customColumnDefinitionName, undefined, logger);
    }
    //Adjust propertyIndex and add properties' enum
    addColumnPropertyIndexAndEnum(sortedColumnsArray, appSchema, lineItems, customColumnDefinitionName);
    const sortedColumnsAsObject = {};
    sortedColumnsArray.forEach(([key, value]) => (sortedColumnsAsObject[key] = value));
    appSchema.definitions[lineItemId].properties = sortedColumnsAsObject;
}
/**
 * Determines the appropriate action definition name based on the provided line item data and record type.
 *
 * @param {LineItemDataForSchema} data - The schema data for the line item, including its identifier and metadata.
 * @param {DataFieldAbstractTypes} lineItemRecord - The record representing a data field or action within the line item.
 * @returns {DefinitionName} The determined action definition name based on the provided data and group type.
 */
function determineActionDefinitionName(data, lineItemRecord) {
    const isGrouped = lineItemRecord.$Type === "com.sap.vocabularies.UI.v1.DataFieldForActionGroup" /* UIAnnotationTypes.DataFieldForActionGroup */;
    let actionDefinitionName;
    if (data.lineItemId.startsWith(ux_specification_types_2.DefinitionName.LineItemsOfView)) {
        actionDefinitionName = isGrouped ? ux_specification_types_2.DefinitionName.ViewToolBarActionGroup : ux_specification_types_2.DefinitionName.ViewToolBarAction;
    }
    else if (data.lineItemId.startsWith(ux_specification_types_2.DefinitionName.LineItems)) {
        actionDefinitionName = isGrouped ? ux_specification_types_2.DefinitionName.ToolBarActionGroup : ux_specification_types_2.DefinitionName.ToolBarAction;
    }
    else {
        actionDefinitionName = isGrouped
            ? ux_specification_types_2.DefinitionName.ObjectPageToolBarActionGroup
            : ux_specification_types_2.DefinitionName.ObjectPageToolBarAction;
    }
    return actionDefinitionName;
}
/**
 * Adds the schema tags 'keys' and 'target' to the schema definition of an action.
 *
 * @param {SchemaDefinition} actionDefinition - current action definition in the app schema
 * @param {DataFieldForActionAbstractTypes} lineItemRecord - actual record of the line item collection
 * @param {string} actionId - ID of the action, according to the lineItem definition
 */
function addTargetAndKeysOfAction(actionDefinition, lineItemRecord, actionId) {
    actionDefinition[ux_specification_types_2.SchemaTag.keys] = [];
    if (lineItemRecord[ux_specification_types_2.SchemaKeyName.semanticObject]) {
        actionDefinition[ux_specification_types_2.SchemaTag.keys].push({
            name: ux_specification_types_2.SchemaKeyName.semanticObject,
            value: lineItemRecord[ux_specification_types_2.SchemaKeyName.semanticObject]
        });
    }
    const { key, ns } = (0, common_1.getActionKey)(actionId, true);
    actionDefinition[ux_specification_types_2.SchemaTag.keys].push({ name: ux_specification_types_2.SchemaKeyName.action, value: key });
    if (ns) {
        actionDefinition[ux_specification_types_2.SchemaTag.target] = ns;
    }
}
/**
 * Adds an action record to a schema definition based on the provided line item definition parameters.
 * This involves defining action-specific properties, references, and metadata, and updating the schema accordingly.
 *
 * @param {AddLineItemDefinitionParams} lineItemDefinitionParams - The parameters describing the line item definition, including data, actions, path, record, and index.
 * @param {boolean} [createRef] - A flag indicating whether to create a reference for the action definition.
 * @returns {void} This function does not return a value.
 */
function addActionRecordToSchema(lineItemDefinitionParams, createRef = true) {
    const { lineItemData: data, actions: actionsDefinition, lineItemPath, lineItemRecord, index: recordIndex } = lineItemDefinitionParams;
    // Action but not inline action
    if (lineItemRecord.Determining === true) {
        return;
    }
    //no footer bar -> toolbar action
    const actionDefinitionName = determineActionDefinitionName(data, lineItemRecord);
    const description = (0, common_1.getDataFieldDescription)(lineItemRecord, data.entityType);
    const prefix = lineItemRecord.$Type.split(`${ux_specification_types_2.UIVOCABULARY}.`)[1];
    const actionId = typeof lineItemRecord.Action === 'string' ? lineItemRecord.Action : lineItemRecord.Action['path'];
    const propertyKey = (0, StableIdHelper_1.replaceSpecialChars)(actionId);
    const actionDefinition = (actionsDefinition.properties[`${prefix}::${propertyKey}`] = {
        description
    });
    if (createRef) {
        actionDefinition.$ref = (0, common_1.getUniqueFacetDefinitionLink)(actionDefinitionName, (0, common_1.prepareRef)(propertyKey), data.appSchema, lineItemPath);
    }
    else {
        actionDefinition.properties = {};
        actionDefinition.type = 'object';
        actionDefinition.isViewNode = true;
    }
    actionDefinition[ux_specification_types_2.SchemaTag.propertyIndex] = recordIndex;
    actionDefinition[ux_specification_types_2.SchemaTag.dataType] = (0, common_1.determineDataType)(lineItemRecord);
    //keys
    addTargetAndKeysOfAction(actionDefinition, lineItemRecord, actionId);
    actionDefinition[ux_specification_types_2.SchemaTag.annotationType] = lineItemRecord.$Type;
    if (createRef) {
        // Using previously computed ref instead of generating new one to support action duplication
        const previouslyComputedRef = actionDefinition.$ref.replace(utils_1.DEFINITION_LINK_PREFIX, '');
        const action = (0, common_1.parseSchemaDefinition)(actionDefinitionName, previouslyComputedRef, data.appSchema, false);
        action[ux_specification_types_2.SchemaTag.annotationPath] = `${lineItemPath}/${recordIndex}`;
    }
    else {
        actionDefinition[ux_specification_types_2.SchemaTag.annotationPath] = `${lineItemPath}/${recordIndex}`;
    }
}
/**
 * Adds a group action record to the schema based on the given parameters. This involves determining
 * action definitions, creating or referencing schema properties, and setting metadata fields.
 *
 * @param {AddLineItemDefinitionParams} lineItemDefinitionParams - Parameters that define the line item, including data, record, path, index, and actions.
 * @param {boolean} [createRef] - Indicates whether to create a reference for the action definition or to use an inline object.
 * @returns {void} - Does not return any value.
 */
function addGroupActionRecordToSchema(lineItemDefinitionParams, createRef = true) {
    const { lineItemData, lineItemRecord, lineItemPath, index, actions } = lineItemDefinitionParams;
    //no footer bar -> toolbar action
    const actionDefinitionName = determineActionDefinitionName(lineItemData, lineItemRecord);
    const propertyKey = (0, StableIdHelper_1.getStableIdPartFromDataField)(lineItemRecord);
    let actionDefinition = {};
    if (createRef) {
        actions.properties[`${propertyKey}`] = {
            $ref: (0, common_1.getFacetDefinitionLink)(actionDefinitionName, (0, common_1.prepareRef)(propertyKey))
        };
        actionDefinition = (0, common_1.parseSchemaDefinition)(actionDefinitionName, (0, common_1.prepareRef)(propertyKey), lineItemData.appSchema);
    }
    else {
        actions.properties[`${propertyKey}`] = actionDefinition;
    }
    // add a warning message for all versions that don't support action groups
    (0, common_1.addMessageToSchema)(actionDefinition, i18next_1.default.t('ACTION_GROUPS_ARENT_SUPPORTED'));
    actionDefinition.properties = {};
    actionDefinition.description = (0, common_1.getDataFieldDescription)(lineItemRecord, lineItemData.entityType);
    actionDefinition.type = 'object';
    actionDefinition.isViewNode = true;
    actionDefinition[ux_specification_types_2.SchemaTag.propertyIndex] = index;
    actionDefinition[ux_specification_types_2.SchemaTag.dataType] = (0, common_1.determineDataType)(lineItemRecord);
    actionDefinition[ux_specification_types_2.SchemaTag.annotationPath] = `${lineItemPath}/${index}`;
    (lineItemRecord['Actions'] ?? []).forEach((action, index) => {
        const lineItemActionDefinitionParams = {
            ...lineItemDefinitionParams,
            lineItemRecord: action,
            lineItemPath: `${actionDefinition[ux_specification_types_2.SchemaTag.annotationPath]}/Actions`,
            actions: actionDefinition,
            index
        };
        addActionRecordToSchema(lineItemActionDefinitionParams, createRef);
    });
}
/**
 * Adds a line item action definition to the schema based on the provided parameters.
 * Handles determining which action to take based on specific conditions of the line item record.
 *
 * @param {AddLineItemDefinitionParams} data - An object containing the details of the line item record and the line item definition.
 * @param {object} data.lineItemRecord - The record of the line item to be processed, containing relevant properties.
 * @param {boolean} data.lineItemRecord.Inline - Indicates whether the line item is inline.
 * @param {boolean} data.lineItemRecord.Determining - Indicates if the line item is determining.
 * @param {boolean} data.lineItemDefinition - Indicates whether the line item definition is present.
 * @returns {void} This method does not return a value.
 */
function addLineItemActionDefinition(data) {
    const { lineItemRecord, lineItemDefinition } = data;
    if (lineItemRecord.Inline !== true || lineItemRecord.Determining === true) {
        addActionRecordToSchema(data, !lineItemDefinition);
    }
    else {
        addLineItemRecordToSchema(data);
    }
}
/**
 * Adds a line item record to the provided schema based on the definition parameters.
 *
 * @param {AddLineItemDefinitionParams} lineItemDefinitionParams - The parameters defining the line item data, schema information, and record.
 * @returns {void} This function does not return a value.
 */
function addLineItemRecordToSchema(lineItemDefinitionParams) {
    const { lineItemData, lineItemRecord, lineItemDefinition, lineItemPath, index, columnDefinitionName } = lineItemDefinitionParams;
    const columnDefinition = lineItemRecord.$Type === "com.sap.vocabularies.UI.v1.DataFieldForAction" /* UIAnnotationTypes.DataFieldForAction */
        ? `${columnDefinitionName}Action`
        : columnDefinitionName;
    const lineItemId = lineItemData.lineItemId;
    if (lineItemRecord['Target']?.['value']) {
        const regex = `@${(0, utils_1.findAlias)(ux_specification_types_2.UIVOCABULARY, lineItemData.oDataServiceAVT)}.`;
        lineItemRecord['Target']['value'] = lineItemRecord['Target']['value'].replace(regex, '@');
    }
    const schemaKey = (0, StableIdHelper_1.getStableIdPartFromDataField)(lineItemRecord).replace(/\//g, '::');
    if (schemaKey) {
        let columnsDefinition = lineItemDefinition;
        if (!columnsDefinition) {
            columnsDefinition = lineItemData.appSchema.definitions[lineItemId];
        }
        const properties = columnsDefinition.properties;
        const property = {
            description: (0, common_1.getDataFieldDescription)(lineItemRecord, lineItemData.entityType)
        };
        if (lineItemDefinition) {
            property.properties = {};
            property.type = 'object';
            property.isViewNode = true;
        }
        else {
            property.$ref = utils_1.DEFINITION_LINK_PREFIX + columnDefinition;
        }
        property[ux_specification_types_2.SchemaTag.annotationType] = lineItemRecord?.$Type;
        property[ux_specification_types_2.SchemaTag.annotationPath] = `${lineItemPath}/${index}`;
        property[ux_specification_types_2.SchemaTag.propertyIndex] = index;
        property[ux_specification_types_2.SchemaTag.dataType] = (0, common_1.determineDataType)(lineItemRecord);
        properties[schemaKey] = property;
        (0, common_1.addKeyToDefinition)(lineItemRecord, properties, schemaKey);
    }
}
/**
 * Appends line item columns and actions to the app schema (for the list report, custom page or an object page section comprising a table).
 *
 * @param {LineItemDataForSchema} data structure comprising
 * - appSchema - the app specific schema that shall get enhanced
 * - lineItemAnnotation - the UI.LineItem annotation, comprising all records
 * - entityType - the entity type as part of the AVT ConvertedMetadata
 * - oDataServiceAVT - complete service information, as returned by Annotation Vocabularies Tool
 * - lineItemId - in case of OP the parameter must be passed to distinguish the OP tables;
 *                in case of LR or ALP 'LineItems' is passed.
 * @param {Definition} actions - actions definition in schema, parent object
 * @param {string} lineItemPath - annotation path to the line item
 * @param {Definition | undefined} lineItemDefinition - line item definition
 * @param {string} columnDefinitionName - line item definition name
 */
function appendLineItemsToSchema(data, actions, lineItemPath, lineItemDefinition, columnDefinitionName = ux_specification_types_2.DefinitionName.TableColumn) {
    if (!data.lineItemAnnotation) {
        return;
    }
    let i = 0;
    data.lineItemAnnotation.forEach((lineItemRecord) => {
        const addLineItemDefinitionsParams = {
            lineItemData: data,
            actions,
            lineItemPath,
            lineItemRecord: lineItemRecord,
            index: i,
            lineItemDefinition,
            columnDefinitionName
        };
        const strategy = DataFieldStrategy_1.dataFieldStrategyContext.getStrategy(lineItemRecord.$Type);
        strategy.addLineItemDefinition(addLineItemDefinitionsParams);
        i++;
    });
}
/**
 * Adds the line item definition, columns and actions to the app schema (for the list report, custom page or an object page section comprising a table.
 *
 * @param data structure comprising
 * - isObjectPage - indicates that the page is an object page
 * - appSchema - the app specific schema that shall get enhanced
 * - lineItemAnnotation - the UI.LineItem annotation, comprising all records
 * - entityType - the entity type as part of the AVT ConvertedMetadata
 * - oDataServiceAVT - complete service information, as returned by Annotation Vocabularies Tool
 * - lineItemId - in case of OP the parameter must be passed to distinguish the OP tables;
 *                in case of LR or ALP 'LineItems' is passed.
 * @param columnDefinitionName - name of the column definition, i.e. TableColumn or ObjectPageTableColumn
 * @param customColumnDefinitionName - name of the custom column definition
 * @param customActionDefinitionName - name of the custom action definition
 */
function addLineItemsTypeToSchema(data, columnDefinitionName = ux_specification_types_2.DefinitionName.TableColumn, customColumnDefinitionName = ux_specification_types_2.DefinitionName.CustomColumn, customActionDefinitionName = ux_specification_types_2.DefinitionName.CustomTableAction) {
    const { actions, lineItemPath } = (0, common_1.addCommonLineItemDefinitions)(data.isObjectPage, data.appSchema, data.lineItemAnnotation, data.entityType, data.lineItemId, customColumnDefinitionName, customActionDefinitionName);
    appendLineItemsToSchema(data, actions, lineItemPath, undefined, columnDefinitionName);
}
/**
 * Adds an enum or value help to position > anchor of custom column.
 *
 * @param appSchema - app specific JSON schema
 * @param lineItemId - ID of the current line item in schema
 * @param v4Page - current page in manifest
 * @param positionName - ID of the definition of custom column position in schema
 * @param sectionIdInManifest - identifier of the current object page section in manifest
 */
function addFragmentEnumForAnchor(appSchema, lineItemId, v4Page, positionName = ux_specification_types_2.DefinitionName.Position, sectionIdInManifest) {
    const columns = appSchema.definitions[lineItemId]?.properties;
    const enumEntries = [];
    if (columns) {
        for (const key in columns) {
            if (key !== 'custom') {
                enumEntries.push(key);
            }
        }
    }
    const id = lineItemId !== ux_specification_types_2.DefinitionName.LineItems ? sectionIdInManifest : `@${"com.sap.vocabularies.UI.v1.LineItem" /* UIAnnotationTerms.LineItem */}`;
    const columnsInManifest = v4Page.options?.settings?.controlConfiguration?.[id]?.['columns'];
    if (columnsInManifest) {
        for (const key in columnsInManifest) {
            if (enumEntries.indexOf(key) === -1) {
                enumEntries.push(key);
            }
        }
    }
    if (enumEntries.length > 0) {
        const anchor = appSchema.definitions[positionName].properties.anchor;
        (0, common_1.addEnumToSchema)(enumEntries, anchor);
    }
}
/**
 * Adds an enum or value help to position > anchor of custom column or custom action.
 *
 * @param appSchema - app specific JSON schema
 * @param definitionId - definition key of actions
 * @param positionName - target definition to update
 */
function addEnumForActionAnchor(appSchema, definitionId, positionName = ux_specification_types_2.DefinitionName.CustomActionPosition) {
    (0, common_1.addDescriptiveEnumDefinition)(appSchema, appSchema.definitions[definitionId], {
        definition: positionName,
        property: 'anchor'
    }, {
        resolveDefinition: true
    });
}
/**
 * Find the relevant V4 page under the routing targets of manifest,json.
 *
 * @param pages - list of all pages in manifest
 * @param templateName - search criterion: template name
 * @param entitySet - search criterion: entity set object from AVT
 * @param contextPath - search criterion: contextPath
 * @returns the page definition in manifest (if found)
 */
function findPageV4(pages, templateName, entitySet, contextPath) {
    let v4Page;
    for (const i in pages) {
        const pageSettings = pages[i].options?.settings || {};
        const isConnectionMatches = (contextPath && pageSettings.contextPath === contextPath) ||
            (entitySet?.name && pageSettings.entitySet === entitySet.name);
        if (isConnectionMatches &&
            ((0, common_1.compareTemplateNames)(templateName, pages[i].name) ||
                (templateName === ux_specification_types_2.v4.FE_TEMPLATE_V4_ALP && pages[i].name === ux_specification_types_2.v4.FE_TEMPLATE_V4_LIST_REPORT))) {
            v4Page = pages[i];
            break;
        }
    }
    return v4Page;
}
/**
 * Depending on the template type, strip down the app schema so that only the relevant views are part of it.
 *
 * @param {Definition} appSchema - app specific JSON schema, to be adjusted
 * @param {GenerateAppSchemaParameters} generateParameters - object comprising all input parameters
 * @returns the right definition name for the table in the schema
 */
function alignSchemaWithTemplateType(appSchema, generateParameters) {
    let tableDefinitionName;
    const tableDefinition = appSchema.properties[ux_specification_types_2.PropertyName.table];
    if (generateParameters.templateType === ux_specification_types_2.TemplateType.AnalyticalListPageV4) {
        tableDefinitionName = ux_specification_types_2.DefinitionName.ALPTableView;
        delete tableDefinition.anyOf;
        tableDefinition.$ref = `${utils_1.DEFINITION_LINK_PREFIX}${ux_specification_types_2.DefinitionName.ALPTableView}`;
        delete appSchema.definitions[ux_specification_types_2.DefinitionName.Table];
        delete appSchema.definitions[ux_specification_types_2.DefinitionName.LRChartView];
        delete appSchema.definitions[ux_specification_types_2.DefinitionName.LRTableView];
        delete appSchema.definitions[ux_specification_types_2.DefinitionName.MultiTableModeV4];
    }
    else if (generateParameters.templateType === ux_specification_types_2.TemplateType.ListReportObjectPageV4) {
        tableDefinitionName = ux_specification_types_2.DefinitionName.Table;
        delete tableDefinition.anyOf;
        tableDefinition.$ref = `${utils_1.DEFINITION_LINK_PREFIX}${ux_specification_types_2.DefinitionName.Table}`;
        appSchema.definitions[tableDefinitionName].properties[ux_specification_types_2.PropertyName.annotationPath][ux_specification_types_2.SchemaTag.hidden] = true;
        delete appSchema.definitions[ux_specification_types_2.DefinitionName.ALPTableView];
        appSchema.properties[ux_specification_types_2.PropertyName.defaultPath][ux_specification_types_2.SchemaTag.hidden] = true;
    }
    return tableDefinitionName;
}
/**
 * Common function for enhancing LineItems, FieldGroups and Custom Section definitions of app schema by custom action definitions.
 *
 * @param appSchema - app-specific JSON schema
 * @param v4Page - actual page in the manifest
 * @param logger - logger for error messages
 * @param customActionDefinitionName - definition name of custom action
 * @param sectionDefinitionName - identifier of the current object page section in schema
 * @param sectionIdInManifest - identifier of the current object page section in manifest
 */
function addCustomActionDefinition(appSchema, v4Page, logger, customActionDefinitionName = ux_specification_types_2.DefinitionName.CustomTableAction, sectionDefinitionName = '', sectionIdInManifest = '') {
    const definition = appSchema.definitions[sectionDefinitionName];
    if (!definition) {
        return;
    }
    // Sort existing actions
    let sortedActionsArray = sortPropertiesRecords(definition);
    let configId;
    if (sectionIdInManifest) {
        if (customActionDefinitionName.indexOf(ux_specification_types_2.DefinitionName.CustomFormActionOP) !== -1) {
            configId = sectionIdInManifest.replace(/::/g, '#');
        }
        else {
            configId = sectionIdInManifest.replace(/::/g, '/');
        }
    }
    else {
        if (customActionDefinitionName === ux_specification_types_2.DefinitionName.CustomFormActionOP) {
            configId = `@${"com.sap.vocabularies.UI.v1.FieldGroup" /* UIAnnotationTerms.FieldGroup */}`;
        }
        else {
            configId = `@${"com.sap.vocabularies.UI.v1.LineItem" /* UIAnnotationTerms.LineItem */}`;
        }
    }
    let actions;
    if (sectionDefinitionName.includes(ux_specification_types_2.DefinitionName.ObjectPageCustomSectionActions)) {
        actions = v4Page.options?.settings?.content?.body?.sections?.[configId]?.['actions'];
    }
    else {
        actions = v4Page.options?.settings?.controlConfiguration?.[configId]?.['actions'];
    }
    if (actions) {
        sortedActionsArray = addExtensionToArray(actions, sortedActionsArray, customActionDefinitionName, 'press', logger);
    }
    // Adjust propertyIndex
    if (sortedActionsArray) {
        for (let index = 0; index < sortedActionsArray.length; index++) {
            sortedActionsArray[index][1][ux_specification_types_2.SchemaTag.propertyIndex] = index;
        }
        const sortedActionsAsObject = {};
        sortedActionsArray.forEach(([key, value]) => (sortedActionsAsObject[key] = value));
        appSchema.definitions[sectionDefinitionName].properties = sortedActionsAsObject;
    }
}
/**
 * Common function for enhancing header and footer definitions of app schema by custom action definitions.
 *
 * @param appSchema - app-specific JSON schema
 * @param v4Page - actual page in the manifest
 * @param logger - logger for error messages
 * @param customActionDefinitionName - definition name of custom action
 * @param sectionId - identifier of the current object page section in schema
 */
function addHeaderFooterCustomActionDefinition(appSchema, v4Page, logger, customActionDefinitionName = ux_specification_types_2.DefinitionName.CustomHeaderActionOP, sectionId = '') {
    const definition = appSchema.definitions[sectionId];
    if (!definition) {
        return;
    }
    // Sort existing actions
    let sortedActionsArray = sortPropertiesRecords(definition);
    let actions;
    if ([ux_specification_types_2.DefinitionName.CustomHeaderAction, ux_specification_types_2.DefinitionName.CustomHeaderActionOP].includes(customActionDefinitionName)) {
        actions = v4Page.options?.settings?.content?.header?.['actions'];
    }
    else {
        actions = v4Page.options?.settings?.content?.footer?.['actions'];
    }
    if (actions) {
        sortedActionsArray = addExtensionToArray(actions, sortedActionsArray, customActionDefinitionName, 'press', logger);
    }
    // Adjust propertyIndex
    const sortedActionsAsObject = {};
    if (sortedActionsArray) {
        for (let index = 0; index < sortedActionsArray.length; index++) {
            sortedActionsArray[index][1][ux_specification_types_2.SchemaTag.propertyIndex] = index;
        }
        sortedActionsArray.forEach(([key, value]) => (sortedActionsAsObject[key] = value));
    }
    appSchema.definitions[sectionId].properties = sortedActionsAsObject;
}
/**
 * Method returns page from manifest by passed page key.
 *
 * @param manifest Object from manifest.json.
 * @param pageId Page id.
 * @param logger Logger to report error of unexisting page.
 * @returns Manifest's target page.
 */
function getManifestPage(manifest, pageId, logger) {
    const pages = (0, utils_1.getJSONPropertyByPath)(manifest, [
        ux_specification_types_2.ManifestSection.ui5,
        'routing',
        'targets'
    ]);
    if (!pages) {
        (0, __1.log)(logger, {
            severity: "error" /* LogSeverity.Error */,
            message: i18next_1.default.t('NOTARGETS'),
            location: {
                path: ux_specification_types_2.MANIFESTPATH,
                range: [ux_specification_types_2.ManifestSection.ui5, 'routing']
            }
        });
        return;
    }
    const page = (0, utils_1.getJSONPropertyByPath)(pages, [pageId]);
    if (!page) {
        (0, __1.log)(logger, {
            severity: "error" /* LogSeverity.Error */,
            message: i18next_1.default.t('NOROUTINGID', { routingId: pageId }),
            location: {
                path: ux_specification_types_2.MANIFESTPATH,
                range: [ux_specification_types_2.ManifestSection.ui5, 'routing']
            }
        });
        return;
    }
    return page;
}
/**
 * Method finds custom view/section XML file for passed page.
 *
 * @param files All extension files.
 * @param page - the page object containing routing target options
 * @param manifest Object from manifest.json.
 * @param xmlType XML file type - view or fragment.
 * @param extensionName Extension namespace or path to extension name in page object.
 * @returns Custom page's data containing XML file.
 */
function getPageCustomExtensionFile(files, page, manifest, xmlType, extensionName) {
    if (extensionName) {
        const appId = manifest['sap.app']?.id || '';
        const fileExtension = 'xml';
        if (extensionName.startsWith(appId)) {
            // Remove app id from extension name
            extensionName = extensionName.replace(appId, '');
        }
        const fileParts = extensionName.split('.');
        let baseName = fileParts.pop();
        baseName = `${baseName}.${xmlType}.${fileExtension}`;
        const extPath = (0, path_1.join)(...fileParts, baseName);
        const file = files.find((file) => file.dataSourceUri.endsWith(extPath));
        if (file) {
            const settings = page.options?.settings;
            return {
                file,
                relativeFilePath: extPath,
                connection: {
                    contextPath: settings?.contextPath,
                    entitySet: settings?.entitySet
                }
            };
        }
    }
    return undefined;
}
/**
 * Method finds view XML file for passed page.
 *
 * @param files All view files.
 * @param pageId Page id.
 * @param manifest Object from manifest.json.
 * @param logger Logger.
 * @returns Custom page's data containing view XML file.
 */
function getPageCustomViewFile(files, pageId, manifest, logger) {
    const page = getManifestPage(manifest, pageId, logger);
    const viewName = (0, utils_1.getJSONPropertyByPath)(page, ['options', 'settings', 'viewName']);
    return page && typeof viewName === 'string'
        ? getPageCustomExtensionFile(files, page, manifest, 'view', viewName)
        : undefined;
}
/**
 * Adds custom section or custom sub section definitions to app schema.
 *
 * @param appSchema - app-specific JSON schema
 * @param definition - sections definition
 * @param v4Page - actual page in the manifest
 * @param customSectionRef - value of custom section ref
 * @param isMergedSections - are merged section used
 * @param facetKey - facet key
 * @param logger - logger for error messages
 */
function addCustomSectionDefinition(appSchema, definition, v4Page, customSectionRef, isMergedSections, facetKey, logger) {
    let sortedSectionsArray = sortPropertiesRecords(definition);
    const annotationSectionsMap = new Map();
    sortedSectionsArray = sortedSectionsArray.map((annotationSection) => {
        const entry = (0, common_1.getEnumEntry)(appSchema, annotationSection[1], annotationSection[0], {
            keyProperties: [ux_specification_types_2.SchemaKeyName.id],
            descriptionAsFallback: true,
            resolveDefinition: true
        });
        annotationSectionsMap.set(entry.const, annotationSection[0]);
        return [entry.const, annotationSection[1]];
    });
    if (facetKey) {
        // check for already defined section
        const section = v4Page.options?.settings?.content?.body?.sections?.[facetKey];
        if (section && 'subSections' in section) {
            // add extension to subsection of section
            sortedSectionsArray = addExtensionToArray(section.subSections, sortedSectionsArray, customSectionRef, 'template', logger, isMergedSections);
        }
    }
    else if (customSectionRef.includes(ux_specification_types_2.DefinitionName.ObjectPageCustomHeaderSectionFragment)) {
        // header custom section extensions
        const header = v4Page.options?.settings?.content?.header;
        if (header && 'facets' in header) {
            // add extension to header section
            sortedSectionsArray = addExtensionToArray(header.facets, sortedSectionsArray, customSectionRef, 'template', logger, isMergedSections);
        }
    }
    else {
        // body custom section extensions
        const sections = v4Page.options?.settings?.content?.body?.sections;
        if (sections) {
            // add extension to sections section
            sortedSectionsArray = addExtensionToArray(sections, sortedSectionsArray, customSectionRef, 'template', logger, isMergedSections);
        }
    }
    // Adjust propertyIndex
    for (let index = 0; index < sortedSectionsArray.length; index++) {
        sortedSectionsArray[index][1][ux_specification_types_2.SchemaTag.propertyIndex] = index;
    }
    const sortedActionsAsObject = {};
    sortedSectionsArray.forEach(([key, value]) => {
        key = annotationSectionsMap.get(key) || key;
        sortedActionsAsObject[key] = value;
    });
    definition.properties = sortedActionsAsObject;
}
/**
 * Method adds custom filter fields from manifest to schema properties.
 *
 * @param appSchema - app-specific JSON schema
 * @param definition - filter fields definition
 * @param v4Page - actual page in the manifest
 */
function addCustomFilterFieldDefinition(appSchema, definition, v4Page) {
    let sortedFilterFieldsArray = sortPropertiesRecords(definition);
    const annotationSectionsMap = new Map();
    sortedFilterFieldsArray = sortedFilterFieldsArray.map((annotationSection) => {
        const entry = (0, common_1.getEnumEntry)(appSchema, annotationSection[1], annotationSection[0], {
            keyProperties: [ux_specification_types_2.SchemaKeyName.value],
            descriptionAsFallback: true,
            resolveDefinition: true
        });
        annotationSectionsMap.set(entry.const, annotationSection[0]);
        return [entry.const, annotationSection[1]];
    });
    // check for already defined section
    const selectionFieldsEntry = v4Page.options?.settings?.controlConfiguration?.[`@${"com.sap.vocabularies.UI.v1.SelectionFields" /* UIAnnotationTerms.SelectionFields */}`];
    if (typeof selectionFieldsEntry === 'object' && 'filterFields' in selectionFieldsEntry) {
        // add extension to subsection of section
        sortedFilterFieldsArray = addExtensionToArray(selectionFieldsEntry.filterFields, sortedFilterFieldsArray, ux_specification_types_2.DefinitionName.CustomFilterField, 'template');
    }
    // Adjust propertyIndex
    for (let index = 0; index < sortedFilterFieldsArray.length; index++) {
        sortedFilterFieldsArray[index][1][ux_specification_types_2.SchemaTag.propertyIndex] = index;
    }
    const sortedFilterFieldsAsObject = {};
    sortedFilterFieldsArray.forEach(([key, value]) => {
        key = annotationSectionsMap.get(key) || key;
        sortedFilterFieldsAsObject[key] = value;
    });
    definition.properties = sortedFilterFieldsAsObject;
}
/**
 * Imports action settings into a configuration object and applies necessary transformations based on provided parameters.
 *
 * @param {object} importActionParams - Parameters required for importing action settings, including schema, factory, and action specifications.
 * @param {string} key - The key used to identify the specific configuration or schema definition.
 * @param {boolean} [keepEmptyAction] - Determines whether to keep empty actions in the configuration object.
 * @returns {void} This method does not return any value.
 */
function importActionToConfigurationObject(importActionParams, key, keepEmptyAction = false) {
    const { appSchema, factory, actionsInConfig, actionKey, manifest, routingId, manifestSectionId, targetAnnotation } = importActionParams;
    const schemaPropertyName = (key ?? '').split('<')[0];
    const metaInstance = factory.createInstance(ux_specification_types_1.PageTypeV4.ObjectPage, schemaPropertyName);
    const breadcrumbs = [actionKey.replace('/', '??')];
    if (targetAnnotation) {
        breadcrumbs.push(targetAnnotation);
    }
    if (metaInstance) {
        const action = (actionsInConfig[actionKey] = metaInstance);
        (0, utils_2.importSettingsOfObject)(action, manifest, appSchema.definitions[key], routingId, breadcrumbs, manifestSectionId);
        if (!keepEmptyAction) {
            (0, common_1.removeEmptyStructure)(actionsInConfig, actionKey);
        }
    }
}
/**
 * Imports the settings of a single action reference into the configuration object.
 *
 * @param {ImportActionSettingsOfReferenceParams} importActionParams - The parameters required for importing action settings, including property definitions.
 * @param {Definition} definitionOfReference - The reference definition object used to resolve the action.
 * @returns {void} This function does not return a value.
 */
function importSingleActionSettingsOfReference(importActionParams, definitionOfReference) {
    const { actionPropertyDefinition } = importActionParams;
    const key = (0, utils_1.getDefinitionKey)(definitionOfReference.$ref || actionPropertyDefinition.$ref);
    importActionToConfigurationObject(importActionParams, key);
}
/**
 * Imports and processes the settings for a group of actions based on a reference definition.
 *
 * @param {ImportActionSettingsOfReferenceParams} importActionParams - The parameters used for importing and configuring the action settings.
 * @param {Definition} definitionOfReference - The reference definition from which the action group settings are imported.
 * @returns {void} This function does not return a value; it modifies the configurations directly.
 */
function importGroupActionSettingsOfReference(importActionParams, definitionOfReference) {
    const { actionPropertyDefinition, appSchema, actionsInConfig, actionKey } = importActionParams;
    // create an instance of the action group in the configuration object
    const key = (0, utils_1.getDefinitionKey)(definitionOfReference.$ref ?? actionPropertyDefinition.$ref);
    importActionToConfigurationObject(importActionParams, key, true);
    // newly created action group instance is available in the actionsInConfig object
    const actionGroup = actionsInConfig[actionKey];
    // add a warning message for all versions that don't support action groups
    (0, common_1.addMessageToSchema)(actionGroup, i18next_1.default.t('ACTION_GROUPS_ARENT_SUPPORTED'));
    // fill the action group with the action settings of the group action
    const { properties } = definitionOfReference;
    for (const propertyKey in properties) {
        const actionInGroupProperty = properties[propertyKey];
        const actionInGroupPropertyKey = (0, utils_1.getDefinitionKey)(actionInGroupProperty['$ref']);
        const actionInGroupDefinition = appSchema.definitions[actionInGroupPropertyKey];
        const key = (0, utils_1.getDefinitionKey)(actionInGroupDefinition.$ref ?? actionInGroupProperty['$ref']);
        const importGroupedActionParams = {
            ...importActionParams,
            actionsInConfig: actionGroup,
            actionKey: propertyKey
            // targetAnnotation: undefined
        };
        importActionToConfigurationObject(importGroupedActionParams, key);
    }
    (0, common_1.removeEmptyStructure)(actionsInConfig, actionKey);
}
/**
 * Imports the action settings of a specified reference based on the given parameters.
 *
 * @param {object} importActionParams - The parameters required for importing action settings.
 * @param {object} importActionParams.actionPropertyDefinition - The action property definition containing the $ref to the reference.
 * @param {object} importActionParams.appSchema - The application schema containing definitions and other related metadata.
 * @returns {void} This function does not return a value.
 */
function importActionSettingsOfReference(importActionParams) {
    const { actionPropertyDefinition, appSchema } = importActionParams;
    const definitionKey = (0, utils_1.getDefinitionKey)(actionPropertyDefinition.$ref);
    const definitionOfReference = appSchema.definitions[definitionKey];
    const actionType = definitionOfReference['dataType'];
    if (actionType === exports.DATA_FIELD_FOR_ACTION_GROUP) {
        importGroupActionSettingsOfReference(importActionParams, definitionOfReference);
    }
    else {
        importSingleActionSettingsOfReference(importActionParams, definitionOfReference);
    }
}
/**
 * Enhances the application schema with custom field definitions for Object Page sections.
 *
 * @param appSchema - The application-specific JSON schema object representing the Object Page.
 * @param v4Page - The current Object Page configuration from the manifest (V4 format).
 * @param fieldGroupInManifest - The manifest identifier for the Object Page section associated with the field definitions.
 * @param logger - Logger instance for reporting or debugging schema processing errors.
 * @param customFieldDefinitionName - The schema definition name to be used for custom fields (defaults to `CustomTableAction`).
 * @param fieldsDefinitionName - The schema definition name for the set of fields being enhanced.
 */
function addCustomFieldDefinition(appSchema, v4Page, fieldGroupInManifest, logger, customFieldDefinitionName, fieldsDefinitionName) {
    const definition = appSchema.definitions[fieldsDefinitionName];
    if (!definition) {
        return;
    }
    // Sort existing actions
    let sortedFieldsArray = sortPropertiesRecords(definition);
    const configId = fieldGroupInManifest.replace(/::/g, '#');
    const fields = v4Page.options?.settings?.controlConfiguration?.[configId]?.['fields'];
    if (fields) {
        sortedFieldsArray = addExtensionToArray(fields, sortedFieldsArray, customFieldDefinitionName, 'template', logger);
    }
    // Adjust propertyIndex
    if (sortedFieldsArray) {
        for (let index = 0; index < sortedFieldsArray.length; index++) {
            sortedFieldsArray[index][1][ux_specification_types_2.SchemaTag.propertyIndex] = index;
        }
        const sortedFieldsAsObject = {};
        sortedFieldsArray.forEach(([key, value]) => (sortedFieldsAsObject[key] = value));
        appSchema.definitions[fieldsDefinitionName].properties = sortedFieldsAsObject;
    }
}
//# sourceMappingURL=utils.js.map