"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataType = void 0;
exports.addEnumToSchema = addEnumToSchema;
exports.getListOfValidAnnotations = getListOfValidAnnotations;
exports.addEnumForValidAnnotations = addEnumForValidAnnotations;
exports.addEnumForSingleTabVariant = addEnumForSingleTabVariant;
exports.addEnumForMultiTabVariant = addEnumForMultiTabVariant;
exports.addEnumForVariantEntitySet = addEnumForVariantEntitySet;
exports.addEnumFieldGroupAnnotationPath = addEnumFieldGroupAnnotationPath;
exports.addDefinitionForRelatedFacetKeys = addDefinitionForRelatedFacetKeys;
exports.getFacetKeyInSchema = getFacetKeyInSchema;
exports.getFacetDefinitionKey = getFacetDefinitionKey;
exports.parseSchemaDefinition = parseSchemaDefinition;
exports.getCustomExtensionDefinitionName = getCustomExtensionDefinitionName;
exports.addCommonLineItemDefinitions = addCommonLineItemDefinitions;
exports.getDataTypeFromAnnotation = getDataTypeFromAnnotation;
exports.determineDataTypeOfTarget = determineDataTypeOfTarget;
exports.determineDataType = determineDataType;
exports.addDataTypeToDefinition = addDataTypeToDefinition;
exports.getFacetDefinitionLink = getFacetDefinitionLink;
exports.getUniqueFacetDefinitionLink = getUniqueFacetDefinitionLink;
exports.addDefinitionRef = addDefinitionRef;
exports.getFacetAnnotationPath = getFacetAnnotationPath;
exports.handleAddressContact = handleAddressContact;
exports.addFieldsType = addFieldsType;
exports.getEnumEntry = getEnumEntry;
exports.addDescriptiveEnumDefinition = addDescriptiveEnumDefinition;
exports.getActionKey = getActionKey;
exports.addKeyToElement = addKeyToElement;
exports.addKeyToDefinition = addKeyToDefinition;
exports.getDataFieldDescription = getDataFieldDescription;
exports.addMessageToSchema = addMessageToSchema;
const __1 = require("..");
const ux_specification_types_1 = require("@sap/ux-specification-types");
const StableIdHelper_1 = require("../../v4/utils/StableIdHelper");
const i18next_1 = __importDefault(require("i18next"));
const DataFieldStrategy_1 = require("../DataFieldStrategy");
/**
 * Adds enum values to the app schema. Either as 'enum' -  if multiple entries exist,
 * or as 'const', if it is only a single value.
 *
 * @param enumEntries - array of strings for setting up the enum definition
 * @param currentDefinition - currentDefinition in the schema
 * @param multiSelect - indication for multi selection with comma separate string approach
 */
function addEnumToSchema(enumEntries, currentDefinition, multiSelect = false) {
    if (!currentDefinition) {
        return;
    }
    if (enumEntries.length > 0) {
        if (enumEntries.length > 1) {
            currentDefinition.enum = enumEntries;
        }
        else {
            currentDefinition.const = enumEntries[0];
        }
    }
    if (multiSelect) {
        currentDefinition.multiSelect = multiSelect;
    }
}
/**
 * Determines the existing UI annotations of the given list (validAnnotations).
 *
 * @param entityType - The entity type containing annotations to be processed
 * @param validAnnotations - List of valid UI annotation terms to be processed
 * @returns the list of valid annotations
 */
function getListOfValidAnnotations(entityType, validAnnotations) {
    const enumEntries = [];
    const uiAnnotations = entityType?.annotations?.UI;
    if (uiAnnotations) {
        for (const key in uiAnnotations) {
            const annotation = uiAnnotations[key];
            if (validAnnotations.indexOf(annotation.term) > -1) {
                const enumEntry = annotation.qualifier
                    ? `${annotation.term}#${annotation.qualifier}`
                    : `${annotation.term}`;
                if (enumEntries.indexOf(enumEntry) === -1) {
                    enumEntries.push(enumEntry);
                }
            }
        }
    }
    return enumEntries;
}
/**
 * Adds an enum filled with existing UI annotations of the given list (validAnnotations).
 *
 * @param {EntityType} entityType - The entity type containing annotations to be processed
 * @param {UIAnnotationTerms[]} validAnnotations - List of valid UI annotation terms to be processed
 * @param {Definition} annoPath - the annotation path property in the app schema where the enum shall be added
 */
