@microsoft/applicationinsights-core-js
Version:
Microsoft Application Insights Core Javascript SDK
235 lines (233 loc) • 10.8 kB
JavaScript
/*
* 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