@datadog/browser-core
Advanced tools
Comparing version 4.6.1 to 4.7.0
@@ -9,3 +9,3 @@ "use strict"; | ||
var publicApi = (0, utils_1.assign)({ | ||
version: "4.6.1", | ||
version: "4.7.0", | ||
// This API method is intentionally not monitored, since the only thing executed is the | ||
@@ -12,0 +12,0 @@ // user-provided 'callback'. All SDK usages executed in the callback should be monitored, and |
@@ -28,5 +28,5 @@ "use strict"; | ||
var parameters = "ddsource=".concat(source || 'browser') + | ||
"&ddtags=".concat(encodeURIComponent(["sdk_version:".concat("4.6.1")].concat(tags).join(','))) + | ||
"&ddtags=".concat(encodeURIComponent(["sdk_version:".concat("4.7.0")].concat(tags).join(','))) + | ||
"&dd-api-key=".concat(clientToken) + | ||
"&dd-evp-origin-version=".concat(encodeURIComponent("4.6.1")) + | ||
"&dd-evp-origin-version=".concat(encodeURIComponent("4.7.0")) + | ||
'&dd-evp-origin=browser' + | ||
@@ -33,0 +33,0 @@ "&dd-request-id=".concat((0, utils_1.generateUUID)()); |
@@ -19,14 +19,2 @@ "use strict"; | ||
function computeEndpointBuilders(initConfiguration, tags) { | ||
if ("release" === 'e2e-test') { | ||
var e2eEndpointBuilder = function (placeholder) { return ({ | ||
build: function () { return placeholder; }, | ||
buildIntakeUrl: function () { return placeholder; }, | ||
}); }; | ||
return { | ||
logsEndpointBuilder: e2eEndpointBuilder('<<< E2E LOGS ENDPOINT >>>'), | ||
rumEndpointBuilder: e2eEndpointBuilder('<<< E2E RUM ENDPOINT >>>'), | ||
sessionReplayEndpointBuilder: e2eEndpointBuilder('<<< E2E SESSION REPLAY ENDPOINT >>>'), | ||
internalMonitoringEndpointBuilder: e2eEndpointBuilder('<<< E2E INTERNAL MONITORING ENDPOINT >>>'), | ||
}; | ||
} | ||
var endpointBuilders = { | ||
@@ -33,0 +21,0 @@ logsEndpointBuilder: (0, endpointBuilder_1.createEndpointBuilder)(initConfiguration, 'logs', tags), |
@@ -35,3 +35,3 @@ "use strict"; | ||
service: 'browser-sdk', | ||
version: "4.6.1", | ||
version: "4.7.0", | ||
_dd: { | ||
@@ -38,0 +38,0 @@ event_type: 'internal_telemetry', |
@@ -17,3 +17,3 @@ export { Configuration, InitConfiguration, buildCookieOptions, validateAndBuildConfiguration, DefaultPrivacyLevel, EndpointBuilder, isExperimentalFeatureEnabled, updateExperimentalFeatures, resetExperimentalFeatures, } from './domain/configuration'; | ||
export * from './tools/browserDetection'; | ||
export { instrumentMethod, instrumentMethodAndCallOriginal } from './tools/instrumentMethod'; | ||
export { instrumentMethod, instrumentMethodAndCallOriginal, instrumentSetter } from './tools/instrumentMethod'; | ||
export { ErrorSource, ErrorHandling, formatUnknownError, createHandlingStack, RawError, toStackTraceString, getFileFromStackTraceString, } from './tools/error'; | ||
@@ -20,0 +20,0 @@ export { Context, ContextArray, ContextValue } from './tools/context'; |
@@ -17,4 +17,4 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.limitModification = exports.createContextManager = exports.catchUserErrors = exports.BoundedBuffer = exports.ConsoleApiName = exports.initConsoleObservable = exports.initFetchObservable = exports.initXhrObservable = exports.COOKIE_ACCESS_DELAY = exports.deleteCookie = exports.setCookie = exports.getCookie = exports.areCookiesAuthorized = exports.getFileFromStackTraceString = exports.toStackTraceString = exports.createHandlingStack = exports.formatUnknownError = exports.ErrorSource = exports.instrumentMethodAndCallOriginal = exports.instrumentMethod = exports.startBatchWithReplica = exports.getEventBridge = exports.canUseEventBridge = exports.Batch = exports.HttpRequest = exports.SESSION_TIME_OUT_DELAY = exports.stopSessionManager = exports.startSessionManager = exports.Observable = exports.setDebugMode = exports.resetInternalMonitoring = exports.startFakeInternalMonitoring = exports.addMonitoringError = exports.addMonitoringMessage = exports.callMonitored = exports.monitor = exports.monitored = exports.startInternalMonitoring = exports.RawReportType = exports.initReportObservable = exports.makePublicApi = exports.defineGlobal = exports.computeStackTrace = exports.trackRuntimeError = exports.resetExperimentalFeatures = exports.updateExperimentalFeatures = exports.isExperimentalFeatureEnabled = exports.DefaultPrivacyLevel = exports.validateAndBuildConfiguration = exports.buildCookieOptions = void 0; | ||
exports.SESSION_COOKIE_NAME = exports.CLEAR_OLD_CONTEXTS_INTERVAL = exports.ContextHistory = void 0; | ||
exports.createContextManager = exports.catchUserErrors = exports.BoundedBuffer = exports.ConsoleApiName = exports.initConsoleObservable = exports.initFetchObservable = exports.initXhrObservable = exports.COOKIE_ACCESS_DELAY = exports.deleteCookie = exports.setCookie = exports.getCookie = exports.areCookiesAuthorized = exports.getFileFromStackTraceString = exports.toStackTraceString = exports.createHandlingStack = exports.formatUnknownError = exports.ErrorSource = exports.instrumentSetter = exports.instrumentMethodAndCallOriginal = exports.instrumentMethod = exports.startBatchWithReplica = exports.getEventBridge = exports.canUseEventBridge = exports.Batch = exports.HttpRequest = exports.SESSION_TIME_OUT_DELAY = exports.stopSessionManager = exports.startSessionManager = exports.Observable = exports.setDebugMode = exports.resetInternalMonitoring = exports.startFakeInternalMonitoring = exports.addMonitoringError = exports.addMonitoringMessage = exports.callMonitored = exports.monitor = exports.monitored = exports.startInternalMonitoring = exports.RawReportType = exports.initReportObservable = exports.makePublicApi = exports.defineGlobal = exports.computeStackTrace = exports.trackRuntimeError = exports.resetExperimentalFeatures = exports.updateExperimentalFeatures = exports.isExperimentalFeatureEnabled = exports.DefaultPrivacyLevel = exports.validateAndBuildConfiguration = exports.buildCookieOptions = void 0; | ||
exports.SESSION_COOKIE_NAME = exports.CLEAR_OLD_CONTEXTS_INTERVAL = exports.ContextHistory = exports.limitModification = void 0; | ||
var configuration_1 = require("./domain/configuration"); | ||
@@ -70,2 +70,3 @@ Object.defineProperty(exports, "buildCookieOptions", { enumerable: true, get: function () { return configuration_1.buildCookieOptions; } }); | ||
Object.defineProperty(exports, "instrumentMethodAndCallOriginal", { enumerable: true, get: function () { return instrumentMethod_1.instrumentMethodAndCallOriginal; } }); | ||
Object.defineProperty(exports, "instrumentSetter", { enumerable: true, get: function () { return instrumentMethod_1.instrumentSetter; } }); | ||
var error_1 = require("./tools/error"); | ||
@@ -72,0 +73,0 @@ Object.defineProperty(exports, "ErrorSource", { enumerable: true, get: function () { return error_1.ErrorSource; } }); |
@@ -0,1 +1,2 @@ | ||
import { noop } from './utils'; | ||
export declare function instrumentMethod<OBJECT extends { | ||
@@ -9,6 +10,11 @@ [key: string]: any; | ||
}, METHOD extends keyof OBJECT>(object: OBJECT, method: METHOD, { before, after, }: { | ||
before?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => ReturnType<OBJECT[METHOD]>; | ||
after?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => ReturnType<OBJECT[METHOD]>; | ||
before?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => void; | ||
after?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => void; | ||
}): { | ||
stop: () => void; | ||
}; | ||
export declare function instrumentSetter<OBJECT extends { | ||
[key: string]: any; | ||
}, PROPERTY extends keyof OBJECT>(object: OBJECT, property: PROPERTY, after: (thisObject: OBJECT, value: OBJECT[PROPERTY]) => void): { | ||
stop: typeof noop; | ||
}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.instrumentMethodAndCallOriginal = exports.instrumentMethod = void 0; | ||
exports.instrumentSetter = exports.instrumentMethodAndCallOriginal = exports.instrumentMethod = void 0; | ||
var internalMonitoring_1 = require("../domain/internalMonitoring"); | ||
var utils_1 = require("./utils"); | ||
function instrumentMethod(object, method, instrumentationFactory) { | ||
@@ -47,2 +48,33 @@ var original = object[method]; | ||
exports.instrumentMethodAndCallOriginal = instrumentMethodAndCallOriginal; | ||
function instrumentSetter(object, property, after) { | ||
var originalDescriptor = Object.getOwnPropertyDescriptor(object, property); | ||
if (!originalDescriptor || !originalDescriptor.set || !originalDescriptor.configurable) { | ||
return { stop: utils_1.noop }; | ||
} | ||
var instrumentation = function (thisObject, value) { | ||
// put hooked setter into event loop to avoid of set latency | ||
setTimeout((0, internalMonitoring_1.monitor)(function () { | ||
after(thisObject, value); | ||
}), 0); | ||
}; | ||
var instrumentationWrapper = function (value) { | ||
originalDescriptor.set.call(this, value); | ||
instrumentation(this, value); | ||
}; | ||
Object.defineProperty(object, property, { | ||
set: instrumentationWrapper, | ||
}); | ||
return { | ||
stop: function () { | ||
var _a; | ||
if (((_a = Object.getOwnPropertyDescriptor(object, property)) === null || _a === void 0 ? void 0 : _a.set) === instrumentationWrapper) { | ||
Object.defineProperty(object, property, originalDescriptor); | ||
} | ||
else { | ||
instrumentation = utils_1.noop; | ||
} | ||
}, | ||
}; | ||
} | ||
exports.instrumentSetter = instrumentSetter; | ||
//# sourceMappingURL=instrumentMethod.js.map |
@@ -6,3 +6,3 @@ import { setDebugMode } from '../domain/internalMonitoring'; | ||
var publicApi = assign({ | ||
version: "4.6.1", | ||
version: "4.7.0", | ||
// This API method is intentionally not monitored, since the only thing executed is the | ||
@@ -9,0 +9,0 @@ // user-provided 'callback'. All SDK usages executed in the callback should be monitored, and |
@@ -25,5 +25,5 @@ import { timeStampNow } from '../../tools/timeUtils'; | ||
var parameters = "ddsource=".concat(source || 'browser') + | ||
"&ddtags=".concat(encodeURIComponent(["sdk_version:".concat("4.6.1")].concat(tags).join(','))) + | ||
"&ddtags=".concat(encodeURIComponent(["sdk_version:".concat("4.7.0")].concat(tags).join(','))) + | ||
"&dd-api-key=".concat(clientToken) + | ||
"&dd-evp-origin-version=".concat(encodeURIComponent("4.6.1")) + | ||
"&dd-evp-origin-version=".concat(encodeURIComponent("4.7.0")) + | ||
'&dd-evp-origin=browser' + | ||
@@ -30,0 +30,0 @@ "&dd-request-id=".concat(generateUUID()); |
@@ -15,14 +15,2 @@ import { assign, objectValues } from '../../tools/utils'; | ||
function computeEndpointBuilders(initConfiguration, tags) { | ||
if ("release" === 'e2e-test') { | ||
var e2eEndpointBuilder = function (placeholder) { return ({ | ||
build: function () { return placeholder; }, | ||
buildIntakeUrl: function () { return placeholder; }, | ||
}); }; | ||
return { | ||
logsEndpointBuilder: e2eEndpointBuilder('<<< E2E LOGS ENDPOINT >>>'), | ||
rumEndpointBuilder: e2eEndpointBuilder('<<< E2E RUM ENDPOINT >>>'), | ||
sessionReplayEndpointBuilder: e2eEndpointBuilder('<<< E2E SESSION REPLAY ENDPOINT >>>'), | ||
internalMonitoringEndpointBuilder: e2eEndpointBuilder('<<< E2E INTERNAL MONITORING ENDPOINT >>>'), | ||
}; | ||
} | ||
var endpointBuilders = { | ||
@@ -29,0 +17,0 @@ logsEndpointBuilder: createEndpointBuilder(initConfiguration, 'logs', tags), |
@@ -32,3 +32,3 @@ import { display } from '../../tools/display'; | ||
service: 'browser-sdk', | ||
version: "4.6.1", | ||
version: "4.7.0", | ||
_dd: { | ||
@@ -35,0 +35,0 @@ event_type: 'internal_telemetry', |
@@ -17,3 +17,3 @@ export { Configuration, InitConfiguration, buildCookieOptions, validateAndBuildConfiguration, DefaultPrivacyLevel, EndpointBuilder, isExperimentalFeatureEnabled, updateExperimentalFeatures, resetExperimentalFeatures, } from './domain/configuration'; | ||
export * from './tools/browserDetection'; | ||
export { instrumentMethod, instrumentMethodAndCallOriginal } from './tools/instrumentMethod'; | ||
export { instrumentMethod, instrumentMethodAndCallOriginal, instrumentSetter } from './tools/instrumentMethod'; | ||
export { ErrorSource, ErrorHandling, formatUnknownError, createHandlingStack, RawError, toStackTraceString, getFileFromStackTraceString, } from './tools/error'; | ||
@@ -20,0 +20,0 @@ export { Context, ContextArray, ContextValue } from './tools/context'; |
@@ -20,3 +20,3 @@ export { buildCookieOptions, validateAndBuildConfiguration, DefaultPrivacyLevel, isExperimentalFeatureEnabled, updateExperimentalFeatures, resetExperimentalFeatures, } from './domain/configuration'; | ||
export * from './tools/browserDetection'; | ||
export { instrumentMethod, instrumentMethodAndCallOriginal } from './tools/instrumentMethod'; | ||
export { instrumentMethod, instrumentMethodAndCallOriginal, instrumentSetter } from './tools/instrumentMethod'; | ||
export { ErrorSource, formatUnknownError, createHandlingStack, toStackTraceString, getFileFromStackTraceString, } from './tools/error'; | ||
@@ -23,0 +23,0 @@ export { areCookiesAuthorized, getCookie, setCookie, deleteCookie, COOKIE_ACCESS_DELAY } from './browser/cookie'; |
@@ -0,1 +1,2 @@ | ||
import { noop } from './utils'; | ||
export declare function instrumentMethod<OBJECT extends { | ||
@@ -9,6 +10,11 @@ [key: string]: any; | ||
}, METHOD extends keyof OBJECT>(object: OBJECT, method: METHOD, { before, after, }: { | ||
before?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => ReturnType<OBJECT[METHOD]>; | ||
after?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => ReturnType<OBJECT[METHOD]>; | ||
before?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => void; | ||
after?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => void; | ||
}): { | ||
stop: () => void; | ||
}; | ||
export declare function instrumentSetter<OBJECT extends { | ||
[key: string]: any; | ||
}, PROPERTY extends keyof OBJECT>(object: OBJECT, property: PROPERTY, after: (thisObject: OBJECT, value: OBJECT[PROPERTY]) => void): { | ||
stop: typeof noop; | ||
}; |
@@ -1,2 +0,3 @@ | ||
import { callMonitored } from '../domain/internalMonitoring'; | ||
import { callMonitored, monitor } from '../domain/internalMonitoring'; | ||
import { noop } from './utils'; | ||
export function instrumentMethod(object, method, instrumentationFactory) { | ||
@@ -42,2 +43,32 @@ var original = object[method]; | ||
} | ||
export function instrumentSetter(object, property, after) { | ||
var originalDescriptor = Object.getOwnPropertyDescriptor(object, property); | ||
if (!originalDescriptor || !originalDescriptor.set || !originalDescriptor.configurable) { | ||
return { stop: noop }; | ||
} | ||
var instrumentation = function (thisObject, value) { | ||
// put hooked setter into event loop to avoid of set latency | ||
setTimeout(monitor(function () { | ||
after(thisObject, value); | ||
}), 0); | ||
}; | ||
var instrumentationWrapper = function (value) { | ||
originalDescriptor.set.call(this, value); | ||
instrumentation(this, value); | ||
}; | ||
Object.defineProperty(object, property, { | ||
set: instrumentationWrapper, | ||
}); | ||
return { | ||
stop: function () { | ||
var _a; | ||
if (((_a = Object.getOwnPropertyDescriptor(object, property)) === null || _a === void 0 ? void 0 : _a.set) === instrumentationWrapper) { | ||
Object.defineProperty(object, property, originalDescriptor); | ||
} | ||
else { | ||
instrumentation = noop; | ||
} | ||
}, | ||
}; | ||
} | ||
//# sourceMappingURL=instrumentMethod.js.map |
{ | ||
"name": "@datadog/browser-core", | ||
"version": "4.6.1", | ||
"version": "4.7.0", | ||
"license": "Apache-2.0", | ||
@@ -24,3 +24,3 @@ "main": "cjs/index.js", | ||
}, | ||
"gitHead": "69979d64af058d2fdc44b87769760b66290f9a45" | ||
"gitHead": "3e5bc9cf4a264d90bc39ed0aac257e86f2a096e8" | ||
} |
@@ -22,21 +22,2 @@ import type { BuildEnvWindow } from '../../../test/specHelper' | ||
describe('endpoint overload', () => { | ||
it('should be available for e2e-test build mode', () => { | ||
;(window as unknown as BuildEnvWindow).__BUILD_ENV__BUILD_MODE__ = 'e2e-test' | ||
const configuration = computeTransportConfiguration({ clientToken }) | ||
expect(configuration.rumEndpointBuilder.build()).toEqual('<<< E2E RUM ENDPOINT >>>') | ||
expect(configuration.logsEndpointBuilder.build()).toEqual('<<< E2E LOGS ENDPOINT >>>') | ||
expect(configuration.internalMonitoringEndpointBuilder?.build()).toEqual( | ||
'<<< E2E INTERNAL MONITORING ENDPOINT >>>' | ||
) | ||
expect(configuration.sessionReplayEndpointBuilder.build()).toEqual('<<< E2E SESSION REPLAY ENDPOINT >>>') | ||
expect(configuration.isIntakeUrl('<<< E2E RUM ENDPOINT >>>')).toBe(true) | ||
expect(configuration.isIntakeUrl('<<< E2E LOGS ENDPOINT >>>')).toBe(true) | ||
expect(configuration.isIntakeUrl('<<< E2E SESSION REPLAY ENDPOINT >>>')).toBe(true) | ||
expect(configuration.isIntakeUrl('<<< E2E INTERNAL MONITORING ENDPOINT >>>')).toBe(true) | ||
}) | ||
}) | ||
describe('site', () => { | ||
@@ -43,0 +24,0 @@ it('should use US site by default', () => { |
@@ -7,5 +7,2 @@ import { assign, objectValues } from '../../tools/utils' | ||
// replaced at build time | ||
declare const __BUILD_ENV__BUILD_MODE__: string | ||
export interface TransportConfiguration { | ||
@@ -45,16 +42,2 @@ logsEndpointBuilder: EndpointBuilder | ||
function computeEndpointBuilders(initConfiguration: InitConfiguration, tags: string[]) { | ||
if (__BUILD_ENV__BUILD_MODE__ === 'e2e-test') { | ||
const e2eEndpointBuilder = (placeholder: string) => ({ | ||
build: () => placeholder, | ||
buildIntakeUrl: () => placeholder, | ||
}) | ||
return { | ||
logsEndpointBuilder: e2eEndpointBuilder('<<< E2E LOGS ENDPOINT >>>'), | ||
rumEndpointBuilder: e2eEndpointBuilder('<<< E2E RUM ENDPOINT >>>'), | ||
sessionReplayEndpointBuilder: e2eEndpointBuilder('<<< E2E SESSION REPLAY ENDPOINT >>>'), | ||
internalMonitoringEndpointBuilder: e2eEndpointBuilder('<<< E2E INTERNAL MONITORING ENDPOINT >>>'), | ||
} | ||
} | ||
const endpointBuilders = { | ||
@@ -61,0 +44,0 @@ logsEndpointBuilder: createEndpointBuilder(initConfiguration, 'logs', tags), |
@@ -47,3 +47,3 @@ export { | ||
export * from './tools/browserDetection' | ||
export { instrumentMethod, instrumentMethodAndCallOriginal } from './tools/instrumentMethod' | ||
export { instrumentMethod, instrumentMethodAndCallOriginal, instrumentSetter } from './tools/instrumentMethod' | ||
export { | ||
@@ -50,0 +50,0 @@ ErrorSource, |
@@ -1,2 +0,5 @@ | ||
import { instrumentMethod } from './instrumentMethod' | ||
import type { Clock } from '../../test/specHelper' | ||
import { mockClock } from '../../test/specHelper' | ||
import { instrumentMethod, instrumentSetter } from './instrumentMethod' | ||
import { noop } from './utils' | ||
@@ -107,1 +110,153 @@ describe('instrumentMethod', () => { | ||
}) | ||
describe('instrumentSetter', () => { | ||
let clock: Clock | ||
beforeEach(() => { | ||
clock = mockClock() | ||
}) | ||
afterEach(() => { | ||
clock.cleanup() | ||
}) | ||
it('replaces the original setter', () => { | ||
const originalSetter = () => { | ||
// do nothing particular, only used to test if this setter gets replaced | ||
} | ||
const object = {} as { foo: number } | ||
Object.defineProperty(object, 'foo', { set: originalSetter, configurable: true }) | ||
instrumentSetter(object, 'foo', noop) | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
expect(Object.getOwnPropertyDescriptor(object, 'foo')!.set).not.toBe(originalSetter) | ||
}) | ||
it('skips instrumentation if there is no original setter', () => { | ||
const object = { foo: 1 } | ||
instrumentSetter(object, 'foo', noop) | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
expect(Object.getOwnPropertyDescriptor(object, 'foo')!.set).toBeUndefined() | ||
}) | ||
it('skips instrumentation if the descriptor is not configurable', () => { | ||
const originalSetter = () => { | ||
// do nothing particular, only used to test if this setter gets replaced | ||
} | ||
const object = {} as { foo: number } | ||
Object.defineProperty(object, 'foo', { set: originalSetter, configurable: false }) | ||
instrumentSetter(object, 'foo', noop) | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
expect(Object.getOwnPropertyDescriptor(object, 'foo')!.set).toBe(originalSetter) | ||
}) | ||
it('calls the original setter', () => { | ||
const originalSetterSpy = jasmine.createSpy() | ||
const object = {} as { foo: number } | ||
Object.defineProperty(object, 'foo', { set: originalSetterSpy, configurable: true }) | ||
instrumentSetter(object, 'foo', noop) | ||
object.foo = 1 | ||
expect(originalSetterSpy).toHaveBeenCalledOnceWith(1) | ||
}) | ||
it('calls the instrumentation asynchronously', () => { | ||
const instrumentationSetterSpy = jasmine.createSpy() | ||
const object = {} as { foo: number } | ||
Object.defineProperty(object, 'foo', { set: noop, configurable: true }) | ||
instrumentSetter(object, 'foo', instrumentationSetterSpy) | ||
object.foo = 1 | ||
expect(instrumentationSetterSpy).not.toHaveBeenCalled() | ||
clock.tick(0) | ||
expect(instrumentationSetterSpy).toHaveBeenCalledOnceWith(object, 1) | ||
}) | ||
it('allows other instrumentations from third parties', () => { | ||
const object = {} as { foo: number } | ||
Object.defineProperty(object, 'foo', { set: noop, configurable: true }) | ||
const instrumentationSetterSpy = jasmine.createSpy() | ||
instrumentSetter(object, 'foo', instrumentationSetterSpy) | ||
const thirdPartyInstrumentationSpy = thirdPartyInstrumentation(object) | ||
object.foo = 2 | ||
expect(thirdPartyInstrumentationSpy).toHaveBeenCalledOnceWith(2) | ||
clock.tick(0) | ||
expect(instrumentationSetterSpy).toHaveBeenCalledOnceWith(object, 2) | ||
}) | ||
describe('stop()', () => { | ||
it('restores the original behavior', () => { | ||
const object = {} as { foo: number } | ||
const originalSetter = () => { | ||
// do nothing particular, only used to test if this setter gets replaced | ||
} | ||
Object.defineProperty(object, 'foo', { set: originalSetter, configurable: true }) | ||
const { stop } = instrumentSetter(object, 'foo', noop) | ||
stop() | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
expect(Object.getOwnPropertyDescriptor(object, 'foo')!.set).toBe(originalSetter) | ||
}) | ||
it('does not call the instrumentation anymore', () => { | ||
const object = {} as { foo: number } | ||
Object.defineProperty(object, 'foo', { set: noop, configurable: true }) | ||
const instrumentationSetterSpy = jasmine.createSpy() | ||
const { stop } = instrumentSetter(object, 'foo', instrumentationSetterSpy) | ||
stop() | ||
object.foo = 2 | ||
expect(instrumentationSetterSpy).not.toHaveBeenCalled() | ||
}) | ||
describe('when the method has been instrumented by a third party', () => { | ||
it('should not break the third party instrumentation', () => { | ||
const object = {} as { foo: number } | ||
Object.defineProperty(object, 'foo', { set: noop, configurable: true }) | ||
const { stop } = instrumentSetter(object, 'foo', noop) | ||
const thirdPartyInstrumentationSpy = thirdPartyInstrumentation(object) | ||
stop() | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
expect(Object.getOwnPropertyDescriptor(object, 'foo')!.set).toBe(thirdPartyInstrumentationSpy) | ||
}) | ||
it('does not call the instrumentation', () => { | ||
const object = {} as { foo: number } | ||
Object.defineProperty(object, 'foo', { set: noop, configurable: true }) | ||
const instrumentationSetterSpy = jasmine.createSpy() | ||
const { stop } = instrumentSetter(object, 'foo', noop) | ||
thirdPartyInstrumentation(object) | ||
stop() | ||
object.foo = 2 | ||
expect(instrumentationSetterSpy).not.toHaveBeenCalled() | ||
}) | ||
}) | ||
}) | ||
function thirdPartyInstrumentation(object: { foo: number }) { | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
const originalSetter = Object.getOwnPropertyDescriptor(object, 'foo')!.set | ||
const thirdPartyInstrumentationSpy = jasmine.createSpy().and.callFake(function (this: any, value) { | ||
if (originalSetter) { | ||
originalSetter.call(this, value) | ||
} | ||
}) | ||
Object.defineProperty(object, 'foo', { set: thirdPartyInstrumentationSpy }) | ||
return thirdPartyInstrumentationSpy | ||
} | ||
}) |
@@ -1,2 +0,3 @@ | ||
import { callMonitored } from '../domain/internalMonitoring' | ||
import { callMonitored, monitor } from '../domain/internalMonitoring' | ||
import { noop } from './utils' | ||
@@ -38,4 +39,4 @@ export function instrumentMethod<OBJECT extends { [key: string]: any }, METHOD extends keyof OBJECT>( | ||
}: { | ||
before?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => ReturnType<OBJECT[METHOD]> | ||
after?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => ReturnType<OBJECT[METHOD]> | ||
before?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => void | ||
after?: (this: OBJECT, ...args: Parameters<OBJECT[METHOD]>) => void | ||
} | ||
@@ -69,1 +70,41 @@ ) { | ||
} | ||
export function instrumentSetter<OBJECT extends { [key: string]: any }, PROPERTY extends keyof OBJECT>( | ||
object: OBJECT, | ||
property: PROPERTY, | ||
after: (thisObject: OBJECT, value: OBJECT[PROPERTY]) => void | ||
) { | ||
const originalDescriptor = Object.getOwnPropertyDescriptor(object, property) | ||
if (!originalDescriptor || !originalDescriptor.set || !originalDescriptor.configurable) { | ||
return { stop: noop } | ||
} | ||
let instrumentation = (thisObject: OBJECT, value: OBJECT[PROPERTY]) => { | ||
// put hooked setter into event loop to avoid of set latency | ||
setTimeout( | ||
monitor(() => { | ||
after(thisObject, value) | ||
}), | ||
0 | ||
) | ||
} | ||
const instrumentationWrapper = function (this: OBJECT, value: OBJECT[PROPERTY]) { | ||
originalDescriptor.set!.call(this, value) | ||
instrumentation(this, value) | ||
} | ||
Object.defineProperty(object, property, { | ||
set: instrumentationWrapper, | ||
}) | ||
return { | ||
stop: () => { | ||
if (Object.getOwnPropertyDescriptor(object, property)?.set === instrumentationWrapper) { | ||
Object.defineProperty(object, property, originalDescriptor) | ||
} else { | ||
instrumentation = noop | ||
} | ||
}, | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
779466
15442