function addEnumForValidAnnotations(entityType, validAnnotations, annoPath) {
    const enumEntries = getListOfValidAnnotations(entityType, validAnnotations);
    if (enumEntries.length > 0) {
        addEnumToSchema(enumEntries, annoPath);
    }
}
/**
 * Adds an enum filled with existing UI annotations for single-tab variants of a table.
 *
 * @param {EntityType} entityType - The entity type containing annotations to be processed
 * @param {Definition} appSchema - app specific JSON schema
 * @param definitionName - name of the definition in the app schema
 */
function addEnumForSingleTabVariant(entityType, appSchema, definitionName) {
    const annoPath = appSchema.definitions[definitionName].properties[ux_specification_types_1.SchemaTag.annotationPath];
    const validAnnotations = ["com.sap.vocabularies.UI.v1.SelectionVariant" /* UIAnnotationTerms.SelectionVariant */, "com.sap.vocabularies.UI.v1.SelectionPresentationVariant" /* UIAnnotationTerms.SelectionPresentationVariant */];
    addEnumForValidAnnotations(entityType, validAnnotations, annoPath);
}
/**
 * Adds an enum filled with existing UI annotations for multi-tab variants of a table.
 *
 * @param appSchema - app specific JSOn schema
 * @param definitionName - name of the definition in the app schema
 * @param {EntitySet} entitySet - current entity set of the page or view
 */
function addEnumForMultiTabVariant(appSchema, definitionName, entitySet) {
    const annoPath = appSchema.definitions[definitionName]?.properties.annotationPath;
    const validAnnotations = ["com.sap.vocabularies.UI.v1.SelectionVariant" /* UIAnnotationTerms.SelectionVariant */, "com.sap.vocabularies.UI.v1.SelectionPresentationVariant" /* UIAnnotationTerms.SelectionPresentationVariant */];
    addEnumForValidAnnotations(entitySet.entityType, validAnnotations, annoPath);
}
/**
 * Adds the enum values for entitySet as part of the multiple view scenario.
 *
 * @param {ConvertedMetadata} oDataServiceAVT - combined service metadata, as returned by annotation vocabularies tools
 * @param appSchema - app specific JSOn schema
 * @param definitionName - name of the definition in the app schema
 */
function addEnumForVariantEntitySet(oDataServiceAVT, appSchema, definitionName) {
    const entitySet = appSchema.definitions[definitionName].properties.entitySet;
    const enumEntries = [];
    oDataServiceAVT.entitySets.forEach((es) => {
        enumEntries.push(es.name);
    });
    addEnumToSchema(enumEntries, entitySet);
}
/**
 * Adds an enum filled with existing UI FieldGroup annotations for annotationPath property in MultiEdit.
 *
 * @param entityType - The entity type containing annotations to be processed
 * @param appSchema - app specific JSOn schema
 * @param definitionName - name of the definition in the app schema
 */
function addEnumFieldGroupAnnotationPath(entityType, appSchema, definitionName) {
    const annoPath = appSchema.definitions[definitionName].properties.annotationPath;
    const validAnnotations = ["com.sap.vocabularies.UI.v1.FieldGroup" /* UIAnnotationTerms.FieldGroup */];
    addEnumForValidAnnotations(entityType, validAnnotations, annoPath);
}
/**
 * Method adds definition for 'RelatedFacetKeys' as enum with description and adds references to 'RelatedFacetKeys' for custom section definitions.
 *
 * @param appSchema App specific schema that potentially gets enhanced
 * @param sectionDefinitions array of section definitions which should be updated with new reference to 'RelatedFacetKeys' enum.
 * @param facetSections Array of facet section objects which is used to generate enum values.
 * @param idProperties Array of property names which should be looked up in 'FacetSection' object.
 *  Please note that method depends on order and takes first non empty value associated to passed properties.
 */
