text: /*!
   * OpenUI5
   * (c) Copyright 2009-2021 SAP SE or an SAP affiliate company.
   * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
   */
  
  /* global Set */
  
  // Provides class sap.ui.base.DataType
  sap.ui.define([
  	'sap/base/util/ObjectPath',
  	"sap/base/assert",
  	"sap/base/Log",
  	"sap/base/util/isPlainObject",
  	'sap/base/util/resolveReference'
  ],
  	function(ObjectPath, assert, Log, isPlainObject, resolveReference) {
  	"use strict";
  
  	/**
  	 * Pseudo-Constructor for class <code>DataType</code>, never to be used.
  	 *
  	 * @class Represents the type of properties in a <code>ManagedObject</code> class.
  	 *
  	 * Each type provides some metadata like its {@link #getName qualified name} or its
  	 * {@link #getBaseType base type} in case of a derived type. Array types provide information
  	 * about the allowed {@link #getComponentType type of components} in an array, enumeration types
  	 * inform about the set of their allowed {@link #getEnumValues keys and values}.
  	 *
  	 * Each type has a method to {@link #isValid check whether a value is valid} for a property
  	 * of that type.
  	 *
  	 * Already defined types can be looked up by calling {@link #.getType DataType.getType}, new
  	 * types can only be created by calling the factory method {@link #.createType DataType.createType},
  	 * calling the constructor will throw an error.
  	 *
  	 * @author SAP SE
  	 * @since 0.9.0
  	 * @alias sap.ui.base.DataType
  	 * @public
  	 * @hideconstructor
  	 * @throws {Error} Constructor must not be called, use {@link #.createType DataType.createType} instead
  	 */
  	var DataType = function() {
  		// Avoid construction of a DataType.
  		// DataType is only a function to support the "instanceof" operator.
  		throw new Error();
  	};
  
  	/**
  	 * The qualified name of the data type.
  	 *
  	 * @returns {string} Name of the data type
  	 * @public
  	 */
  	DataType.prototype.getName = function() {
  		return undefined;
  	};
  
  	/**
  	 * The base type of this type or undefined if this is a primitive type.
  	 * @returns {sap.ui.base.DataType|undefined} Base type or <code>undefined</code>
  	 * @public
  	 */
  	DataType.prototype.getBaseType = function() {
  		return undefined;
  	};
  
  	/**
  	 * Returns the most basic (primitive) type that this type has been derived from.
  	 *
  	 * If the type is a primitive type by itself, <code>this</code> is returned.
  	 *
  	 * @returns {sap.ui.base.DataType} Primitive type of this type
  	 * @public
  	 */
  	DataType.prototype.getPrimitiveType = function() {
  		/*eslint-disable consistent-this*/
  		var oType = this;
  		/*eslint-enable consistent-this*/
  		while (oType.getBaseType()) {
  			oType = oType.getBaseType();
  		}
  		return oType;
  	};
  
  	/**
  	 * Returns the component type of this type or <code>undefined</code> if this is not an array type.
  	 *
  	 * @returns {sap.ui.base.DataType|undefined} Component type or <code>undefined</code>
  	 * @public
  	 */
  	DataType.prototype.getComponentType = function() {
  		return undefined;
  	};
  
  	/**
  	 * The default value for this type. Each type must define a default value.
  	 * @returns {any} Default value of the data type. The type of the returned value
  	 *    must match the JavaScript type of the data type (a string for string types etc.)
  	 * @public
  	 */
  	DataType.prototype.getDefaultValue = function() {
  		return undefined;
  	};
  
  	/**
  	 * Whether this type is an array type.
  	 * @returns {boolean} Whether this type is an array type
  	 * @public
  	 */
  	DataType.prototype.isArrayType = function() {
  		return false;
  	};
  
  	/**
  	 * Whether this type is an enumeration type.
  	 * @returns {boolean} Whether this type is an enum type
  	 * @public
  	 */
  	DataType.prototype.isEnumType = function() {
  		return false;
  	};
  
  	/**
  	 * Returns the object with keys and values from which this enum type was created
  	 * or <code>undefined</code> if this is not an enum type.
  	 *
  	 * @returns {object} Object with enum keys and values or <code>undefined</code>
  	 * @public
  	 */
  	DataType.prototype.getEnumValues = function() {
  		return undefined;
  	};
  
  	/**
  	 * Parses the given string value and converts it into the specific data type.
  	 * @param {string} sValue String representation for a value of this type
  	 * @returns {any} Value in the correct internal format
  	 * @public
  	 */
  	DataType.prototype.parseValue = function(sValue) {
  		return sValue;
  	};
  
  	/**
  	 * Checks whether the given value is valid for this type.
  	 *
  	 * To be implemented by concrete types.
  	 * @param {any} vValue Value to be checked
  	 * @returns {boolean} Whether the given value is valid for this data type (without conversion)
  	 * @public
  	 * @function
  	 */
  	DataType.prototype.isValid = undefined;
  	// Note that <code>isValid</code> must be assigned a falsy value here as it otherwise
  	// would be called in addition to any <code>isValid</code> implementation in subtypes.
  	// See <code>createType</code> for details.
  
  	/**
  	 * Set or unset a normalizer function to be used for values of this data type.
  	 *
  	 * When a normalizer function has been set, it will be applied to values of this type
  	 * whenever {@link #normalize} is called. <code>ManagedObject.prototype.setProperty</code>
  	 * calls the <code>normalize</code> method before setting a new value to a property
  	 * (normalization is applied on-write, not on-read).
  	 *
  	 * The <code>fnNormalize</code> function has the signature
  	 * <pre>
  	 *   fnNormalize(value:any) : any
  	 * </pre>
  	 * It will be called with a value for this type and should return a normalized
  	 * value (which also must be valid for the this type). There's no mean to reject a value.
  	 * The <code>this</code> context of the function will be this type.
  	 *
  	 * This method allows applications or application frameworks to plug-in a generic value
  	 * normalization for a type, e.g. to convert all URLs in some app-specific way before
  	 * they are applied to controls. It is not intended to break-out of the value range
  	 * defined by a type.
  	 *
  	 * @param {function} fnNormalizer Function to apply for normalizing
  	 * @public
  	 */
  	DataType.prototype.setNormalizer = function(fnNormalizer) {
  		assert(typeof fnNormalizer === "function", "DataType.setNormalizer: fnNormalizer must be a function");
  		this._fnNormalizer = typeof fnNormalizer === "function" ? fnNormalizer : undefined;
  	};
  
  	/**
  	 * Normalizes the given value using the specified normalizer for this data type.
  	 *
  	 * If no normalizer has been set, the original value is returned.
  	 *
  	 * @param {any} oValue Value to be normalized
  	 * @returns {any} Normalized value
  	 * @public
  	 */
  	DataType.prototype.normalize = function(oValue) {
  		return this._fnNormalizer ? this._fnNormalizer(oValue) : oValue;
  	};
  
  	function createType(sName, mSettings, oBase) {
  
  		mSettings = mSettings || {};
  
  		// create a new type object with the base type as prototype
  		var oBaseObject = oBase || DataType.prototype;
  		var oType = Object.create(oBaseObject);
  
  		// getter for the name
  		oType.getName = function() {
  			return sName;
  		};
  
  		// if a default value is specified, create a getter for it
  		if ( mSettings.hasOwnProperty("defaultValue") ) {
  			var vDefault = mSettings.defaultValue;
  			oType.getDefaultValue = function() {
  				return vDefault;
  			};
  		}
  
  		// if a validator is specified either chain it with the base type validator
  		// or set it if no base validator exists
  		if ( mSettings.isValid ) {
  			var fnIsValid = mSettings.isValid;
  			oType.isValid = oBaseObject.isValid ? function(vValue) {
  				if ( !oBaseObject.isValid(vValue) ) {
  					return false;
  				}
  				return fnIsValid(vValue);
  			} : fnIsValid;
  		}
  
  		if ( mSettings.parseValue ) {
  			oType.parseValue = mSettings.parseValue;
  		}
  
  		// return the base type
  		oType.getBaseType = function() {
  			return oBase;
  		};
  
  		return oType;
  	}
  
  	var mTypes = {
  
  		"any" :
  			createType("any", {
  				defaultValue : null,
  				isValid : function(vValue) {
  					return true;
  				}
  			}),
  
  		"boolean" :
  			createType("boolean", {
  				defaultValue : false,
  				isValid : function(vValue) {
  					return typeof vValue === "boolean";
  				},
  				parseValue: function(sValue) {
  					return sValue == "true";
  				}
  			}),
  
  		"int" :
  			createType("int", {
  				defaultValue : 0,
  				isValid : function(vValue) {
  					return typeof vValue === "number" && (isNaN(vValue) || Math.floor(vValue) == vValue);
  				},
  				parseValue: function(sValue) {
  					return parseInt(sValue);
  				}
  			}),
  
  		"float" :
  			createType("float", {
  				defaultValue : 0.0,
  				isValid : function(vValue) {
  					return typeof vValue === "number";
  				},
  				parseValue: function(sValue) {
  					return parseFloat(sValue);
  				}
  			}),
  
  		"string" :
  			createType("string", {
  				defaultValue : "",
  				isValid : function(vValue) {
  					return typeof vValue === "string" || vValue instanceof String;
  				},
  				parseValue: function(sValue) {
  					return sValue;
  				}
  			}),
  
  		"object" :
  			createType("object", {
  				defaultValue : null,
  				isValid : function(vValue) {
  					return typeof vValue === "object" || typeof vValue === "function";
  				},
  				parseValue: function(sValue) {
  					return sValue ? JSON.parse(sValue) : null;
  				}
  			}),
  
  		"function" :
  			createType("function", {
  				defaultValue : null,
  				isValid : function(vValue) {
  					return vValue == null || typeof vValue === 'function';
  				},
  				/*
  				 * Note: the second parameter <code>_oOptions</code> is a hidden feature for internal use only.
  				 * Its structure is subject to change. No code other than the XMLTemplateProcessor must use it.
  				 */
  				parseValue: function(sValue, _oOptions) {
  					if ( sValue === "" ) {
  						return undefined;
  					}
  
  					if ( !/^\.?[A-Z_\$][A-Z0-9_\$]*(\.[A-Z_\$][A-Z0-9_\$]*)*$/i.test(sValue) ) {
  						throw new Error(
  							"Function references must consist of dot separated " +
  							"simple identifiers (A-Z, 0-9, _ or $) only, but was '" + sValue + "'");
  					}
  
  					var fnResult,
  						oContext = _oOptions && _oOptions.context,
  						oLocals = _oOptions && _oOptions.locals;
  
  					fnResult = resolveReference(sValue,
  						Object.assign({".": oContext}, oLocals));
  
  					if ( fnResult && this.isValid(fnResult) ) {
  						return fnResult;
  					}
  
  					throw new TypeError("The string '" + sValue + "' couldn't be resolved to a function");
  				}
  			})
  
  	};
  
  	// The generic "array" type must not be exposed by DataType.getType to avoid direct usage
  	// as type of a managed property. It is therefore not stored in the mTypes map
  	var arrayType = createType("array", {
  		defaultValue : []
  	});
  
  	function createArrayType(componentType) {
  		assert(componentType instanceof DataType, "DataType.<createArrayType>: componentType must be a DataType");
  
  		// create a new type object with the base type as prototype
  		var oType = Object.create(DataType.prototype);
  
  		// getter for the name
  		oType.getName = function() {
  			return componentType.getName() + "[]";
  		};
  
  		// getter for component type
  		oType.getComponentType = function() {
  			return componentType;
  		};
  
  		// array validator
  		oType.isValid = function(aValues) {
  			if (aValues === null) {
  				return true;
  			}
  			if (Array.isArray(aValues)) {
  				for (var i = 0; i < aValues.length; i++) {
  					if (!componentType.isValid(aValues[i])) {
  						return false;
  					}
  				}
  				return true;
  			}
  			return false;
  		};
  
  		// array parser
  		oType.parseValue = function(sValue) {
  			var aValues = sValue.split(",");
  			for (var i = 0; i < aValues.length; i++) {
  				aValues[i] = componentType.parseValue(aValues[i]);
  			}
  			return aValues;
  		};
  
  		// is an array type
  		oType.isArrayType = function() {
  			return true;
  		};
  
  		// return the base type
  		oType.getBaseType = function() {
  			return arrayType;
  		};
  
  		return oType;
  	}
  
  	function createEnumType(sTypeName, oEnum) {
  
  		var mValues = {},
  			sDefaultValue;
  		for (var sName in oEnum) {
  			var sValue = oEnum[sName];
  			// the first entry will become the default value
  			if (!sDefaultValue) {
  				sDefaultValue = sValue;
  			}
  			if ( typeof sValue !== "string") {
  				throw new Error("Value " + sValue + " for enum type " + sTypeName + " is not a string");
  			}
  			// if there are multiple entries with the same value, the one where name
  			// and value are matching is taken
  			if (!mValues.hasOwnProperty(sValue) || sName == sValue) {
  				mValues[sValue] = sName;
  			}
  		}
  
  		var oType = Object.create(DataType.prototype);
  
  		// getter for the name
  		oType.getName = function() {
  			return sTypeName;
  		};
  
  		// enum validator
  		oType.isValid = function(v) {
  			return typeof v === "string" && mValues.hasOwnProperty(v);
  		};
  
  		// enum parser
  		oType.parseValue = function(sValue) {
  			return oEnum[sValue];
  		};
  
  		// default value
  		oType.getDefaultValue = function() {
  			return sDefaultValue;
  		};
  
  		// return the base type
  		oType.getBaseType = function() {
  			return mTypes.string;
  		};
  
  		// is an enum type
  		oType.isEnumType = function() {
  			return true;
  		};
  
  		// enum values are best represented by the existing global object
  		oType.getEnumValues = function() {
  			return oEnum;
  		};
  
  		return oType;
  	}
  
  	/**
  	 * Looks up the type with the given name and returns it.
  	 *
  	 * See {@link topic:ac56d92162ed47ff858fdf1ce26c18c4 Defining Control Properties} for
  	 * a list of the built-in primitive types and their semantics.
  	 *
  	 * The lookup consists of the following steps:
  	 * <ul>
  	 * <li>When a type with the given name is already known, it will be returned</li>
  	 * <li>When the name ends with a pair of brackets (<code>[]</code>), a type with the name
  	 *     in front of the brackets (<code>name.slice(0,-2)</code>) will be looked up and an
  	 *     array type will be created with the looked-up type as its component type. If the
  	 *     component type is <code>undefined</code>, <code>undefined</code> will be returned</li>
  	 * <li>When a global property exists with the same name as the type and when the value of that
  	 *     property is an instance of <code>DataType</code>, that instance will be returned</li>
  	 * <li>When a global property exists with the same name as the type and when the value of that
  	 *     property is a plain object (its prototype is <code>Object</code>), then an enum type will
  	 *     be created, based on the keys and values in that object. The <code>parseValue</code> method
  	 *     of the type will accept any of the keys in the plain object and convert them to the
  	 *     corresponding value; <code>isValid</code> will accept any of the values from the plain
  	 *     object's keys. The <code>defaultValue</code> will be the value of the first key found in
  	 *     the plain object</li>
  	 * <li>When a global property exist with any other, non-falsy value, a warning is logged and the
  	 *     primitive type 'any' is returned</li>
  	 * <li>If no such global property exist, an error is logged and <code>undefined</code>
  	 *     is returned</li>
  	 * </ul>
  	 *
  	 * <b<Note:</b> UI Libraries and even components can introduce additional types. This method
  	 * only checks for types that either have been defined already, or that describe arrays of
  	 * values of an already defined type or types whose name matches the global name of a plain
  	 * object (containing enum keys and values). This method doesn't try to load modules that
  	 * might contain type definitions. So before being able to lookup and use a specific type,
  	 * the module containing its definition has to be loaded. For that reason it is suggested that
  	 * controls (or <code>ManagedObject</code> classes in general) declare a dependency to all
  	 * modules (typically <code>some/lib/library.js</code> modules) that contain the type definitions
  	 * needed by the specific control or class definition.
  	 *
  	 * @param {string} sTypeName Qualified name of the type to retrieve
  	 * @returns {sap.ui.base.DataType|undefined} Type object or <code>undefined</code> when
  	 *     no such type has been defined yet
  	 * @public
  	 */
  	DataType.getType = function(sTypeName) {
  		assert( sTypeName && typeof sTypeName === 'string', "sTypeName must be a non-empty string");
  
  		var oType = mTypes[sTypeName];
  		if ( !(oType instanceof DataType) ) {
  			// check for array types
  			if (sTypeName.indexOf("[]", sTypeName.length - 2) > 0) {
  				var sComponentTypeName = sTypeName.slice(0, -2),
  					oComponentType = this.getType(sComponentTypeName);
  				oType = oComponentType && createArrayType(oComponentType);
  				if ( oType ) {
  					mTypes[sTypeName] = oType;
  				}
  			} else if ( sTypeName !== 'array') {
  				oType = ObjectPath.get(sTypeName);
  				if ( oType instanceof DataType ) {
  					mTypes[sTypeName] = oType;
  				} else if ( isPlainObject(oType) ) {
  					oType = mTypes[sTypeName] = createEnumType(sTypeName, oType);
  				} else if ( oType ) {
  					Log.warning("'" + sTypeName + "' is not a valid data type. Falling back to type 'any'.");
  					oType = mTypes.any;
  				} else {
  					Log.error("data type '" + sTypeName + "' could not be found.");
  					oType = undefined;
  				}
  			}
  		}
  		return oType;
  	};
  
  	/**
  	 * Derives a new type from a given base type.
  	 *
  	 * Example:<br>
  	 * <pre>
  	 *
  	 *   var fooType = DataType.createType('foo', {
  	 *       isValid : function(vValue) {
  	 *           return /^(foo(bar)?)$/.test(vValue);
  	 *       }
  	 *   }, DataType.getType('string'));
  	 *
  	 *   fooType.isValid('foo'); // true
  	 *   fooType.isValid('foobar'); // true
  	 *   fooType.isValid('==foobar=='); // false
  	 *
  	 * </pre>
  	 *
  	 * If <code>mSettings</code> contains an implementation for <code>isValid</code>,
  	 * then the validity check of the newly created type will first execute the check of the
  	 * base type and then call the given <code>isValid</code> function.
  	 *
  	 * Array types and enumeration types cannot be created with this method. They're created
  	 * on-the-fly by {@link #.getType DataType.getType} when such a type is looked up.
  	 *
  	 * <b>Note:</b> The creation of new primitive types is not supported. When a type is created
  	 * without a base type, it is automatically derived from the primitive type <code>any</code>.
  	 *
  	 * <b>Note:</b> If a type has to be used in classes tagged with <code>@ui5-metamodel</code>,
  	 * then the implementation of <code>isValid</code> must exactly have the structure shown
  	 * in the example above (single return statement, regular expression literal of the form
  	 * <code>/^(...)$/</code>, calling <code>/regex/.test()</code> on the given value).
  	 * Only the inner part of the regular expression literal can be different.
  	 *
  	 * @param {string} sName Unique qualified name of the new type
  	 * @param {object} [mSettings] Settings for the new type
  	 * @param {any} [mSettings.defaultValue] Default value for the type (inherited if not given)
  	 * @param {function} [mSettings.isValid] Additional validity check function for values of the
  	 *                       type (inherited if not given)
  	 * @param {function} [mSettings.parseValue] Parse function that converts a locale independent
  	 *                       string into a value of the type (inherited if not given)
  	 * @param {sap.ui.base.DataType|string} [vBase='any'] Base type for the new type
  	 * @returns {sap.ui.base.DataType} The newly created type object
  	 * @public
  	 */
  	DataType.createType = function(sName, mSettings, vBase) {
  		assert(typeof sName === "string" && sName, "DataType.createType: type name must be a non-empty string");
  		assert(vBase == null || vBase instanceof DataType || typeof vBase === "string" && vBase,
  				"DataType.createType: base type must be empty or a DataType or a non-empty string");
  		if ( /[\[\]]/.test(sName) ) {
  			Log.error(
  				"DataType.createType: array types ('something[]') must not be created with createType, " +
  				"they're created on-the-fly by DataType.getType");
  		}
  		if ( typeof vBase === "string" ) {
  			vBase = DataType.getType(vBase);
  		}
  		vBase = vBase || mTypes.any;
  		if ( vBase.isArrayType() || vBase.isEnumType() ) {
  			Log.error("DataType.createType: base type must not be an array- or enum-type");
  		}
  		if ( sName === 'array' || mTypes[sName] instanceof DataType ) {
  			if ( sName === 'array' || mTypes[sName].getBaseType() == null ) {
  				throw new Error("DataType.createType: primitive or hidden type " + sName + " can't be re-defined");
  			}
  			Log.warning("DataTypes.createType: type " + sName + " is redefined. " +
  				"This is an unsupported usage of DataType and might cause issues." );
  		}
  		var oType = mTypes[sName] = createType(sName, mSettings, vBase);
  		return oType;
  	};
  
  
  	// ---- minimal support for interface types -------------------------------------------------------------------
  
  	var oInterfaces = new Set();
  
  	/**
  	 * Registers the given array of type names as known interface types.
  	 * Only purpose is to enable the {@link #isInterfaceType} check.
  	 * @param {string[]} aTypes interface types to be registered
  	 * @private
  	 * @ui5-restricted sap.ui.core.Core
  	 */
  	DataType.registerInterfaceTypes = function(aTypes) {
  		aTypes.forEach(function(sType) {
  			oInterfaces.add(sType);
  
  			// Defining the interface on global namespace for compatibility reasons.
  			// This has never been a public feature and it is strongly discouraged it be relied upon.
  			// An interface must always be referenced by a string literal, not via the global namespace.
  			ObjectPath.set(sType, sType);
  		});
  	};
  
  	/**
  	 * @param {string} sType name of type to check
  	 * @returns {boolean} whether the given type is known to be an interface type
  	 * @private
  	 * @ui5-restricted sap.ui.base.ManagedObject
  	 */
  	DataType.isInterfaceType = function(sType) {
  		return oInterfaces.has(sType);
  	};
  
  
  	return DataType;
  
  }, /* bExport= */ true);
  