UNPKG

@ui5/task-adaptation

Version:

Custom task for ui5-builder which allows building UI5 Flexibility Adaptation Projects for SAP BTP, Cloud Foundry environment

1,329 lines (1,303 loc) 334 kB
var window = {}; var AppDescriptorChange = function (content) { this.content = content; }; AppDescriptorChange.prototype.getChangeType = function () { return this.content?.flexObjectMetadata?.changeType || this.content?.changeType; }; AppDescriptorChange.prototype.getLayer = function () { return this.content.layer; }; AppDescriptorChange.prototype.getContent = function () { return this.content.content; }; AppDescriptorChange.prototype.getTexts = function () { return this.content.texts; }; var fnIsEmptyObject = function isEmptyObject(obj) { for (var sName in obj) { return false; } return true; }; var rVersion = /^[0-9]+(?:\.([0-9]+)(?:\.([0-9]+))?)?(.*)$/; function Version(vMajor, iMinor, iPatch, sSuffix) { if (vMajor instanceof Version) { return vMajor; } if (!(this instanceof Version)) { return new Version(vMajor, iMinor, iPatch, sSuffix); } var m; if (typeof vMajor === "string") { m = rVersion.exec(vMajor); } else if (Array.isArray(vMajor)) { m = vMajor; } else { m = arguments; } m = m || []; function norm(v) { v = parseInt(v); return isNaN(v) ? 0 : v; } vMajor = norm(m[0]); iMinor = norm(m[1]); iPatch = norm(m[2]); sSuffix = String(m[3] || ""); this.toString = function () { return vMajor + "." + iMinor + "." + iPatch + sSuffix; }; this.getMajor = function () { return vMajor; }; this.getMinor = function () { return iMinor; }; this.getPatch = function () { return iPatch; }; this.getSuffix = function () { return sSuffix; }; this.compareTo = function (vOtherMajor, iOtherMinor, iOtherPatch, sOtherSuffix) { var vOther = Version.apply(window, arguments); return vMajor - vOther.getMajor() || iMinor - vOther.getMinor() || iPatch - vOther.getPatch() || (sSuffix < vOther.getSuffix() ? -1 : sSuffix === vOther.getSuffix() ? 0 : 1); }; } Version.prototype.inRange = function (vMin, vMax) { return this.compareTo(vMin) >= 0 && this.compareTo(vMax) < 0; }; function _mergeExistingLibrary(oManifestLib, oChangeLib) { var oUpdatedLibrary = {}; if (oChangeLib.minVersion) { var vManifest = new Version(oManifestLib.minVersion); oUpdatedLibrary.minVersion = vManifest.compareTo(oChangeLib.minVersion) >= 0 ? oManifestLib.minVersion : oChangeLib.minVersion; } if (oChangeLib.lazy) { oUpdatedLibrary.lazy = oManifestLib.lazy === oChangeLib.lazy === true; } return oUpdatedLibrary; } var AddLibrary = { applyChange(oManifest, oChange) { oManifest["sap.ui5"].dependencies.libs ||= {}; var oManifestLibs = oManifest["sap.ui5"].dependencies.libs; var oChangeLibs = oChange.getContent().libraries; Object.keys(oChangeLibs).forEach(function (sLibName) { if (oManifestLibs[sLibName]) { oManifestLibs[sLibName] = _mergeExistingLibrary(oManifestLibs[sLibName], oChangeLibs[sLibName]); } else { oManifestLibs[sLibName] = oChangeLibs[sLibName]; } }); return oManifest; } }; var CondenserClassification = { LastOneWins: "lastOneWins", Reverse: "reverse", Move: "move", Create: "create", Destroy: "destroy", Update: "update" }; var SetTitle = { applyChange(oManifest) { oManifest["sap.app"].title = `{{${oManifest["sap.app"].id}_sap.app.title}}`; return oManifest; }, getCondenserInfo() { return { classification: CondenserClassification.LastOneWins, uniqueKey: "manifestSetTitle" }; } }; const SetDescription = { applyChange(oManifest) { oManifest["sap.app"].description = `{{${oManifest["sap.app"].id}_sap.app.description}}`; return oManifest; } }; var ObjectPath = {}; var defaultRootContext = globalThis; function getObjectPathArray(vObjectPath) { return Array.isArray(vObjectPath) ? vObjectPath.slice() : vObjectPath.split("."); } ObjectPath.create = function (vObjectPath, oRootContext) { var oObject = oRootContext || defaultRootContext; var aNames = getObjectPathArray(vObjectPath); for (var i = 0; i < aNames.length; i++) { var sName = aNames[i]; if (oObject[sName] === null || oObject[sName] !== undefined && (typeof oObject[sName] !== "object" && typeof oObject[sName] !== "function")) { throw new Error("Could not set object-path for '" + aNames.join(".") + "', path segment '" + sName + "' already exists."); } oObject[sName] = oObject[sName] || ({}); oObject = oObject[sName]; } return oObject; }; ObjectPath.get = function (vObjectPath, oRootContext) { var oObject = oRootContext || defaultRootContext; var aNames = getObjectPathArray(vObjectPath); var sPropertyName = aNames.pop(); for (var i = 0; i < aNames.length && oObject; i++) { oObject = oObject[aNames[i]]; } return oObject ? oObject[sPropertyName] : undefined; }; ObjectPath.set = function (vObjectPath, vValue, oRootContext) { oRootContext = oRootContext || defaultRootContext; var aNames = getObjectPathArray(vObjectPath); var sPropertyName = aNames.pop(); var oObject = ObjectPath.create(aNames, oRootContext); oObject[sPropertyName] = vValue; }; var ChangeCard = { applyChange(oManifest, oChange) { var oChangedCard = oChange.getContent(); var bIsOperationValid = oChangedCard.entityPropertyChange.operation === "UPSERT"; var oOldCards = oManifest["sap.ovp"].cards; var oPropertyChange = oChangedCard.entityPropertyChange; if (Array.isArray(oPropertyChange)) { throw Error("Expected value for oPropertyChange was an object"); } if (!bIsOperationValid) { throw Error("This Operation is not supported"); } if ((oChangedCard.cardId in oOldCards) && ("propertyPath" in oPropertyChange)) { ObjectPath.set([oChangedCard.cardId, oPropertyChange.propertyPath], oPropertyChange.propertyValue, oOldCards); } else { throw Error("Change card settings was not found"); } return oManifest; } }; var AddNewCard = { applyChange(oManifest, oChange) { var oNewCard = oChange.getContent(); var oOldCards = oManifest["sap.ovp"].cards; if (("card" in oNewCard) && Object.keys(oNewCard.card).length > 0 && !((Object.keys(oNewCard.card) in oOldCards))) { Object.assign(oOldCards, oNewCard.card); } else { throw Error("No new card found"); } return oManifest; } }; var DeleteCard = { applyChange(oManifest, oChange) { var oDeleteCard = oChange.getContent(); var oOldCards = oManifest["sap.ovp"].cards; if ((oDeleteCard.cardId in oOldCards)) { delete oOldCards[oDeleteCard.cardId]; } else { throw Error("The card to be deleted was not found"); } return oManifest; } }; var fnAssert = function (bResult, vMessage) { if (!bResult) { var sMessage = typeof vMessage === "function" ? vMessage() : vMessage; console.assert(bResult, sMessage); } }; var fnNow = function now() { return performance.timeOrigin + performance.now(); }; var Log = {}; Log.Level = { NONE: -1, FATAL: 0, ERROR: 1, WARNING: 2, INFO: 3, DEBUG: 4, TRACE: 5, ALL: 5 + 1 }; var aLog = [], mMaxLevel = { "": Log.Level.ERROR }, iLogEntriesLimit = 3000, oListener = null, bLogSupportInfo = false; function pad0(i, w) { return ("000" + String(i)).slice(-w); } function level(sComponent) { return !sComponent || isNaN(mMaxLevel[sComponent]) ? mMaxLevel[""] : mMaxLevel[sComponent]; } function discardLogEntries() { var iLogLength = aLog.length; if (iLogLength) { var iEntriesToKeep = Math.min(iLogLength, Math.floor(iLogEntriesLimit * 0.7)); if (oListener) { oListener.onDiscardLogEntries(aLog.slice(0, iLogLength - iEntriesToKeep)); } if (iEntriesToKeep) { aLog = aLog.slice(-iEntriesToKeep, iLogLength); } else { aLog = []; } } } function getLogEntryListenerInstance() { if (!oListener) { oListener = { listeners: [], onLogEntry: function (oLogEntry) { for (var i = 0; i < oListener.listeners.length; i++) { if (oListener.listeners[i].onLogEntry) { oListener.listeners[i].onLogEntry(oLogEntry); } } }, onDiscardLogEntries: function (aDiscardedLogEntries) { for (var i = 0; i < oListener.listeners.length; i++) { if (oListener.listeners[i].onDiscardLogEntries) { oListener.listeners[i].onDiscardLogEntries(aDiscardedLogEntries); } } }, attach: function (oLog, oLstnr) { if (oLstnr) { oListener.listeners.push(oLstnr); if (oLstnr.onAttachToLog) { oLstnr.onAttachToLog(oLog); } } }, detach: function (oLog, oLstnr) { for (var i = 0; i < oListener.listeners.length; i++) { if (oListener.listeners[i] === oLstnr) { if (oLstnr.onDetachFromLog) { oLstnr.onDetachFromLog(oLog); } oListener.listeners.splice(i, 1); return; } } } }; } return oListener; } Log.fatal = function (sMessage, vDetails, sComponent, fnSupportInfo) { log(Log.Level.FATAL, sMessage, vDetails, sComponent, fnSupportInfo); }; Log.error = function (sMessage, vDetails, sComponent, fnSupportInfo) { log(Log.Level.ERROR, sMessage, vDetails, sComponent, fnSupportInfo); }; Log.warning = function (sMessage, vDetails, sComponent, fnSupportInfo) { log(Log.Level.WARNING, sMessage, vDetails, sComponent, fnSupportInfo); }; Log.info = function (sMessage, vDetails, sComponent, fnSupportInfo) { log(Log.Level.INFO, sMessage, vDetails, sComponent, fnSupportInfo); }; Log.debug = function (sMessage, vDetails, sComponent, fnSupportInfo) { log(Log.Level.DEBUG, sMessage, vDetails, sComponent, fnSupportInfo); }; Log.trace = function (sMessage, vDetails, sComponent, fnSupportInfo) { log(Log.Level.TRACE, sMessage, vDetails, sComponent, fnSupportInfo); }; Log.setLevel = function (iLogLevel, sComponent, _bDefault) { sComponent = sComponent || ""; if (!_bDefault || mMaxLevel[sComponent] == null) { mMaxLevel[sComponent] = iLogLevel; var sLogLevel; Object.keys(Log.Level).forEach(function (sLevel) { if (Log.Level[sLevel] === iLogLevel) { sLogLevel = sLevel; } }); log(Log.Level.INFO, "Changing log level " + (sComponent ? "for '" + sComponent + "' " : "") + "to " + sLogLevel, "", "sap.base.log"); } }; Log.getLevel = function (sComponent) { return level(sComponent); }; Log.isLoggable = function (iLevel, sComponent) { return (iLevel == null ? Log.Level.DEBUG : iLevel) <= level(sComponent); }; Log.logSupportInfo = function (bEnabled) { bLogSupportInfo = bEnabled; }; function log(iLevel, sMessage, vDetails, sComponent, fnSupportInfo) { if (!fnSupportInfo && !sComponent && typeof vDetails === "function") { fnSupportInfo = vDetails; vDetails = ""; } if (!fnSupportInfo && typeof sComponent === "function") { fnSupportInfo = sComponent; sComponent = ""; } if (iLevel <= level(sComponent)) { var fNow = fnNow(), oNow = new Date(fNow), iMicroSeconds = Math.floor((fNow - Math.floor(fNow)) * 1000), oLogEntry = { time: pad0(oNow.getHours(), 2) + ":" + pad0(oNow.getMinutes(), 2) + ":" + pad0(oNow.getSeconds(), 2) + "." + pad0(oNow.getMilliseconds(), 3) + pad0(iMicroSeconds, 3), date: pad0(oNow.getFullYear(), 4) + "-" + pad0(oNow.getMonth() + 1, 2) + "-" + pad0(oNow.getDate(), 2), timestamp: fNow, level: iLevel, message: String(sMessage || ""), details: String(vDetails || ""), component: String(sComponent || "") }; if (bLogSupportInfo && typeof fnSupportInfo === "function") { oLogEntry.supportInfo = fnSupportInfo(); } if (iLogEntriesLimit) { if (aLog.length >= iLogEntriesLimit) { discardLogEntries(); } aLog.push(oLogEntry); } if (oListener) { oListener.onLogEntry(oLogEntry); } if (console) { var isDetailsError = vDetails instanceof Error, logText = oLogEntry.date + " " + oLogEntry.time + " " + oLogEntry.message + " - " + oLogEntry.details + " " + oLogEntry.component; switch (iLevel) { case Log.Level.FATAL: case Log.Level.ERROR: isDetailsError ? console.error(logText, "\n", vDetails) : console.error(logText); break; case Log.Level.WARNING: isDetailsError ? console.warn(logText, "\n", vDetails) : console.warn(logText); break; case Log.Level.INFO: if (console.info) { isDetailsError ? console.info(logText, "\n", vDetails) : console.info(logText); } else { isDetailsError ? console.log(logText, "\n", vDetails) : console.log(logText); } break; case Log.Level.DEBUG: isDetailsError ? console.debug(logText, "\n", vDetails) : console.debug(logText); break; case Log.Level.TRACE: isDetailsError ? console.trace(logText, "\n", vDetails) : console.trace(logText); break; } if (console.info && oLogEntry.supportInfo) { console.info(oLogEntry.supportInfo); } } return oLogEntry; } } Log.getLogEntries = function () { return aLog.slice(); }; Log.getLogEntriesLimit = function () { return iLogEntriesLimit; }; Log.setLogEntriesLimit = function (iLimit) { if (iLimit < 0) { throw new Error("The log entries limit needs to be greater than or equal to 0!"); } iLogEntriesLimit = iLimit; if (aLog.length >= iLogEntriesLimit) { discardLogEntries(); } }; Log.addLogListener = function (oListener) { getLogEntryListenerInstance().attach(this, oListener); }; Log.removeLogListener = function (oListener) { getLogEntryListenerInstance().detach(this, oListener); }; function Logger(sComponent) { this.fatal = function (msg, detail, comp, support) { Log.fatal(msg, detail, comp || sComponent, support); return this; }; this.error = function (msg, detail, comp, support) { Log.error(msg, detail, comp || sComponent, support); return this; }; this.warning = function (msg, detail, comp, support) { Log.warning(msg, detail, comp || sComponent, support); return this; }; this.info = function (msg, detail, comp, support) { Log.info(msg, detail, comp || sComponent, support); return this; }; this.debug = function (msg, detail, comp, support) { Log.debug(msg, detail, comp || sComponent, support); return this; }; this.trace = function (msg, detail, comp, support) { Log.trace(msg, detail, comp || sComponent, support); return this; }; this.setLevel = function (level, comp) { Log.setLevel(level, comp || sComponent); return this; }; this.getLevel = function (comp) { return Log.getLevel(comp || sComponent); }; this.isLoggable = function (level, comp) { return Log.isLoggable(level, comp || sComponent); }; } Log.getLogger = function (sComponent, iDefaultLogLevel) { if (!isNaN(iDefaultLogLevel) && mMaxLevel[sComponent] == null) { mMaxLevel[sComponent] = iDefaultLogLevel; } return new Logger(sComponent); }; var fnUniqueSort = function (aArray) { fnAssert(Array.isArray(aArray), "uniqueSort: input parameter must be an Array"); var iLength = aArray.length; if (iLength > 1) { aArray.sort(); var j = 0; for (var i = 1; i < iLength; i++) { if (aArray.indexOf(aArray[i]) === i) { aArray[++j] = aArray[i]; } } if (++j < iLength) { aArray.splice(j, iLength - j); } } return aArray; }; function isFunction(obj) { return typeof obj === "function"; } var Metadata = function (sClassName, oClassInfo) { fnAssert(typeof sClassName === "string" && sClassName, "Metadata: sClassName must be a non-empty string"); fnAssert(typeof oClassInfo === "object", "Metadata: oClassInfo must be empty or an object"); if (!oClassInfo || typeof oClassInfo.metadata !== "object") { oClassInfo = { metadata: oClassInfo || ({}), constructor: ObjectPath.get(sClassName) }; oClassInfo.metadata.__version = 1; } oClassInfo.metadata ??= {}; oClassInfo.metadata.__version = oClassInfo.metadata.__version || 2; if (!isFunction(oClassInfo.constructor)) { throw Error("constructor for class " + sClassName + " must have been declared before creating metadata for it"); } this._sClassName = sClassName; this._oClass = oClassInfo.constructor; this.extend(oClassInfo); }; Metadata.prototype.extend = function (oClassInfo) { this.applySettings(oClassInfo); this.afterApplySettings(); }; Metadata.prototype.applySettings = function (oClassInfo) { var that = this, oStaticInfo = oClassInfo.metadata, oPrototype; if (oStaticInfo.baseType) { var oParentClass, bValidBaseType = isFunction(oStaticInfo.baseType); if (bValidBaseType) { oParentClass = oStaticInfo.baseType; if (!isFunction(oParentClass.getMetadata)) { throw new TypeError("baseType must be a UI5 class with a static getMetadata function"); } } if (!bValidBaseType) { oParentClass = ObjectPath.get(oStaticInfo.baseType); if (!isFunction(oParentClass)) { Log.fatal("base class '" + oStaticInfo.baseType + "' does not exist"); } } if (oParentClass.getMetadata) { this._oParent = oParentClass.getMetadata(); fnAssert(oParentClass === oParentClass.getMetadata().getClass(), "Metadata: oParentClass must match the class in the parent metadata"); } else { this._oParent = new Metadata(oStaticInfo.baseType, {}); } } else { this._oParent = undefined; } this._bAbstract = !!oStaticInfo["abstract"]; this._bFinal = !!oStaticInfo["final"]; this._sStereotype = oStaticInfo.stereotype || (this._oParent ? this._oParent._sStereotype : "object"); this._bDeprecated = !!oStaticInfo["deprecated"]; this._aInterfaces = oStaticInfo.interfaces || []; this._aPublicMethods = oStaticInfo.publicMethods || []; this._bInterfacesUnique = false; oPrototype = this._oClass.prototype; for (var n in oClassInfo) { if (n !== "metadata" && n !== "constructor") { oPrototype[n] = oClassInfo[n]; if (!n.match(/^_|^on|^init$|^exit$/)) { that._aPublicMethods.push(n); } } } }; Metadata.prototype.afterApplySettings = function () { if (this._oParent) { this._aAllPublicMethods = this._oParent._aAllPublicMethods.concat(this._aPublicMethods); this._bInterfacesUnique = false; } else { this._aAllPublicMethods = this._aPublicMethods; } }; Metadata.prototype.getStereotype = function () { return this._sStereotype; }; Metadata.prototype.getName = function () { return this._sClassName; }; Metadata.prototype.getClass = function () { return this._oClass; }; Metadata.prototype.getParent = function () { return this._oParent; }; Metadata.prototype._dedupInterfaces = function () { if (!this._bInterfacesUnique) { fnUniqueSort(this._aInterfaces); fnUniqueSort(this._aPublicMethods); fnUniqueSort(this._aAllPublicMethods); this._bInterfacesUnique = true; } }; Metadata.prototype.getPublicMethods = function () { this._dedupInterfaces(); return this._aPublicMethods; }; Metadata.prototype.getAllPublicMethods = function () { this._dedupInterfaces(); return this._aAllPublicMethods; }; Metadata.prototype.getInterfaces = function () { this._dedupInterfaces(); return this._aInterfaces; }; Metadata.prototype.isInstanceOf = function (sInterface) { if (this._oParent) { if (this._oParent.isInstanceOf(sInterface)) { return true; } } var a = this._aInterfaces; for (var i = 0, l = a.length; i < l; i++) { if (a[i] === sInterface) { return true; } } return false; }; Object.defineProperty(Metadata.prototype, "_mImplementedTypes", { get: function () { if (this === Metadata.prototype) { throw new Error("sap.ui.base.Metadata: The '_mImplementedTypes' property must not be accessed on the prototype"); } var result = Object.create(this._oParent ? this._oParent._mImplementedTypes : null); result[this._sClassName] = true; var aInterfaces = this._aInterfaces, i = aInterfaces.length; while (i-- > 0) { if (!result[aInterfaces[i]]) { result[aInterfaces[i]] = true; } } Object.defineProperty(this, "_mImplementedTypes", { value: Object.freeze(result), writable: false, configurable: false }); return result; }, configurable: true }); Metadata.prototype.isA = function (vTypeName) { var mTypes = this._mImplementedTypes; if (Array.isArray(vTypeName)) { for (var i = 0; i < vTypeName.length; i++) { if ((vTypeName[i] in mTypes)) { return true; } } return false; } return (vTypeName in mTypes); }; Metadata.prototype.isAbstract = function () { return this._bAbstract; }; Metadata.prototype.isFinal = function () { return this._bFinal; }; Metadata.prototype.isDeprecated = function () { return this._bDeprecated; }; Metadata.prototype.addPublicMethods = function (sMethod) { var aNames = sMethod instanceof Array ? sMethod : arguments; Array.prototype.push.apply(this._aPublicMethods, aNames); Array.prototype.push.apply(this._aAllPublicMethods, aNames); this._bInterfacesUnique = false; }; Metadata.prototype.getStaticProperty = function (sStaticName) { let oMetadata = this; while (oMetadata && !((sStaticName in oMetadata.getClass()))) { oMetadata = oMetadata.getParent(); } const oClass = oMetadata?.getClass(); return oClass?.[sStaticName]; }; Metadata.createClass = function (fnBaseClass, sClassName, oClassInfo, FNMetaImpl) { if (typeof fnBaseClass === "string") { FNMetaImpl = oClassInfo; oClassInfo = sClassName; sClassName = fnBaseClass; fnBaseClass = null; } fnAssert(!fnBaseClass || isFunction(fnBaseClass)); fnAssert(typeof sClassName === "string" && !!sClassName); fnAssert(!oClassInfo || typeof oClassInfo === "object"); fnAssert(!FNMetaImpl || isFunction(FNMetaImpl)); FNMetaImpl = FNMetaImpl || Metadata; if (isFunction(FNMetaImpl.preprocessClassInfo)) { oClassInfo = FNMetaImpl.preprocessClassInfo(oClassInfo); } oClassInfo = oClassInfo || ({}); oClassInfo.metadata = oClassInfo.metadata || ({}); if (!oClassInfo.hasOwnProperty("constructor")) { oClassInfo.constructor = undefined; } var fnClass = oClassInfo.constructor; fnAssert(!fnClass || isFunction(fnClass)); if (fnBaseClass) { if (!fnClass) { if (oClassInfo.metadata.deprecated) { fnClass = function () { Log.warning("Usage of deprecated class: " + sClassName); fnBaseClass.apply(this, arguments); }; } else { fnClass = function () { fnBaseClass.apply(this, arguments); }; } } fnClass.prototype = Object.create(fnBaseClass.prototype); fnClass.prototype.constructor = fnClass; oClassInfo.metadata.baseType = fnBaseClass; } else { fnClass = fnClass || (function () {}); delete oClassInfo.metadata.baseType; } oClassInfo.constructor = fnClass; ObjectPath.set(sClassName, fnClass); var oMetadata = new FNMetaImpl(sClassName, oClassInfo); fnClass.getMetadata = fnClass.prototype.getMetadata = function () { return oMetadata; }; if (!fnClass.getMetadata().isFinal()) { fnClass.extend = function (sSCName, oSCClassInfo, fnSCMetaImpl) { return Metadata.createClass(fnClass, sSCName, oSCClassInfo, fnSCMetaImpl || FNMetaImpl); }; } return fnClass; }; var BaseObject = Metadata.createClass("sap.ui.base.Object", { constructor: function () { if (!(this instanceof BaseObject)) { throw Error("Cannot instantiate object: \"new\" is missing!"); } } }); BaseObject.prototype.destroy = function () {}; BaseObject.prototype.getInterface = function () { var oInterface = new BaseObject._Interface(this, this.getMetadata().getAllPublicMethods()); this.getInterface = function () { return oInterface; }; return oInterface; }; BaseObject.defineClass = function (sClassName, oStaticInfo, FNMetaImpl) { var oMetadata = new (FNMetaImpl || Metadata)(sClassName, oStaticInfo); var fnClass = oMetadata.getClass(); fnClass.getMetadata = fnClass.prototype.getMetadata = function () { return oMetadata; }; if (!oMetadata.isFinal()) { fnClass.extend = function (sSCName, oSCClassInfo, fnSCMetaImpl) { return Metadata.createClass(fnClass, sSCName, oSCClassInfo, fnSCMetaImpl || FNMetaImpl); }; } Log.debug("defined class '" + sClassName + "'" + (oMetadata.getParent() ? " as subclass of " + oMetadata.getParent().getName() : "")); return oMetadata; }; BaseObject.prototype.isA = function (vTypeName) { return this.getMetadata().isA(vTypeName); }; BaseObject.isA = function (oObject, vTypeName) { return oObject instanceof BaseObject && oObject.isA(vTypeName); }; BaseObject.isObjectA = function (oObject, vTypeName) { return oObject instanceof BaseObject && oObject.isA(vTypeName); }; BaseObject._Interface = function (oObject, aMethods, _bReturnFacade) { if (!oObject) { return oObject; } function fCreateDelegator(oObject, sMethodName) { return function () { var tmp = oObject[sMethodName].apply(oObject, arguments); if (_bReturnFacade) { return this; } else { return tmp instanceof BaseObject ? tmp.getInterface() : tmp; } }; } if (!aMethods) { return {}; } var sMethodName; for (var i = 0, ml = aMethods.length; i < ml; i++) { sMethodName = aMethods[i]; if (!oObject[sMethodName] || typeof oObject[sMethodName] === "function") { this[sMethodName] = fCreateDelegator(oObject, sMethodName); } } }; var class2type = {}; var hasOwn$1 = class2type.hasOwnProperty; var toString = class2type.toString; var fnToString = hasOwn$1.toString; var ObjectFunctionString = fnToString.call(Object); var fnIsPlainObject = function (obj) { var proto, Ctor; if (!obj || toString.call(obj) !== "[object Object]") { return false; } proto = Object.getPrototypeOf(obj); if (!proto) { return true; } Ctor = hasOwn$1.call(proto, "constructor") && proto.constructor; return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; }; var oToken = Object.create(null); var fnMerge$1 = function () { var src, copyIsArray, copy, name, options, clone, target = arguments[2] || ({}), i = 3, length = arguments.length, deep = arguments[0] || false, skipToken = arguments[1] ? undefined : oToken; if (typeof target !== "object" && typeof target !== "function") { target = {}; } for (; i < length; i++) { if ((options = arguments[i]) != null) { for (name in options) { src = target[name]; copy = options[name]; if (name === "__proto__" || target === copy) { continue; } if (deep && copy && (fnIsPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { if (copyIsArray) { copyIsArray = false; clone = src && Array.isArray(src) ? src : []; } else { clone = src && fnIsPlainObject(src) ? src : {}; } target[name] = fnMerge$1(deep, arguments[1], clone, copy); } else if (copy !== skipToken) { target[name] = copy; } } } } return target; }; var fnExtend = function () { var args = [false, true]; args.push.apply(args, arguments); return fnMerge$1.apply(null, args); }; var sFioriComponent = "FioriElements: "; function getMethods(sClassName, oLog) { var sFullClassName = sFioriComponent + sClassName; return { Level: oLog.Level, addLogListener: function (oListener) { oLog.addLogListener(oListener); }, getLogger: function () { var oRet = oLog.getLogger(sFullClassName); return oRet; } }; } var FeLogger = BaseObject.extend("sap.suite.ui.generic.template.genericUtilities.FeLogger", { constructor: function (sClassName) { fnExtend(this, getMethods(sClassName, Log)); } }); var oLogger$2 = new FeLogger("manifestMerger.MergerUil").getLogger(); var GLOBAL_MANIFEST_CHANGE_COMPONENT$1 = "sap.suite.ui.generic.template"; function fnArrayToMap(aPages) { var oOutput = {}; aPages.forEach(function (oPage) { var sComponentName = oPage.component.name.split(".").pop(); var sKey = sComponentName + "|" + oPage.entitySet; oOutput[sKey] = oPage; if (oPage.pages) { oPage.pages = fnArrayToMap(oPage.pages); } }); return oOutput; } var mergerUtil = { transformPagesToMapStructure: function (oPages) { var oRet = oPages; if (Array.isArray(oPages)) { try { oRet = fnArrayToMap(oPages); } catch (e) { throw new Error("Manifest should have sap.ui.generic.app.pages as Object structure and not array "); } } return oRet; }, iterateAndFind: function iterateFind(oPages, sEntityKey, sPageComponent, sChildPageId, sParentKey) { var oPageStructure; if (Array.isArray(oPages)) { throw new Error("Manifest should have sap.ui.generic.app.pages as Object structure and not array "); } for (var sKey in oPages) { if (sKey === "entitySet" && oPages.entitySet === sEntityKey) { if (oPages.component && oPages.component.name === sPageComponent) { if (oPages.pages) { var aSiblingkeys = Object.keys(oPages.pages); findDuplicate(aSiblingkeys); } oLogger$2.info(oPages); return oPages; } } else if (typeof oPages[sKey] === "object" && !Array.isArray(oPages[sKey])) { if (oPageStructure) { break; } if (sKey === "pages" || sParentKey === "pages") { oPageStructure = iterateFind(oPages[sKey], sEntityKey, sPageComponent, sChildPageId, sKey); } } else if (sKey === "pages" && Array.isArray(oPages[sKey])) { throw new Error("Manifest should have sap.ui.generic.app.pages as Object structure and not array "); } } function findDuplicate(aSiblingkeys) { if (aSiblingkeys.length) { aSiblingkeys.filter(function (sPageKey) { if (sPageKey === sChildPageId) { throw new Error("Adding duplicate pageKey " + sChildPageId + " is not supported."); } }); } } return oPageStructure; }, consistencyCheck: function (oChangeContent, sMergerType, aSupportedProperties) { if (!oChangeContent["parentPage"]) { throw new Error("Mandatory 'parentPage' parameter is not provided."); } if (!oChangeContent.parentPage.component) { throw new Error("Mandatory 'parentPage.component' parameter is not provided."); } if (!oChangeContent.parentPage.entitySet && oChangeContent.parentPage.component !== GLOBAL_MANIFEST_CHANGE_COMPONENT$1) { throw new Error("Mandatory 'parentPage.entitySet' parameter is not provided."); } if (sMergerType === "ADD") { if (!oChangeContent.childPage.id) { throw new Error(" Add mandatory parameter 'childPage.id' "); } if (!oChangeContent.childPage.definition) { throw new Error("Mandatory 'childPageDefinition' are not provided. Add 'childPage.definition' to add the new page. "); } var aChildkeys = Object.keys(oChangeContent.childPage.definition); aChildkeys.forEach(function (sKey) { if (!aSupportedProperties.includes(sKey)) { throw new Error("Changing " + sKey + " is not supported. The supported 'propertyPath' is: " + aSupportedProperties.join(",")); } }); var aMandatoryParams = aSupportedProperties.filter(function (sComponentKey) { return !aChildkeys.includes(sComponentKey); }); if (aMandatoryParams.length) { throw new Error("Mandatory parameter " + aMandatoryParams + " is not defined."); } } else if (sMergerType === "MODIFY") { if (!oChangeContent.entityPropertyChange) { throw new Error("Changes for \"" + oChangeContent["pageId"] + "\" are not provided."); } else { var oEntityPropertyChange = oChangeContent.entityPropertyChange; if (!oEntityPropertyChange.propertyPath) { throw new Error("Invalid change format: The mandatory 'propertyPath' is not defined. Please define the mandatory property 'propertyPath'"); } if (!oEntityPropertyChange.operation || oEntityPropertyChange.operation !== "UPSERT") { throw new Error("Invalid change format: The mandatory 'operation' is not defined or is not valid type. Please define the mandatory property 'operation' with type 'UPSERT"); } if (oEntityPropertyChange.propertyValue === undefined) { throw new Error("Invalid change format: The mandatory 'propertyValue' is not defined. Please define the mandatory property 'propertyValue'"); } } } } }; var Layer = { USER: "USER", PUBLIC: "PUBLIC", CUSTOMER: "CUSTOMER", CUSTOMER_BASE: "CUSTOMER_BASE", PARTNER: "PARTNER", VENDOR: "VENDOR", BASE: "BASE" }; function checkObjectProperties(oChangeObject, aObjects, aMandatoryProperties, aSupportedProperties, oSupportedPropertyPattern, oSupportedPropertyTypes) { aObjects.forEach(function (sObject) { const oSetOfProperties = new Set(Object.keys(oChangeObject[sObject])); if (aMandatoryProperties) { aMandatoryProperties.forEach(function (sMandatoryProperty) { if (!oSetOfProperties.has(sMandatoryProperty)) { const sText = aMandatoryProperties.length > 1 ? "properties are" : "property is"; throw new Error(`Mandatory property '${sMandatoryProperty}' is missing. Mandatory ${sText} ${aMandatoryProperties.join("|")}.`); } }); } if (aSupportedProperties) { const notSupportedProperties = []; oSetOfProperties.forEach(function (sProperty) { if (!aSupportedProperties.includes(sProperty)) { notSupportedProperties.push(sProperty); } }); if (notSupportedProperties.length > 0) { const sText1 = notSupportedProperties.length > 1 ? `Properties ${notSupportedProperties.join("|")} are not supported. ` : `Property ${notSupportedProperties.join("|")} is not supported. `; const sText2 = aSupportedProperties.length > 1 ? `Supported properties are ${aSupportedProperties.join("|")}.` : `Supported property is $${aSupportedProperties.join("|")}.`; throw new Error(sText1 + sText2); } } if (oSupportedPropertyTypes) { oSetOfProperties.forEach(function (sProperty) { if (oSupportedPropertyTypes[sProperty]) { if (String(typeof oChangeObject[sObject][sProperty]) !== oSupportedPropertyTypes[sProperty]) { throw new Error(`The property '${sProperty}' is type of '${typeof oChangeObject[sObject][sProperty]}'. Supported type for property '${sProperty}' is '${oSupportedPropertyTypes[sProperty]}'`); } } }); } if (oSupportedPropertyPattern) { oSetOfProperties.forEach(function (sProperty) { if (oSupportedPropertyPattern[sProperty]) { const regex = new RegExp(oSupportedPropertyPattern[sProperty]); if (!regex.test(oChangeObject[sObject][sProperty])) { throw new Error(`The property has disallowed values. Supported values for '${sProperty}' should adhere to regular expression ${regex}.`); } } }); } }); } function getAndCheckContentObject(oChangeContent, sKey, sChangeType, aMandatoryProperties, aSupportedProperties, oSupportedPropertyPattern, oSupportedPropertyTypes) { const aObjectKeyNames = Object.keys(oChangeContent); if (aObjectKeyNames.length > 1) { throw new Error("It is not allowed to add more than one object under change object 'content'."); } if (aObjectKeyNames.length < 1) { throw new Error(`The change object 'content' cannot be empty. Please provide the necessary property, as outlined in the change schema for '${sChangeType}'.`); } if (aObjectKeyNames[0] !== sKey) { throw new Error(`The provided property '${aObjectKeyNames[0]}' is not supported. Supported property for change '${sChangeType}' is '${sKey}'.`); } const aObjectKeys = Object.keys(oChangeContent[sKey]); if (aObjectKeys.length > 1) { if (sKey === "dataSource") { if (aObjectKeys.length !== 2) { throw new Error("It is not allowed to add more than two data sources to manifest."); } } else { throw new Error(`It is not allowed to add more than one ${sKey}: ${aObjectKeys.join(", ")}.`); } } if (aObjectKeys.length < 1) { throw new Error(`There is no ${sKey} provided. Please provide an ${sKey}.`); } if (aObjectKeys.includes("")) { throw new Error(`The ID of your ${sKey} is empty.`); } checkObjectProperties(oChangeContent[sKey], aObjectKeys, aMandatoryProperties, aSupportedProperties, oSupportedPropertyPattern, oSupportedPropertyTypes); return sKey !== "dataSource" ? aObjectKeys[aObjectKeys.length - 1] : aObjectKeys; } function checkChange(oEntityPropertyChange, aSupportedProperties, aSupportedOperations, oSupportedPropertyPattern, aNotAllowedToBeDeleteProperties, oSupportedPropertyTypes) { const aEntityPropertyChanges = Array.isArray(oEntityPropertyChange) ? oEntityPropertyChange : [oEntityPropertyChange]; aEntityPropertyChanges.forEach(function (oChange) { formatEntityCheck(oChange, aSupportedProperties, aSupportedOperations, aNotAllowedToBeDeleteProperties, oSupportedPropertyTypes); checkPropertyValuePattern(oChange, oSupportedPropertyPattern); }); } function getClearedGenericPath(aSupportedProperties) { var aPropertiesClearedGenericPath = []; var aPropertiesWithGenericPath = aSupportedProperties.filter(function (sProperty) { return sProperty.endsWith("/*"); }); aPropertiesWithGenericPath.forEach(function (sProperty) { var sClearedProperty = sProperty.replaceAll("/*", ""); if (sClearedProperty) { aPropertiesClearedGenericPath.push(sClearedProperty); } }); return aPropertiesClearedGenericPath; } function isGenericPropertyPathSupported(aSupportedProperties, sPropertyPath) { const aClearedGenericPath = getClearedGenericPath(aSupportedProperties); let bIsGenericPathSupported = false; aClearedGenericPath.forEach(function (path) { if (sPropertyPath.startsWith(path)) { const sPathWithoutRoot = sPropertyPath.replace(path, ""); if (sPathWithoutRoot.startsWith("/") || sPathWithoutRoot === "") { bIsGenericPathSupported = true; } } }); return bIsGenericPathSupported; } function formatEntityCheck(oChangeEntity, aSupportedProperties, aSupportedOperations, aNotAllowedToBeDeleteProperties, oSupportedPropertyTypes) { if (!oChangeEntity.propertyPath) { throw new Error("Invalid change format: The mandatory 'propertyPath' is not defined. Please define the mandatory property 'propertyPath'"); } if (!oChangeEntity.operation) { throw new Error("Invalid change format: The mandatory 'operation' is not defined. Please define the mandatory property 'operation'"); } const sOpertationUpperCase = oChangeEntity.operation.toUpperCase(); if (sOpertationUpperCase === "DELETE") { if (aNotAllowedToBeDeleteProperties) { if (aNotAllowedToBeDeleteProperties.includes(oChangeEntity.propertyPath)) { throw new Error(`The property '${oChangeEntity.propertyPath}' was attempted to be deleted. The mandatory properties ${aNotAllowedToBeDeleteProperties.join("|")} cannot be deleted.`); } } if (oChangeEntity.hasOwnProperty("propertyValue")) { throw new Error("The property 'propertyValue' must not be provided in a 'DELETE' operation. Please remove 'propertyValue'."); } } if (sOpertationUpperCase !== "DELETE") { if (!oChangeEntity.hasOwnProperty("propertyValue")) { throw new Error("Invalid change format: The mandatory 'propertyValue' is not defined. Please define the mandatory property 'propertyValue'"); } if (!aSupportedProperties.includes(oChangeEntity.propertyPath) && !isGenericPropertyPathSupported(aSupportedProperties, oChangeEntity.propertyPath)) { throw new Error(`Changing ${oChangeEntity.propertyPath} is not supported. The supported 'propertyPath' is: ${aSupportedProperties.join("|")}`); } if (oSupportedPropertyTypes) { const aPropertyPath = oChangeEntity.propertyPath.split("/"); const sProperty = aPropertyPath[aPropertyPath.length - 1]; if (oSupportedPropertyTypes[sProperty]) { if (String(typeof oChangeEntity.propertyValue) !== oSupportedPropertyTypes[sProperty]) { throw new Error(`The property '${sProperty}' is type of '${typeof oChangeEntity.propertyValue}'. Supported type for property '${sProperty}' is '${oSupportedPropertyTypes[sProperty]}'.`); } } } } if (!aSupportedOperations.includes(sOpertationUpperCase)) { throw new Error(`Operation ${sOpertationUpperCase} is not supported. The supported 'operation' is ${aSupportedOperations.join("|")}`); } } function checkEntityPropertyChange(oChange, aSupportedProperties, aSupportedOperations, oSupportedPropertyPattern, aNotAllowedToBeDeleteProperties, oSupportedPropertyTypes) { var sId = Object.keys(oChange).filter(function (sKey) { return sKey.endsWith("Id"); }).shift(); if (!oChange[sId]) { throw new Error(`Mandatory "${sId}" parameter is not provided.`); } if (!oChange.entityPropertyChange) { throw new Error(`Changes for "${oChange[sId]}" are not provided.`); } checkChange(oChange.entityPropertyChange, aSupportedProperties, aSupportedOperations, oSupportedPropertyPattern, aNotAllowedToBeDeleteProperties, oSupportedPropertyTypes); } var layer_prefixes = {}; layer_prefixes[Layer.CUSTOMER] = "customer."; layer_prefixes[Layer.CUSTOMER_BASE] = "customer."; layer_prefixes[Layer.PARTNER] = "partner."; layer_prefixes[Layer.VENDOR] = null; function checkIdNamespaceCompliance(sId, oChange) { var sLayer = oChange.getLayer(); if (!sLayer) { throw new Error("Mandatory layer parameter is not provided."); } var sPrefix = getNamespacePrefixForLayer(sLayer); if (sPrefix === null) { Object.keys(layer_prefixes).forEach(function (sKey) { if (layer_prefixes[sKey] && sId.startsWith(layer_prefixes[sKey])) { throw new Error(`Id ${sId} must not start with reserved ${layer_prefixes[sKey]}`); } }); } else if (!sId.startsWith(sPrefix)) { throw new Error(`Id ${sId} must start with ${sPrefix}`); } } function getNamespacePrefixForLayer(sLayer) { var sPrefix = layer_prefixes[sLayer]; if (sPrefix === undefined) { throw new Error(`Layer ${sLayer} not supported.`); } return sPrefix; } function checkPropertyValuePattern(oChange, oSupportedPattern) { if (oSupportedPattern) { if (!Object.keys(oSupportedPattern).includes(oChange.propertyPath)) { return; } if (!oChange.propertyValue.match(oSupportedPattern[oChange.propertyPath])) { throw new Error(`Not supported format for propertyPath ${oChange.propertyPath}. ` + `The supported pattern is ${oSupportedPattern[oChange.propertyPath]}`); } } } var DescriptorChangeCheck = { checkEntityPropertyChange, checkIdNamespaceCompliance, getNamespacePrefixForLayer, getClearedGenericPath, isGenericPropertyPathSupported, getAndCheckContentObject }; var oLogger$1 = new FeLogger("manifestMerger.AddNewObjectPage").getLogger(); var addNewObjectPage = { applyChange: function (oManifest, oChange) { oLogger$1.info("addNewPage use case"); var aSupportedProperties = ["navigationProperty", "entitySet"]; var oChangeContent = oChange.getContent(); var sChildPageId = oChangeContent.childPage && oChangeContent.childPage.id; if (sChildPageId) { DescriptorChangeCheck.checkIdNamespaceCompliance(sChildPageId, oChange); } mergerUtil.consistencyCheck(oChangeContent, "ADD", aSupportedProperties); var sParentEntitySet = oChangeContent.parentPage.entitySet; var sParentComponent = oChangeContent.parentPage.component; var pages = oManifest["sap.ui.generic.app"]["pages"]; oManifest["sap.ui.generic.app"]["pages"] = mergerUtil.transformPagesToMapStructure(pages); var oPageStructure = mergerUtil.iterateAndFind(oManifest["sap.ui.generic.app"], sParentEntitySet, sParentComponent, sChildPageId); var oComponentContent = { "name": "sap.suite.ui.generic.template.ObjectPage" }; if (oPageStructure) { if (oPageStructure.pages && Array.isArray(oPageStructure.pages)) { throw Error("Manifest should have sap.ui.generic.app.pages as Object structure and not array"); } ObjectPath.create(["pages", sChildPageId], oPageStructure); ObjectPath.set(["pages", sChildPageId], oChangeContent.childPage.definition, oPageStructure); ObjectPath.set(["pages", sChildPageId, "component"], oComponentContent, oPageStructure); } else { throw Error("The target content definition is invalid"); } return oManifest; } }; var oLogger = new FeLogger("manifestMerger.ChangePageConfiguration").getLogger(); var GLOBAL_MANIFEST_CHANGE_COMPONENT = "sap.suite.ui.generic.template"; var changePageConfiguration = { applyChange: function (oManifest, oChange) { oLogger.info("modifyPageConfiguration use case"); var oChangeContent = oChange.getContent(); mergerUtil.consistencyCheck(oChangeContent, "MODIFY"); var sParentEntitySet = oChangeContent.parentPage.entitySet; var sParentComponent = oChangeContent.parentPage.component; var pages = oManifest["sap.ui.generic.app"]["pages"]; oManifest["sap.ui.generic.app"]["pages"] = mergerUtil.transformPagesToMapStructure(pages); var oPageStructure; if (sParentComponent === GLOBAL_MANIFEST_CHANGE_COMPONENT) { oPageStructure = oManifest["sap.ui.generic.app"]; } else { oPageStructure = mergerUtil.iterateAndFind(oManifest["sap.ui.generic.app"], sParentEntitySet, sParentComponent); } var oPropertyChange = oChangeContent.entityPropertyChange; if (typeof oPropertyChange.propertyValue !== "object" || oPropertyChange.propertyValue === null || Array.isArray(oPropertyChange.propertyValue)) { var aPropertyPath = oPropertyChange.propertyPath.split("/"); ObjectPath.set(aPropertyPath, oPropertyChange.propertyValue, oPageStructure); } else { var aPropertyKeys = Object.keys(oPropertyChange.propertyValue); aPropertyKeys.forEach(function (sCurrentKey) { var aPropertyPath = oPropertyChange.propertyPath.split("/"); aPropertyPath.push(sCurrentKey); var vVal = ObjectPath.get(aPropertyPath, oPageStructure); if (vVal && typeof vVal === "object") { var oPropertyPathContent = ObjectPath.create(aPropertyPath, oPageStructure); Object.assign(oPropertyPathContent, oPropertyChange.propertyValue[sCurrentKey]); } else { ObjectPath.set(aPropertyPath, oPropertyChange.propertyValue[sCurrentKey], oPageStructure); } }); } return oManifest; } }; var _exports$1 = {}; function applyChange$1(manifest, change) { const changeContent = change.getContent(); const pageId = changeContent?.page; const propertyChange = changeContent?.entityPropertyChange; if (propertyChange?.operation !== "UPSERT" || !propertyChange?.propertyPath || propertyChange?.propertyValue === undefined || propertyChange?.propertyPath.startsWith("/")) { Log.error("Change content is not a valid"); return manifest; } return changeConfiguration$1(manifest, pageId, propertyChange.propertyPath, propertyChange.propertyValue); } _exports$1.applyChange = applyChange$1; function changeConfiguration$1(manifest, pageId, path, value, lateChange, appComponent) { const pageSAPfe = "sap.fe"; let propertyPath = retrievePropertyPath(path); let pageSettings; if (pageId === pageSAPfe) { propertyPath = [pageSAPfe, ...propertyPath]; pageSettings = manifest; } else { pageSettings = getPageSettings(manifest, pageId); } if (pageSettings) { manageSpecificFormat(propertyPath, pageSettings); ObjectPath.set(propertyPath, value, pageSettings); if (lateChange && appComponent) { appComponent.pageConfigurationChanges[pageId] = appComponent.pageConfigurationChanges[pageId] || []; appComponent.pageConfigurationChanges[pageId].push(path); } } else { Log.error(`No Fiori elements page with ID ${pageId} found in routing targets.`); } return manifest; } _exports$1.changeConfiguration = changeConfiguration$1; function manageSpecificFormat(propertyPath, pageSettings) { if (propertyPath.length > 1) { for (let i = 0; i < propertyPath.length - 1; i++) { if (typeof ObjectPath.get(propertyPath.slice(0, i + 1), pageSettings) !== "object") { ObjectPath.set(propertyPath.slice(0, i + 1), {}, pageSettings); } } } } function retrievePropertyPath(path) { let propertyPath = path.split("/"); if (propertyPath[0] === "controlConfiguration") { let annotationPath = ""; for (let i = 1; i < propertyPath.length; i++) { annotationPath += (i > 1 ? "/" : "") + propertyPath[i]; if (annotationPath.includes("@")) { propertyPath = ["controlConfiguration", annotationPath].concat(propertyPath.slice(i + 1)); break; } } } return propertyPath; } function getPageSettings(manifest, pageId) { let pageSettings; const targets = manifest["sap.ui5"]?.routing?.targets ?? ({}); for (const p in targets) { if (targets[p].id === pageId && targets[p].name.startsWith("sap.fe.")) { pageSettings = targets[p].options?.settings ?? ({}); break; } } return pageSettings; } function applyPageConfigurationChanges(manifest, viewData, appComponent, pageId) { viewData = viewData ?? ({}); const pageChanges = appComponent.pageConfigurationChanges[pageId] || []; for (const path of pageChanges) { const propertyPath = retrievePropertyPath(path); const manifestValue = ObjectPath.g