function addDefinitionForRelatedFacetKeys(appSchema, sectionDefinitions, facetSections, idProperties) {
    const oneOfSections = facetSections.map((section) => {
        // Loop acceptable properties in received order and find first entry with value
        const propertyName = idProperties.find((property) => !!section[property]);
        const schemaIdForSection = section[propertyName];
        const label = section.label || section.title;
        return {
            const: schemaIdForSection,
            ...(label && { description: label }),
            ...(section.custom && { custom: section.custom })
        };
    });
    // Change 'relatedFacet' only when we have entries for sections - otherwise use generic.
    if (oneOfSections.length) {
        // Create new definition in schema as 'oneOf'.
        // Simpler way would be to use 'enum', but then there no option to pass description.
        appSchema.definitions[ux_specification_types_1.DefinitionName.RelatedFacetKeys] = {
            type: 'string',
            oneOf: oneOfSections
        };
        // Add enum definition
        for (const name of sectionDefinitions) {
            const definition = appSchema.definitions[name];
            const property = definition.properties['relatedFacet'];
            definition.properties['relatedFacet'] = {
                anyOf: [
                    {
                        ...(typeof property === 'object' ? property : undefined),
                        $ref: `${__1.DEFINITION_LINK_PREFIX}${ux_specification_types_1.DefinitionName.RelatedFacetKeys}`
                    },
                    property
                ]
            };
        }
    }
}
/**
 * Receives a facet key and returns the key as used in schema.
 *
 * @param facetKey - key of the facet, as used in annotation
 * @returns facetKeyInSchema - key of the facet, as used in schema
 */
function getFacetKeyInSchema(facetKey) {
    return facetKey.replace('#', '::');
}
/**
 * Returns the name of a facet and definition, as key in definition.
 *
 * @param definition name of definition, as used in schema
 * @param facetKey - key of the facet, as used in annotation
 * @returns definition key of facet, as used in definition
 */
function getFacetDefinitionKey(definition, facetKey) {
    return `${definition}<${getFacetKeyInSchema(facetKey)}>`;
}
/**
 * Adds an existing schema definition to a new definition in the app schema.
 *
 * @param definition name of definition, as used in schema
 * @param facetKey - key of the facet, as used in annotation
 * @param {Definition} appSchema App schema in general
 * @param {boolean} useDefinitionAsKey If set to false, facet key will solely be used as key, else encapsulated within definition key `definition<facetKey>`
 * @returns {Definition} part of app schema that has been added and filled
 */
function parseSchemaDefinition(definition, facetKey, appSchema, useDefinitionAsKey = true) {
    let newDefinitionKey = facetKey;
    if (useDefinitionAsKey) {
        newDefinitionKey = getFacetDefinitionKey(definition, facetKey);
    }
    if (definition && definition !== newDefinitionKey) {
        try {
            const schemaDefinition = JSON.parse(JSON.stringify(appSchema.definitions[definition]));
            appSchema.definitions[newDefinitionKey] = schemaDefinition;
        }
        catch {
            throw new Error(i18next_1.default.t('INCONSISTENTSCHEMA', { function: 'parseSchemaDefinition', definition }));
        }
    }
    return appSchema.definitions[newDefinitionKey];
}
/**
 * Method receives custom extension base definition name and detect if it should be combined with lineItemId.
 *
 * @param appSchema - the app specific schema that shall get enhanced
 * @param lineItemId - line item ID, as comprise in stable ID
 * @param customExtensionDefinitionName - name of the custom extension definition
 * @returns $ref path for definition.
 */
function getCustomExtensionDefinitionName(appSchema, lineItemId, customExtensionDefinitionName) {
    let definitionName;
    if (lineItemId === ux_specification_types_1.DefinitionName.LineItems ||
        lineItemId === 'LineItemsOfSPV::LineItem' ||
        lineItemId === `@${"com.sap.vocabularies.UI.v1.LineItem" /* UIAnnotationTerms.LineItem */}`) {
        definitionName = `${__1.DEFINITION_LINK_PREFIX}${customExtensionDefinitionName}`;
    }
    else {
        definitionName = `${__1.DEFINITION_LINK_PREFIX}${customExtensionDefinitionName}<${lineItemId}>`;
        parseSchemaDefinition(customExtensionDefinitionName, lineItemId, appSchema, true);
    }
    return definitionName;
}
/**
 * Functions used both by V2 and V4 to add the common definitions for a line item to the app schema.
 *
 * @param isObjectPage - indicates that the page is an object page
 * @param appSchema - the app specific schema that shall get enhanced
 * @param lineItemAnnotation - the UI.LineItem annotation, comprising all records
 * @param entityType - the entity type as part of the AVT ConvertedMetadata
 * @param lineItemId - line item ID, as comprise in stable ID
 * @param customColumnDefinitionName - (optional) definition name of custom column.
 *        Passed in the V4 case, then additional properties of this type will be allowed.
 * @param customActionDefinitionName - (optional) definition name of custom action.
 * @returns the actions definition plus the annotation path to the given line item
 */
