UNPKG

@microsoft/applicationinsights-core-js

Version:

Microsoft Application Insights Core Javascript SDK

235 lines (233 loc) • 10.8 kB
/* * Application Insights JavaScript SDK - Core, 3.3.9 * Copyright (c) Microsoft and contributors. All rights reserved. */ import { arrForEach, arrIndexOf, dumpObj, isArray, objDefine, objDefineProp, objForEachKey, objGetOwnPropertyDescriptor } from "@nevware21/ts-utils"; import { UNDEFINED_VALUE } from "../JavaScriptSDK/InternalConstants"; import { _DYN_APPLY, _DYN_LOGGER, _DYN_PUSH, _DYN_SPLICE, _DYN_THROW_INTERNAL } from "../__DynamicConstants"; import { CFG_HANDLER_LINK, _canMakeDynamic, blockDynamicConversion, throwInvalidAccess } from "./DynamicSupport"; var arrayMethodsToPatch = [ "push", "pop", "shift", "unshift", "splice" ]; export var _throwDynamicError = function (logger, name, desc, e) { logger && logger[_DYN_THROW_INTERNAL /* @min:%2ethrowInternal */](3 /* eLoggingSeverity.DEBUG */, 108 /* _eInternalMessageId.DynamicConfigException */, "".concat(desc, " [").concat(name, "] failed - ") + dumpObj(e)); }; function _patchArray(state, target, name) { if (isArray(target)) { // Monkey Patch the methods that might change the array arrForEach(arrayMethodsToPatch, function (method) { var orgMethod = target[method]; target[method] = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var result = orgMethod[_DYN_APPLY /* @min:%2eapply */](this, args); // items may be added, removed or moved so need to make some new dynamic properties _makeDynamicObject(state, target, name, "Patching"); return result; }; }); } } function _getOwnPropGetter(target, name) { var propDesc = objGetOwnPropertyDescriptor(target, name); return propDesc && propDesc.get; } function _createDynamicProperty(state, theConfig, name, value) { // Does not appear to be dynamic so lets make it so var detail = { n: name, h: [], trk: function (handler) { if (handler && handler.fn) { if (arrIndexOf(detail.h, handler) === -1) { // Add this handler to the collection that should be notified when the value changes detail.h[_DYN_PUSH /* @min:%2epush */](handler); } state.trk(handler, detail); } }, clr: function (handler) { var idx = arrIndexOf(detail.h, handler); if (idx !== -1) { detail.h[_DYN_SPLICE /* @min:%2esplice */](idx, 1); } } }; // Flag to optimize lookup response time by avoiding additional function calls var checkDynamic = true; var isObjectOrArray = false; function _getProperty() { if (checkDynamic) { isObjectOrArray = isObjectOrArray || _canMakeDynamic(_getProperty, state, value); // Make sure that if it's an object that we make it dynamic if (value && !value[CFG_HANDLER_LINK] && isObjectOrArray) { // It doesn't look like it's already dynamic so lets make sure it's converted the object into a dynamic Config as well value = _makeDynamicObject(state, value, name, "Converting"); } // If it needed to be converted it now has been checkDynamic = false; } // If there is an active handler then add it to the tracking set of handlers var activeHandler = state.act; if (activeHandler) { detail.trk(activeHandler); } return value; } // Tag this getter as our dynamic property and provide shortcut for notifying a change _getProperty[state.prop] = { chng: function () { state.add(detail); } }; function _setProperty(newValue) { if (value !== newValue) { if (!!_getProperty[state.ro] && !state.upd) { // field is marked as readonly so return false throwInvalidAccess("[" + name + "] is read-only:" + dumpObj(theConfig)); } if (checkDynamic) { isObjectOrArray = isObjectOrArray || _canMakeDynamic(_getProperty, state, value); checkDynamic = false; } // The value must be a plain object or an array to enforce the reference (in-place updates) var isReferenced = isObjectOrArray && _getProperty[state.rf]; if (isObjectOrArray) { // We are about to replace a plain object or an array if (isReferenced) { // Reassign the properties from the current value to the same properties from the newValue // This will set properties not in the newValue to undefined objForEachKey(value, function (key) { value[key] = newValue ? newValue[key] : UNDEFINED_VALUE; }); // Now assign / re-assign value with all of the keys from newValue try { objForEachKey(newValue, function (key, theValue) { _setDynamicProperty(state, value, key, theValue); }); // Now drop newValue so when we assign value later it keeps the existing reference newValue = value; } catch (e) { // Unable to convert to dynamic property so just leave as non-dynamic _throwDynamicError((state.hdlr || {})[_DYN_LOGGER /* @min:%2elogger */], name, "Assigning", e); // Mark as not an object or array so we don't try and do this again isObjectOrArray = false; } } else if (value && value[CFG_HANDLER_LINK]) { // As we are replacing the value, if it's already dynamic then we need to notify the listeners // for every property it has already objForEachKey(value, function (key) { // Check if the value is dynamic var getter = _getOwnPropGetter(value, key); if (getter) { // And if it is tell it's listeners that the value has changed var valueState = getter[state.prop]; valueState && valueState.chng(); } }); } } if (newValue !== value) { var newIsObjectOrArray = newValue && _canMakeDynamic(_getProperty, state, newValue); if (!isReferenced && newIsObjectOrArray) { // As the newValue is an object/array lets preemptively make it dynamic newValue = _makeDynamicObject(state, newValue, name, "Converting"); } // Now assign the internal "value" to the newValue value = newValue; isObjectOrArray = newIsObjectOrArray; } // Cause any listeners to be scheduled for notification state.add(detail); } } objDefine(theConfig, detail.n, { g: _getProperty, s: _setProperty }); } export function _setDynamicProperty(state, target, name, value) { if (target) { // To be a dynamic property it needs to have a get function var getter = _getOwnPropGetter(target, name); var isDynamic = getter && !!getter[state.prop]; if (!isDynamic) { _createDynamicProperty(state, target, name, value); } else { // Looks like it's already dynamic just assign the new value target[name] = value; } } return target; } export function _setDynamicPropertyState(state, target, name, flags) { if (target) { // To be a dynamic property it needs to have a get function var getter = _getOwnPropGetter(target, name); var isDynamic = getter && !!getter[state.prop]; var inPlace = flags && flags[0 /* _eSetDynamicPropertyFlags.inPlace */]; var rdOnly = flags && flags[1 /* _eSetDynamicPropertyFlags.readOnly */]; var blkProp = flags && flags[2 /* _eSetDynamicPropertyFlags.blockDynamicProperty */]; if (!isDynamic) { if (blkProp) { try { // Attempt to mark the target as blocked from conversion blockDynamicConversion(target); } catch (e) { _throwDynamicError((state.hdlr || {})[_DYN_LOGGER /* @min:%2elogger */], name, "Blocking", e); } } try { // Make sure it's dynamic so that we can tag the property as per the state _setDynamicProperty(state, target, name, target[name]); getter = _getOwnPropGetter(target, name); } catch (e) { // Unable to convert to dynamic property so just leave as non-dynamic _throwDynamicError((state.hdlr || {})[_DYN_LOGGER /* @min:%2elogger */], name, "State", e); } } // Assign the optional flags if true if (inPlace) { getter[state.rf] = inPlace; } if (rdOnly) { getter[state.ro] = rdOnly; } if (blkProp) { getter[state.blkVal] = true; } } return target; } export function _makeDynamicObject(state, target, name, desc) { try { // Assign target with new value properties (converting into dynamic properties in the process) objForEachKey(target, function (key, value) { // Assign and/or make the property dynamic _setDynamicProperty(state, target, key, value); }); if (!target[CFG_HANDLER_LINK]) { // Link the config back to the dynamic config details objDefineProp(target, CFG_HANDLER_LINK, { get: function () { return state.hdlr; } }); _patchArray(state, target, name); } } catch (e) { // Unable to convert to dynamic property so just leave as non-dynamic _throwDynamicError((state.hdlr || {})[_DYN_LOGGER /* @min:%2elogger */], name, desc, e); } return target; } //# sourceMappingURL=DynamicProperty.js.map