text: // valid-jsdoc disabled because this check is validating just the params and return statement and those are all inherited from BaseTreeModifier.
  /* eslint-disable valid-jsdoc */
  /*!
   * ${copyright}
   */
  
  sap.ui.define([
  	"sap/ui/base/BindingParser",
  	"./BaseTreeModifier",
  	"./XmlTreeModifier",
  	"sap/base/util/ObjectPath",
  	"sap/ui/util/XMLHelper",
  	"sap/base/util/merge",
  	"sap/ui/core/Fragment" // also needed to have sap.ui.xmlfragment
  ], function (
  	BindingParser,
  	BaseTreeModifier,
  	XmlTreeModifier,
  	ObjectPath,
  	XMLHelper,
  	merge,
  	Fragment
  ) {
  
  
  	"use strict";
  	/**
  	 * Static utility class to access ManagedObjects in a harmonized way with XMLNodes.
  	 *
  	 * @namespace sap.ui.core.util.reflection.JsControlTreeModifier
  	 * @extends sap.ui.core.util.reflection.BaseTreeModifier
  	 * @private
  	 * @ui5-restricted
  	 * @since 1.56.0
  	 */
  	var JsControlTreeModifier = /** @lends sap.ui.core.util.reflection.JsControlTreeModifier */ {
  
  		targets: "jsControlTree",
  
  		/**
  		 * @inheritDoc
  		 */
  		setVisible: function (oControl, bVisible) {
  			if (oControl.setVisible) {
  				this.unbindProperty(oControl, "visible");
  				oControl.setVisible(bVisible);
  			} else {
  				throw new Error("Provided control instance has no setVisible method");
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getVisible: function (oControl) {
  			if (oControl.getVisible) {
  				return oControl.getVisible();
  			} else {
  				throw new Error("Provided control instance has no getVisible method");
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		setStashed: function (oControl, bStashed) {
  			bStashed = !!bStashed;
  			if (oControl.unstash) {
  				// check if the control is stashed and should be unstashed
  				if (oControl.isStashed() === true && bStashed === false) {
  					oControl = oControl.unstash();
  				}
  
  				// ensure original control's visible property is set
  				if (oControl.setVisible) {
  					this.setVisible(oControl, !bStashed);
  				}
  
  				return oControl;
  			} else {
  				throw new Error("Provided control instance has no unstash method");
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getStashed: function (oControl) {
  			if (oControl.isStashed) {
  				return oControl.isStashed() ? oControl.isStashed() : !this.getVisible(oControl);
  			}
  			throw new Error("Provided control instance has no isStashed method");
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		bindProperty: function (oControl, sPropertyName, vBindingInfos) {
  			oControl.bindProperty(sPropertyName, vBindingInfos);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		unbindProperty: function (oControl, sPropertyName) {
  			if (oControl) {
  				oControl.unbindProperty(sPropertyName, /*bSuppressReset = */true);
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		setProperty: function (oControl, sPropertyName, vPropertyValue) {
  			var oMetadata = oControl.getMetadata().getPropertyLikeSetting(sPropertyName);
  			var oBindingParserResult;
  			var bError;
  
  			this.unbindProperty(oControl, sPropertyName);
  
  			try {
  				oBindingParserResult = BindingParser.complexParser(vPropertyValue, undefined, true);
  			} catch (error) {
  				bError = true;
  			}
  
  			//For compatibility with XMLTreeModifier the value should be serializable
  			if (oMetadata) {
  				if (this._isSerializable(vPropertyValue)) {
  					if (oBindingParserResult && typeof oBindingParserResult === "object" || bError) {
  						vPropertyValue = this._escapeCurlyBracketsInString(vPropertyValue);
  					}
  					var sPropertySetter = oMetadata._sMutator;
  					oControl[sPropertySetter](vPropertyValue);
  				} else {
  					throw new TypeError("Value cannot be stringified", "sap.ui.core.util.reflection.JsControlTreeModifier");
  				}
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getProperty: function (oControl, sPropertyName) {
  			var oMetadata = oControl.getMetadata().getPropertyLikeSetting(sPropertyName);
  			if (oMetadata) {
  				var sPropertyGetter = oMetadata._sGetter;
  				return oControl[sPropertyGetter]();
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		isPropertyInitial: function (oControl, sPropertyName) {
  			return oControl.isPropertyInitial(sPropertyName);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		setPropertyBinding: function (oControl, sPropertyName, oPropertyBinding) {
  			this.unbindProperty(oControl, sPropertyName);
  			var mSettings = {};
  			mSettings[sPropertyName] = oPropertyBinding;
  			oControl.applySettings(mSettings);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getPropertyBinding: function (oControl, sPropertyName) {
  			return oControl.getBindingInfo(sPropertyName);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		createAndAddCustomData: function(oControl, sCustomDataKey, sValue, oAppComponent) {
  			var oCustomData = this.createControl("sap.ui.core.CustomData", oAppComponent);
  			this.setProperty(oCustomData, "key", sCustomDataKey);
  			this.setProperty(oCustomData, "value", sValue);
  			this.insertAggregation(oControl, "customData", oCustomData, 0);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		createControl: function (sClassName, oAppComponent, oView, oSelector, mSettings, bAsync) {
  			var sErrorMessage;
  			if (this.bySelector(oSelector, oAppComponent)) {
  				sErrorMessage = "Can't create a control with duplicated ID " + (oSelector.id || oSelector);
  				if (bAsync) {
  					return Promise.reject(sErrorMessage);
  				}
  				throw new Error(sErrorMessage);
  			}
  
  			if (bAsync) {
  				return new Promise(function(fnResolve, fnReject) {
  					sap.ui.require([sClassName.replace(/\./g,"/")],
  						function(ClassObject) {
  							var sId = this.getControlIdBySelector(oSelector, oAppComponent);
  							fnResolve(new ClassObject(sId, mSettings));
  						}.bind(this),
  						function() {
  							fnReject(new Error("Required control '" + sClassName + "' couldn't be created asynchronously"));
  						}
  					);
  				}.bind(this));
  			}
  
  			// in the synchronous case, object should already be preloaded
  			var ClassObject = ObjectPath.get(sClassName);
  			if (!ClassObject) {
  				throw new Error("Can't create a control because the matching class object has not yet been loaded. Please preload the '" + sClassName + "' module");
  			}
  			var sId = this.getControlIdBySelector(oSelector, oAppComponent);
  			return new ClassObject(sId, mSettings);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		applySettings: function(oControl, mSettings) {
  			oControl.applySettings(mSettings);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		_byId: function (sId) {
  			return sap.ui.getCore().byId(sId);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getId: function (oControl) {
  			return oControl.getId();
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getParent: function (oControl) {
  			return oControl.getParent && oControl.getParent();
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getControlMetadata: function (oControl) {
  			return oControl && oControl.getMetadata();
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getControlType: function (oControl) {
  			return oControl && oControl.getMetadata().getName();
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		setAssociation: function (vParent, sName, sId) {
  			var oMetadata = vParent.getMetadata().getAssociation(sName);
  			oMetadata.set(vParent, sId);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getAssociation: function (vParent, sName) {
  			var oMetadata = vParent.getMetadata().getAssociation(sName);
  			return oMetadata.get(vParent);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getAllAggregations: function (oParent) {
  			return oParent.getMetadata().getAllAggregations();
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getAggregation: function (oParent, sName) {
  			var oAggregation = this.findAggregation(oParent, sName);
  			if (oAggregation) {
  				return oParent[oAggregation._sGetter]();
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		insertAggregation: function (oParent, sName, oObject, iIndex) {
  			//special handling without invalidation for customData
  			if ( sName === "customData"){
  				oParent.insertAggregation(sName, oObject, iIndex, /*bSuppressInvalidate=*/true);
  			} else {
  				var oAggregation = this.findAggregation(oParent, sName);
  				if (oAggregation) {
  					if (oAggregation.multiple) {
  						var iInsertIndex = iIndex || 0;
  						oParent[oAggregation._sInsertMutator](oObject, iInsertIndex);
  					} else {
  						oParent[oAggregation._sMutator](oObject);
  					}
  				}
  			}
  
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		removeAggregation: function (oControl, sName, oObject) {
  			//special handling without invalidation for customData
  			if ( sName === "customData"){
  				oControl.removeAggregation(sName, oObject, /*bSuppressInvalidate=*/true);
  			} else {
  				var oAggregation = this.findAggregation(oControl, sName);
  				if (oAggregation) {
  					oControl[oAggregation._sRemoveMutator](oObject);
  				}
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		removeAllAggregation: function (oControl, sName) {
  			//special handling without invalidation for customData
  			if ( sName === "customData"){
  				oControl.removeAllAggregation(sName, /*bSuppressInvalidate=*/true);
  			} else {
  				var oAggregation = this.findAggregation(oControl, sName);
  				if (oAggregation) {
  					oControl[oAggregation._sRemoveAllMutator]();
  				}
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getBindingTemplate: function (oControl, sAggregationName) {
  			var oBinding = oControl.getBindingInfo(sAggregationName);
  			return oBinding && oBinding.template;
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		updateAggregation: function (oControl, sAggregationName) {
  			var oAggregation = this.findAggregation(oControl, sAggregationName);
  			if (oAggregation) {
  				oControl[oAggregation._sDestructor]();
  				oControl.updateAggregation(sAggregationName);
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		findIndexInParentAggregation: function(oControl) {
  			var oParent = this.getParent(oControl),
  				aControlsInAggregation;
  
  			if (!oParent) {
  				return -1;
  			}
  
  			// we need all controls in the aggregation
  			aControlsInAggregation = this.getAggregation(oParent, this.getParentAggregationName(oControl));
  
  			// if aControls is an array:
  			if (Array.isArray(aControlsInAggregation)) {
  				// then the aggregtion is multiple and we can find the index of
  				// oControl in the array
  				return aControlsInAggregation.indexOf(oControl);
  			} else {
  				// if aControlsInAggregation is not an array, then the aggregation is
  				// of type 0..1 and aControlsInAggregation is the oControl provided
  				// to the function initially, so its index is 0
  				return 0;
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getParentAggregationName: function (oControl) {
  			return oControl.sParentAggregationName;
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		findAggregation: function(oControl, sAggregationName) {
  			if (oControl) {
  				if (oControl.getMetadata) {
  					var oMetadata = oControl.getMetadata();
  					var oAggregations = oMetadata.getAllAggregations();
  					if (oAggregations) {
  						return oAggregations[sAggregationName];
  					}
  				}
  			}
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		validateType: function(oControl, oAggregationMetadata, oParent, sFragment) {
  			var sTypeOrInterface = oAggregationMetadata.type;
  
  			// if aggregation is not multiple and already has element inside, then it is not valid for element
  			if (oAggregationMetadata.multiple === false && this.getAggregation(oParent, oAggregationMetadata.name) &&
  					this.getAggregation(oParent, oAggregationMetadata.name).length > 0) {
  				return false;
  			}
  			return this._isInstanceOf(oControl, sTypeOrInterface) || this._hasInterface(oControl, sTypeOrInterface);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		instantiateFragment: function(sFragment, sNamespace, oView) {
  			var oFragment = XMLHelper.parse(sFragment);
  			oFragment = this._checkAndPrefixIdsInFragment(oFragment, sNamespace);
  
  			var aNewControls;
  			var sId = oView && oView.getId();
  			var oController = oView.getController();
  			aNewControls = sap.ui.xmlfragment({
  				fragmentContent: oFragment,
  				sId:sId
  			}, oController);
  
  			if (!Array.isArray(aNewControls)) {
  				aNewControls = [aNewControls];
  			}
  			return aNewControls;
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		templateControlFragment: function(sFragmentName, mPreprocessorSettings, oView) {
  			return BaseTreeModifier._templateFragment(
  				sFragmentName,
  				mPreprocessorSettings
  			).then(function(oFragment) {
  				var oController = (oView && oView.getController()) || undefined;
  				return Fragment.load({
  					definition: oFragment,
  					controller: oController
  				});
  			});
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		destroy: function(oControl, bSuppressInvalidate) {
  			oControl.destroy(bSuppressInvalidate);
  		},
  
  		_getFlexCustomData: function(oControl, sType) {
  			var oCustomData = typeof oControl === "object"
  				&& typeof oControl.data === "function"
  				&& oControl.data("sap-ui-custom-settings");
  			return ObjectPath.get(["sap.ui.fl", sType], oCustomData);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		attachEvent: function (oObject, sEventName, sFunctionPath, vData) {
  			var fnCallback = ObjectPath.get(sFunctionPath);
  
  			if (typeof fnCallback !== "function") {
  				throw new Error("Can't attach event because the event handler function is not found or not a function.");
  			}
  
  			oObject.attachEvent(sEventName, vData, fnCallback);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		detachEvent: function (oObject, sEventName, sFunctionPath) {
  			var fnCallback = ObjectPath.get(sFunctionPath);
  
  			if (typeof fnCallback !== "function") {
  				throw new Error("Can't attach event because the event handler function is not found or not a function.");
  			}
  
  			// EventProvider.detachEvent doesn't accept vData parameter, therefore it might lead
  			// to a situation when an incorrect event listener is detached.
  			oObject.detachEvent(sEventName, fnCallback);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		bindAggregation: function (oControl, sAggregationName, oBindingInfo) {
  			oControl.bindAggregation(sAggregationName, oBindingInfo);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		unbindAggregation: function (oControl, sAggregationName) {
  			// bSuppressReset is not supported
  			oControl.unbindAggregation(sAggregationName);
  		},
  
  		/**
  		 * @inheritDoc
  		 */
  		getExtensionPointInfo: function(sExtensionPointName, oView) {
  			var oViewNode = (oView._xContent) ? oView._xContent : oView;
  			var oExtensionPointInfo = XmlTreeModifier.getExtensionPointInfo(sExtensionPointName, oViewNode);
  			if (oExtensionPointInfo) {
  				// decrease the index by 1 to get the index of the extension point itself for js-case
  				oExtensionPointInfo.index--;
  				oExtensionPointInfo.parent = oExtensionPointInfo.parent && this._byId(oView.createId(oExtensionPointInfo.parent.getAttribute("id")));
  				oExtensionPointInfo.defaultContent = oExtensionPointInfo.defaultContent
  					.map(function (oNode) {
  						var sId = oView.createId(oNode.getAttribute("id"));
  						return this._byId(sId);
  					}.bind(this))
  					.filter(function (oControl) {
  						return !!oControl;
  					});
  			}
  			return oExtensionPointInfo;
  		}
  	};
  
  	return merge(
  		{} /* target object, to avoid changing of original modifier */,
  		BaseTreeModifier,
  		JsControlTreeModifier
  	);
  },
  /* bExport= */true);
  