function addCommonLineItemDefinitions(isObjectPage, appSchema, lineItemAnnotation, entityType, lineItemId, customColumnDefinitionName, customActionDefinitionName) {
    let lineItemPath;
    appSchema.definitions[lineItemId] = {
        type: 'object',
        properties: {},
        description: 'Columns'
    };
    appSchema.definitions[lineItemId][ux_specification_types_1.SchemaTag.isViewNode] = true;
    appSchema.definitions[lineItemId].additionalProperties = false;
    if (customColumnDefinitionName) {
        const customColumnRef = getCustomExtensionDefinitionName(appSchema, lineItemId, customColumnDefinitionName);
        appSchema.definitions[lineItemId].additionalProperties = { $ref: customColumnRef };
    }
    // Copy toolbar
    const toolBar = isObjectPage ? ux_specification_types_1.DefinitionName.ObjectPageToolBar : ux_specification_types_1.DefinitionName.ToolBar;
    const schemaIdForToolBar = `${toolBar}<${lineItemId}>`;
    try {
        appSchema.definitions[schemaIdForToolBar] = JSON.parse(JSON.stringify(appSchema.definitions[`${toolBar}`]));
    }
    catch {
        throw new Error(i18next_1.default.t('INCONSISTENTSCHEMA', { function: 'addCommonLineItemDefinitions', definition: `${toolBar}` }));
    }
    const schemaIdForActions = `${ux_specification_types_1.DefinitionName.Actions}<${(0, __1.prepareRef)(lineItemId)}>`;
    appSchema.definitions[schemaIdForToolBar].properties.actions['$ref'] =
        __1.DEFINITION_LINK_PREFIX + schemaIdForActions;
    const actionId = lineItemId.startsWith(ux_specification_types_1.DefinitionName.LineItems)
        ? ux_specification_types_1.DefinitionName.Actions
        : ux_specification_types_1.DefinitionName.ObjectPageToolBarActions;
    let actions;
    try {
        actions = appSchema.definitions[schemaIdForActions] = JSON.parse(JSON.stringify(appSchema.definitions[actionId]));
        actions.properties = {};
        // Handle actions additional properties - add custom action reference if it is supported
        actions.additionalProperties = false;
        if (customActionDefinitionName) {
            const customActionRef = getCustomExtensionDefinitionName(appSchema, lineItemId, customActionDefinitionName);
            actions.additionalProperties = { $ref: customActionRef };
        }
    }
    catch {
        throw new Error(i18next_1.default.t('INCONSISTENTSCHEMA', {
            function: 'addCommonLineItemDefinitions',
            definition: `${actionId}`
        }));
    }
    // Copy LR footer
    let footerActions, schemaIdForFooter;
    if (lineItemId === ux_specification_types_1.DefinitionName.LineItems && appSchema.properties['footer']) {
        schemaIdForFooter = `${ux_specification_types_1.DefinitionName.Footer}<${lineItemId}>`;
        appSchema.properties['footer'].$ref = `${__1.DEFINITION_LINK_PREFIX}${schemaIdForFooter}`;
        try {
            appSchema.definitions[schemaIdForFooter] = JSON.parse(JSON.stringify(appSchema.definitions[ux_specification_types_1.DefinitionName.GenericFooter]));
        }
        catch {
            throw new Error(i18next_1.default.t('INCONSISTENTSCHEMA', {
                function: 'addCommonLineItemDefinitions',
                definition: ux_specification_types_1.DefinitionName.GenericFooter
            }));
        }
        const schemaIdForFooterActions = `${ux_specification_types_1.DefinitionName.FooterActions}<${(0, __1.prepareRef)(lineItemId)}>`;
        appSchema.definitions[schemaIdForFooter].properties.actions['$ref'] =
            __1.DEFINITION_LINK_PREFIX + schemaIdForFooterActions;
        footerActions = appSchema.definitions[schemaIdForFooterActions] = JSON.parse(JSON.stringify(appSchema.definitions[ux_specification_types_1.DefinitionName.Actions]));
        footerActions.properties = {};
        footerActions.additionalProperties = false;
    }
    //Determine annotation path
    if (lineItemAnnotation) {
        lineItemPath = (0, __1.createAnnotationPath)(entityType?.fullyQualifiedName, lineItemAnnotation.term, lineItemAnnotation.qualifier);
        if (lineItemPath) {
            appSchema.definitions[schemaIdForToolBar][ux_specification_types_1.SchemaTag.annotationPath] = lineItemPath;
            if (footerActions) {
                appSchema.definitions[schemaIdForFooter][ux_specification_types_1.SchemaTag.annotationPath] = lineItemPath;
            }
        }
    }
    return { actions, footerActions, lineItemPath };
}
var DataType;
(function (DataType) {
    DataType["String"] = "String";
    DataType["Rating"] = "Rating";
    DataType["Progress"] = "Progress";
    DataType["DataPoint"] = "DataPoint";
    DataType["Contact"] = "Contact";
    DataType["Address"] = "Address";
    DataType["Chart"] = "Chart";
    DataType["FieldGroup"] = "FieldGroup";
    DataType["IntentBasedNavigation"] = "IntentBasedNavigation";
})(DataType || (exports.DataType = DataType = {}));
/**
 * Common logic to build the dataType tag from an annotation type.
 *
 * @param {string} annotation - the annotation type
 * @returns the dataType as string
 */
function getDataTypeFromAnnotation(annotation) {
    const dataType = annotation.substring(annotation.lastIndexOf('.') + 1);
    return dataType.replace(/Type$/, '');
}
/**
 * Determines the dataType of the target that shall be added to a property in schema.
 *
 * @param target - the given target
 * @returns - the dataType as string
 */
function determineDataTypeOfTarget(target) {
    let dataType;
    if (target?.Value) {
        if (target.Visualization === 'UI.VisualizationType/Rating') {
            dataType = DataType.Rating;
        }
        else if (target.Visualization === 'UI.VisualizationType/Progress') {
            dataType = DataType.Progress;
        }
        else if (target.$Type === 'com.sap.vocabularies.UI.v1.DataPointType') {
            dataType = DataType.DataPoint;
        }
        else {
            dataType = target.Value?.$target?.type.replace('Edm.', '');
        }
    }
    else if (target?.$Type?.startsWith('com.sap.vocabularies.')) {
        dataType = getDataTypeFromAnnotation(target.$Type);
    }
    return dataType;
}
/**
 * Determines the dataType that shall be added to a property in schema for any kind of field like:
 * - field of a field group
 * - line item record
 * - selection field
 * passed as object.
 *
 * @param field - the given field
 * @returns - the dataType as string
 */
function determineDataType(field) {
    let dataType;
    try {
        if (field['Value']) {
            if (field['Value'].$target?.type) {
                dataType = field['Value'].$target.type.replace('Edm.', '');
            }
            else {
                dataType = DataType.String;
            }
        }
        else if (field['Target']) {
            dataType = determineDataTypeOfTarget(field['Target']?.$target);
        }
        else if (field['$target']) {
            dataType = field['$target'].type.replace('Edm.', '');
        }
        else if (field['$Type']?.startsWith('com.sap.vocabularies.')) {
            dataType = getDataTypeFromAnnotation(field['$Type']);
        }
        else if (field['type']) {
            dataType = field['type'];
        }
        return dataType;
    }
    catch {
        return dataType;
    }
}
/**
 * Adds the dataType to the given schema field definition, if the data type cane be determined.
 *
 * @param definition - given schema definition
 * @param field - given field definition = annotation property, at AVT
 */
function addDataTypeToDefinition(definition, field) {
    const dataType = determineDataType(field);
    if (dataType) {
        definition[ux_specification_types_1.SchemaTag.dataType] = dataType;
    }
}
/**
 * Creates a definition link for a facet and definition name.
 *
 * @param {DefinitionName} definition - name of definition, as used in schema
 * @param {string} facetKey - key of the facet, as used in annotation
 * @returns definition link of facet, as used in definition
 */
function getFacetDefinitionLink(definition, facetKey) {
    return `${__1.DEFINITION_LINK_PREFIX}${getFacetDefinitionKey(definition, facetKey)}`;
}
/**
 * Generates a unique facet definition link by appending an index to the facet key if necessary.
 *
 * @param definition The definition name or section type used to derive the facet definition link.
 * @param facetKey The base key of the facet to generate the definition link.
 * @param appSchema The application schema containing existing definitions where the uniqueness will be validated.
 * @param lineItemPath The path to the line item to check if the facet definition is associated with it.
 * @returns A string representing a unique facet definition link.
 */
function getUniqueFacetDefinitionLink(definition, facetKey, appSchema, lineItemPath) {
    let index = 0;
    let isFacetDefinitionKeyUniqOrReusable = false;
    let facetDefinitionLink = '';
    do {
        // The definition link at index 0 serves as the default one
        const indexedFacetKey = `${facetKey}${index === 0 ? '' : '.' + index}`;
        facetDefinitionLink = getFacetDefinitionLink(definition, indexedFacetKey);
        index++;
        // Check if the facet definition already exists in the application schema
        // If the duplicated element is placed in the same line item, we can reuse the definition
        const facetDefinition = appSchema.definitions[getFacetDefinitionKey(definition, indexedFacetKey)];
        const facetLineItemPath = (facetDefinition?.[`annotationPath`] ?? '').split('/').slice(0, -1).join('/');
        isFacetDefinitionKeyUniqOrReusable = !facetDefinition || facetLineItemPath === lineItemPath;
    } while (!isFacetDefinitionKeyUniqOrReusable);
    return facetDefinitionLink;
}
/**
 * Creates and adds a reference link to a definition.
 *
 * @param {Definition} schemaPart - part of schema to add $ref to
 * @param {string} schemaRef - reference to be added
 * @param {string} schemaKey - key to be encapsulated within reference as `schemaRef<schemaKey>`
 */
function addDefinitionRef(schemaPart, schemaRef, schemaKey) {
    const schemaLink = schemaKey ? `${schemaRef}<${schemaKey}>` : schemaRef;
    schemaPart.$ref = `${__1.DEFINITION_LINK_PREFIX}${schemaLink}`;
}
/**
 * Extracts annotationPath from facet or Chart/LineItem fullyQualifiedName.
 *
 * @param facet facet or Chart/LineItem
 * @returns {string} annotationPath
 */
function getFacetAnnotationPath(facet) {
    let result;
    if (facet.annotationPath) {
        result = facet.annotationPath;
    }
    else if (facet.fullyQualifiedName) {
        const [namespace, target] = facet.fullyQualifiedName.split(`@${ux_specification_types_1.UIVOCABULARY}`);
        result = `/${namespace}/@${ux_specification_types_1.UIVOCABULARY}${target}`;
    }
    return result;
}
/**
 * Adds definitions for Address and Contact items in object page sections to the app schema.
 *
 * @param facet - current facet.
 * @param facetKey - facet key.
 * @param sections - schema of current sections definition.
 * @param appSchema - app specific schema that potentially gets enhanced.
 * @param sectionPrefix - prefix to distinguish Section and HeaderSection
 * @param subSectionPrefix - prefix to distinguish subsections within the schema
 * @param versionPostfix - optional postfix to distinguish schema versions
 */
function handleAddressContact(facet, facetKey, sections, appSchema, sectionPrefix, subSectionPrefix, versionPostfix = '') {
    const definitionName = `ObjectPage${sectionPrefix}${facet.base}${versionPostfix}`;
    const subDefinitionName = `ObjectPage${subSectionPrefix}${facet.base}${versionPostfix}`;
    sections.properties[facetKey] = {
        $ref: getFacetDefinitionLink(subSectionPrefix ? subDefinitionName : definitionName, facetKey)
    };
    const definition = parseSchemaDefinition(subSectionPrefix ? subDefinitionName : definitionName, facetKey, appSchema, true);
    (0, __1.addSectionTitle)(facet, definition, facetKey);
    (0, __1.addSectionDescription)(facet, definition, facetKey);
    definition[ux_specification_types_1.SchemaTag.annotationPath] = facet.annotationPath;
    definition[ux_specification_types_1.SchemaTag.isViewNode] = true;
}
/**
 * Method updates schema definition's property.
 *
 * @param {DefinitionOrBoolean} definition Definition object.
 * @param {string} key Property name.
 * @param {unknown} value New value.
 */
function updateSchemaProperty(definition, key, value) {
    if (typeof definition === 'object') {
        definition[key] = value;
    }
}
/**
 * Add schema definitions for fields of createWithParameterDialog.
 *
 * @param {object} appSchema - Application-specific schema, to be enhanced
 * @param {EntityType} entityType - Given entity type for which entries shall get generated
 * @param {string=} suffix - floorplan specific suffix (optional)
 */
function addFieldsType(appSchema, entityType, suffix = (0, __1.prepareRef)('')) {
    const itemsEnum = entityType.entityProperties.map((property) => property.name);
    const fields4Dialog = appSchema.definitions[`${ux_specification_types_1.DefinitionName.Fields4Dialog}${suffix}`];
    updateSchemaProperty(fields4Dialog.properties.fields['items'], 'enum', itemsEnum);
}
/**
 * Method finds first schema definition key by passed key names.
 *
 * @param keys Schema definitions keys to search in.
 * @param keyProperties Key properties to use as query.
 * @returns Found first schema definition key.
 */
function findFirstSchemaDefinitionKey(keys, keyProperties) {
    if (!keyProperties || !keys) {
        return;
    }
    for (const keyProperty of keyProperties) {
        const schemaDefinitionKey = keys.find((innerKey) => innerKey.name === keyProperty);
        if (schemaDefinitionKey) {
            return schemaDefinitionKey;
        }
    }
}
/**
 * Method returns enum entry for passed schema definition.
 *
 * @param {Definition} appSchema App specific JSON schema
 * @param {SchemaDefinition} definition Target definition to resolve description.
 * @param {string} key Default enum key.
 * @param {EnumDefinitionParsingOptions} [options] Additional parsing options.
 * @returns {string | undefined} Enum entry of passed definition.
 */
function getEnumEntry(appSchema, definition, key, options) {
    let description = definition.description;
    let keys = definition.keys;
    let custom = !definition.annotationPath;
    if (definition.$ref) {
        // Try to read description from reference
        const definitionKey = (0, __1.getDefinitionKey)(definition.$ref);
        const refDefinition = appSchema.definitions?.[definitionKey];
        if (typeof refDefinition === 'object') {
            custom = !refDefinition.annotationPath;
            if (options?.resolveDefinition && !description) {
                description = refDefinition.description;
                keys = refDefinition.keys;
            }
        }
    }
    // Resolve enum key
    let enumKey = key;
    // Read key from schema keys by passed property
    const schemaDefinitionKey = findFirstSchemaDefinitionKey(keys, options?.keyProperties);
    if (schemaDefinitionKey) {
        enumKey = schemaDefinitionKey.value;
    }
    else if (options?.descriptionAsFallback && description) {
        // Fallback to use description/label as key. It is fallback solution for some extensions.
        enumKey = description;
    }
    return {
        const: enumKey,
        ...(description && { description }),
        ...(custom && { custom })
    };
}
/**
 * Method adds enum with key and description to schema definition.
 * Description can be easily used by UI to describe enum value/key.
 *
 * @param {Definition} appSchema App specific JSON schema
 * @param {DefinitionOrBoolean} origin Origin schema object containing key and description.
 * @param {PropertyInDefinition} target Target to update with enum.
 * @param {EnumDefinitionParsingOptions} [options] Additional parsing options.
 * @param {boolean} [options.resolveDefinition] Should logic use fallback to look into reference definition.
 */
function addDescriptiveEnumDefinition(appSchema, origin, target, options) {
    if (typeof origin !== 'object') {
        // Safe checks
        return;
    }
    const oneOfEnum = [];
    for (const key in origin.properties) {
        if (options?.excludeKey === key) {
            continue;
        }
        const property = origin.properties[key];
        const entry = getEnumEntry(appSchema, property, key, options);
        oneOfEnum.push(entry);
    }
    const definition = appSchema.definitions[target.definition] || target.schema;
    if (typeof definition === 'object') {
        if (target.property) {
            const property = definition.properties?.[target.property];
            updateSchemaProperty(property, 'oneOf', oneOfEnum);
        }
        else {
            updateSchemaProperty(definition, 'oneOf', oneOfEnum);
        }
    }
}
/**
 * Extracts the key of an action that shall be added to schema as SchemaTag.keys.
 *
 * @param action - full-blown action ID
 * @param isAction - indicates an action
 * @returns action ID stripped down to the last key part
 */
function getActionKey(action, isAction) {
    let actionKey = action;
    let namespace;
    if (actionKey.indexOf('(') > 0) {
        actionKey = actionKey.substring(0, actionKey.indexOf('('));
    }
    if (isAction && actionKey.indexOf('.') > 0) {
        const firstSlash = actionKey.indexOf('/');
        const lastDot = actionKey.lastIndexOf('.');
        namespace = firstSlash > 0 ? actionKey.substring(0, firstSlash) : actionKey.substring(0, lastDot);
        actionKey = firstSlash > 0 ? actionKey.substring(firstSlash + 1) : actionKey.substring(lastDot + 1);
    }
    if (!namespace) {
        namespace = action.substring(0, action.lastIndexOf('.'));
    }
    return { key: actionKey.replace(/@/g, ''), ns: namespace };
}
/**
 * This function determines the content of the 'keys' and the 'target' property that should be added to a schema element representing a given line item record.
 *
 * @param lineItemRecord - object representing the line item record, as defined in the AVT ConvertedMetadata, e.g. containing properties like '$Type', 'Value', 'Action', 'Target' etc.
 * @returns An object containing the 'keys' array and the 'target' string (if applicable) for the given line item record.
 */
function getKeysAndTargetForLineItemRecord(lineItemRecord) {
    let keys, target;
    if (lineItemRecord['Value']) {
        keys = [{ name: ux_specification_types_1.SchemaKeyName.value, value: (0, StableIdHelper_1.getStableIdPartFromValue)(lineItemRecord['Value']) }];
    }
    else if (lineItemRecord['$Type'] === "com.sap.vocabularies.UI.v1.DataFieldWithAction" /* UIAnnotationTypes.DataFieldWithAction */ ||
        lineItemRecord['$Type'] === "com.sap.vocabularies.UI.v1.DataFieldForAction" /* UIAnnotationTypes.DataFieldForAction */) {
        const { key, ns } = getActionKey(lineItemRecord['Action'], true);
        keys = [{ name: ux_specification_types_1.SchemaKeyName.action, value: key }];
        target = ns;
    }
    else if (lineItemRecord['$Type'] === "com.sap.vocabularies.UI.v1.DataFieldForAnnotation" /* UIAnnotationTypes.DataFieldForAnnotation */) {
        const { key } = getActionKey(lineItemRecord['Target'].value, false);
        keys = [{ name: ux_specification_types_1.SchemaKeyName.target, value: (0, __1.replaceNamespaces)(key) }];
        target = lineItemRecord['Target']?.$target?.fullyQualifiedName?.split('@')[0];
    }
    else if (lineItemRecord['$Type'] === "com.sap.vocabularies.UI.v1.DataFieldForIntentBasedNavigation" /* UIAnnotationTypes.DataFieldForIntentBasedNavigation */ ||
        lineItemRecord['$Type'] === "com.sap.vocabularies.UI.v1.DataFieldWithIntentBasedNavigation" /* UIAnnotationTypes.DataFieldWithIntentBasedNavigation */) {
        const actionId = typeof lineItemRecord['Action'] === 'string' ? lineItemRecord['Action'] : lineItemRecord['Action'].path;
        const { key, ns } = getActionKey(actionId, true);
        keys = [
            { name: `SemanticObject`, value: lineItemRecord[ux_specification_types_1.SchemaKeyName.semanticObject] },
            { name: `Action`, value: key }
        ];
        target = ns;
    }
    target = target || undefined; // normalize empty string to undefined
    return { keys, target };
}
/**
 * Adds the schema tag 'key' to a line item record or property in schema. By default it also adds schema tag 'target' if applicable.
 *
 * @param lineItemRecord - the given line item record
 * @param element - the target object to be updated
 * @param addTarget - if true the schema tag 'target' will be added as well if applicable
 */
function addKeyToElement(lineItemRecord, element, addTarget = true) {
    try {
        const { keys, target } = getKeysAndTargetForLineItemRecord(lineItemRecord);
        if (keys) {
            element[ux_specification_types_1.SchemaTag.keys] = keys;
        }
        if (addTarget && target) {
            element[ux_specification_types_1.SchemaTag.target] = target;
        }
    }
    catch (error) {
        return;
    }
}
/**
 * Adds the schema tag key to a line item record or property in schema.
 *
 * @param lineItemRecord - the given line item record
 * @param properties - list of all properties in schema
 * @param schemaKey - key of the given property
 */
function addKeyToDefinition(lineItemRecord, properties, schemaKey) {
    addKeyToElement(lineItemRecord, properties[schemaKey]);
}
/**
 * Determines the description of a data field, e.g. for the column header.
 *
 * @param dataFieldAbstract - the given record of the line item annotation
 * @param entityType - the entity type as part of the AVT ConvertedMetadata
 * @returns the description of the data field
 */
function getDataFieldDescription(dataFieldAbstract, entityType) {
    try {
        const strategy = DataFieldStrategy_1.dataFieldStrategyContext.getStrategy(dataFieldAbstract.$Type);
        return strategy.generateDescription(dataFieldAbstract, entityType);
    }
    catch {
        return '';
    }
}
/**
 * Adds a message to the `messages` field of a schema element.
 *
 * @param {Definition} element - The element to which the message will be added.
 * @param {MessageParameters} parameters - The message parameters including text and deletable flag.
 * @returns {void}
 */
function addMessageToSchema(element, { text, deletable = false }) {
    if (!element[ux_specification_types_1.SchemaTag.messages]) {
        element[ux_specification_types_1.SchemaTag.messages] = [];
    }
    if (Array.isArray(element[ux_specification_types_1.SchemaTag.messages])) {
        element[ux_specification_types_1.SchemaTag.messages].push({
            text,
            deletable
        });
    }
}
//# sourceMappingURL=utils.js.map