From 6b7e9bdd9a169a1a47d7a52de3ab639ce5c67ced Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 9 Jan 2025 16:47:29 +0100 Subject: [PATCH 1/2] add rule --- packages/eslint-config-sdk/src/base.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/eslint-config-sdk/src/base.js b/packages/eslint-config-sdk/src/base.js index c137729161c5..8c11f26dd925 100644 --- a/packages/eslint-config-sdk/src/base.js +++ b/packages/eslint-config-sdk/src/base.js @@ -52,6 +52,9 @@ module.exports = { '@typescript-eslint/consistent-type-imports': 'error', + // We want to use optional chaining, where possible, to safe bytes + '@typescript-eslint/prefer-optional-chain': 'error', + // Private and protected members of a class should be prefixed with a leading underscore. // typeLike declarations (class, interface, typeAlias, enum, typeParameter) should be // PascalCase. From 080674042a3c4df023907f7003f1945e5bbe5474 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 9 Jan 2025 17:50:51 +0100 Subject: [PATCH 2/2] wip --- .../captureConsole-attachStackTrace/test.ts | 4 +- .../integrations/captureConsole/test.ts | 4 +- .../featureFlags/withScope/test.ts | 4 +- .../launchdarkly/withScope/test.ts | 4 +- .../openfeature/withScope/test.ts | 4 +- .../acs/getCurrentScope/subject.js | 2 +- .../hub/isOlderThan/subject.js | 2 +- .../replay/captureReplayOffline/test.ts | 2 +- .../replay/replayIntegrationShim/test.ts | 2 +- .../suites/replay/replayShim/test.ts | 2 +- .../suites/transport/offline/queued/test.ts | 2 +- packages/angular/src/zone.ts | 2 +- .../src/getNativeImplementation.ts | 2 +- packages/browser-utils/src/instrument/dom.ts | 4 +- .../src/metrics/browserMetrics.ts | 4 +- packages/browser-utils/src/metrics/cls.ts | 4 +- .../browser-utils/src/metrics/instrument.ts | 2 +- packages/browser-utils/src/metrics/utils.ts | 2 +- .../web-vitals/lib/getNavigationEntry.ts | 3 +- .../src/metrics/web-vitals/lib/initMetric.ts | 4 +- .../metrics/web-vitals/lib/interactions.ts | 2 +- .../src/metrics/web-vitals/lib/onHidden.ts | 2 +- .../metrics/web-vitals/lib/whenActivated.ts | 2 +- .../src/metrics/web-vitals/lib/whenIdle.ts | 2 +- .../src/metrics/web-vitals/onTTFB.ts | 4 +- .../browser/src/integrations/breadcrumbs.ts | 2 +- .../src/integrations/browserapierrors.ts | 2 +- .../browser/src/integrations/contextlines.ts | 4 +- .../browser/src/integrations/httpcontext.ts | 12 ++- packages/browser/src/profiling/integration.ts | 6 +- packages/browser/src/profiling/utils.ts | 16 ++-- packages/browser/src/sdk.ts | 2 +- packages/browser/src/tracing/request.ts | 5 +- packages/browser/src/userfeedback.ts | 13 ++- packages/browser/test/loader.js | 6 +- packages/browser/test/sdk.test.ts | 4 +- packages/browser/test/tracing/request.test.ts | 54 +++++------ packages/core/src/client.ts | 6 +- packages/core/src/exports.ts | 4 +- packages/core/src/fetch.ts | 3 +- packages/core/src/integrations/dedupe.ts | 2 +- .../core/src/integrations/inboundfilters.ts | 8 +- .../core/src/integrations/rewriteframes.ts | 2 +- packages/core/src/integrations/zoderrors.ts | 8 +- packages/core/src/server-runtime-client.ts | 4 +- packages/core/src/transports/offline.ts | 4 +- .../core/src/utils-hoist/aggregate-errors.ts | 2 +- packages/core/src/utils-hoist/browser.ts | 2 +- packages/core/src/utils-hoist/envelope.ts | 4 +- packages/core/src/utils-hoist/misc.ts | 2 +- .../core/src/utils-hoist/node-stack-trace.ts | 2 +- packages/core/src/utils-hoist/ratelimit.ts | 4 +- packages/core/src/utils-hoist/supports.ts | 2 +- packages/core/src/utils-hoist/time.ts | 6 +- packages/core/src/utils-hoist/tracing.ts | 2 +- packages/core/src/utils-hoist/url.ts | 16 ++-- packages/core/src/utils/prepareEvent.ts | 6 +- packages/core/test/mocks/client.ts | 2 +- .../deno/src/integrations/contextlines.ts | 4 +- .../sentry-performance.ts | 2 +- packages/ember/vendor/initial-load-body.js | 2 +- packages/ember/vendor/initial-load-head.js | 2 +- packages/feedback/src/modal/integration.tsx | 10 +-- packages/feedback/src/util/mergeOptions.ts | 20 ++--- .../src/integrations/google-cloud-grpc.ts | 2 +- .../src/integrations/google-cloud-http.ts | 2 +- .../client/clientNormalizationIntegration.ts | 5 +- .../pagesRouterRoutingInstrumentation.ts | 4 +- .../devErrorSymbolicationEventProcessor.ts | 2 +- .../wrapApiHandlerWithSentryVercelCrons.ts | 4 +- .../src/config/loaders/wrappingLoader.ts | 2 +- .../wrapServerEntryWithDynamicImport.ts | 24 +++-- packages/node/src/integrations/context.ts | 2 +- .../node/src/integrations/contextlines.ts | 2 +- packages/node/src/integrations/http/index.ts | 4 +- packages/node/src/integrations/modules.ts | 2 +- .../node/src/integrations/tracing/express.ts | 2 +- packages/node/src/integrations/tracing/koa.ts | 2 +- packages/node/src/sdk/api.ts | 2 +- packages/node/src/sdk/index.ts | 2 +- packages/node/src/transports/http.ts | 12 ++- .../nuxt/src/runtime/plugins/sentry.server.ts | 4 +- packages/nuxt/src/runtime/utils.ts | 2 +- packages/nuxt/src/vite/utils.ts | 24 +++-- packages/profiling-node/src/integration.ts | 3 +- packages/profiling-node/src/utils.ts | 6 +- .../profiling-node/test/cpu_profiler.test.ts | 2 +- packages/react/src/reactrouterv3.ts | 2 +- .../react/src/reactrouterv6-compat-utils.tsx | 4 +- .../src/coreHandlers/handleAfterSendEvent.ts | 4 +- .../src/coreHandlers/handleBeforeSendEvent.ts | 3 +- .../src/coreHandlers/handleBreadcrumbs.ts | 2 +- packages/replay-internal/src/integration.ts | 4 +- packages/replay-internal/src/replay.ts | 6 +- .../src/util/addGlobalListeners.ts | 2 +- .../replay-internal/src/util/isRrwebError.ts | 2 +- packages/replay-internal/src/util/logger.ts | 8 +- .../test/integration/flush.test.ts | 12 +-- packages/solidstart/src/config/utils.ts | 24 +++-- packages/svelte/src/config.ts | 2 +- packages/svelte/test/preprocessors.test.ts | 90 ++++++++----------- packages/svelte/test/sdk.test.ts | 4 +- .../src/client/browserTracingIntegration.ts | 2 +- packages/sveltekit/src/server/handleError.ts | 2 +- packages/sveltekit/src/server/load.ts | 2 +- packages/sveltekit/src/server/serverRoute.ts | 2 +- packages/sveltekit/src/vite/autoInstrument.ts | 4 +- packages/vercel-edge/src/sdk.ts | 2 +- packages/vue/src/errorhandler.ts | 2 +- packages/vue/src/integration.ts | 2 +- packages/vue/src/tracing.ts | 4 +- packages/wasm/src/index.ts | 4 +- 112 files changed, 296 insertions(+), 343 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts b/dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts index 4f1aafb87c7d..7e61bc43ce0e 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts @@ -19,10 +19,10 @@ sentryTest( const errorEvent = events.find(event => event.message === 'console error'); const traceEvent = events.find(event => event.message === 'console trace'); const errorWithErrorEvent = events.find( - event => event.exception && event.exception.values?.[0].value === 'console error with error object', + event => event.exception?.values?.[0].value === 'console error with error object', ); const traceWithErrorEvent = events.find( - event => event.exception && event.exception.values?.[0].value === 'console trace with error object', + event => event.exception?.values?.[0].value === 'console trace with error object', ); expect(logEvent).toEqual( diff --git a/dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts b/dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts index 3dca4c6e979c..5cef9bc7e949 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts @@ -17,10 +17,10 @@ sentryTest('it captures console messages correctly', async ({ getLocalTestUrl, p const errorEvent = events.find(event => event.message === 'console error'); const traceEvent = events.find(event => event.message === 'console trace'); const errorWithErrorEvent = events.find( - event => event.exception && event.exception.values?.[0].value === 'console error with error object', + event => event.exception?.values?.[0].value === 'console error with error object', ); const traceWithErrorEvent = events.find( - event => event.exception && event.exception.values?.[0].value === 'console trace with error object', + event => event.exception?.values?.[0].value === 'console trace with error object', ); expect(logEvent).toEqual( diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/withScope/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/withScope/test.ts index 97ecf2d961a7..5fedd521b2c2 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/withScope/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/withScope/test.ts @@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({ const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true }); await page.goto(url); - const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true); - const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false); + const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true); + const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false); await page.evaluate(() => { const Sentry = (window as any).Sentry; diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/withScope/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/withScope/test.ts index 6046da6241be..b84c4c008e0e 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/withScope/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/withScope/test.ts @@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({ const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true }); await page.goto(url); - const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true); - const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false); + const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true); + const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false); await page.evaluate(() => { const Sentry = (window as any).Sentry; diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/withScope/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/withScope/test.ts index 7edb9b2e533b..60682b03e4a7 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/withScope/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/withScope/test.ts @@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({ const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true }); await page.goto(url); - const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true); - const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false); + const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true); + const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false); await page.evaluate(() => { const Sentry = (window as any).Sentry; diff --git a/dev-packages/browser-integration-tests/suites/old-sdk-interop/acs/getCurrentScope/subject.js b/dev-packages/browser-integration-tests/suites/old-sdk-interop/acs/getCurrentScope/subject.js index a3a2fb0e144c..273f740eea03 100644 --- a/dev-packages/browser-integration-tests/suites/old-sdk-interop/acs/getCurrentScope/subject.js +++ b/dev-packages/browser-integration-tests/suites/old-sdk-interop/acs/getCurrentScope/subject.js @@ -4,7 +4,7 @@ const sentryCarrier = window?.__SENTRY__; * Simulate an old pre v8 SDK obtaining the hub from the global sentry carrier * and checking for the hub version. */ -const res = sentryCarrier.acs && sentryCarrier.acs.getCurrentScope(); +const res = sentryCarrier.acs?.getCurrentScope(); // Write back result into the document document.getElementById('currentScope').innerText = res && 'scope'; diff --git a/dev-packages/browser-integration-tests/suites/old-sdk-interop/hub/isOlderThan/subject.js b/dev-packages/browser-integration-tests/suites/old-sdk-interop/hub/isOlderThan/subject.js index 8e7131a0fbe5..def990b268b5 100644 --- a/dev-packages/browser-integration-tests/suites/old-sdk-interop/hub/isOlderThan/subject.js +++ b/dev-packages/browser-integration-tests/suites/old-sdk-interop/hub/isOlderThan/subject.js @@ -4,7 +4,7 @@ const sentryCarrier = window?.__SENTRY__; * Simulate an old pre v8 SDK obtaining the hub from the global sentry carrier * and checking for the hub version. */ -const res = sentryCarrier.hub && sentryCarrier.hub.isOlderThan(7); +const res = sentryCarrier.hub?.isOlderThan(7); // Write back result into the document document.getElementById('olderThan').innerText = res; diff --git a/dev-packages/browser-integration-tests/suites/replay/captureReplayOffline/test.ts b/dev-packages/browser-integration-tests/suites/replay/captureReplayOffline/test.ts index b8b30184b754..ddd4be03e376 100644 --- a/dev-packages/browser-integration-tests/suites/replay/captureReplayOffline/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/captureReplayOffline/test.ts @@ -5,7 +5,7 @@ import { getReplayEvent, shouldSkipReplayTest, waitForReplayRequest } from '../. sentryTest('should capture replays offline', async ({ getLocalTestUrl, page }) => { // makeBrowserOfflineTransport is not included in any CDN bundles - if (shouldSkipReplayTest() || (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle'))) { + if (shouldSkipReplayTest() || process.env.PW_BUNDLE?.startsWith('bundle')) { sentryTest.skip(); } diff --git a/dev-packages/browser-integration-tests/suites/replay/replayIntegrationShim/test.ts b/dev-packages/browser-integration-tests/suites/replay/replayIntegrationShim/test.ts index a5f10c18d83f..ffe667d780dc 100644 --- a/dev-packages/browser-integration-tests/suites/replay/replayIntegrationShim/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/replayIntegrationShim/test.ts @@ -7,7 +7,7 @@ sentryTest( async ({ getLocalTestUrl, page, forceFlushReplay }) => { const bundle = process.env.PW_BUNDLE; - if (!bundle || !bundle.startsWith('bundle_') || bundle.includes('replay')) { + if (!bundle?.startsWith('bundle_') || bundle.includes('replay')) { sentryTest.skip(); } diff --git a/dev-packages/browser-integration-tests/suites/replay/replayShim/test.ts b/dev-packages/browser-integration-tests/suites/replay/replayShim/test.ts index 7df2ab111f3f..8df888863ea2 100644 --- a/dev-packages/browser-integration-tests/suites/replay/replayShim/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/replayShim/test.ts @@ -7,7 +7,7 @@ sentryTest( async ({ getLocalTestUrl, page, forceFlushReplay }) => { const bundle = process.env.PW_BUNDLE; - if (!bundle || !bundle.startsWith('bundle_') || bundle.includes('replay')) { + if (!bundle?.startsWith('bundle_') || bundle.includes('replay')) { sentryTest.skip(); } diff --git a/dev-packages/browser-integration-tests/suites/transport/offline/queued/test.ts b/dev-packages/browser-integration-tests/suites/transport/offline/queued/test.ts index 9b6eb36fd0ea..c330c17be1f7 100644 --- a/dev-packages/browser-integration-tests/suites/transport/offline/queued/test.ts +++ b/dev-packages/browser-integration-tests/suites/transport/offline/queued/test.ts @@ -10,7 +10,7 @@ function delay(ms: number) { sentryTest('should queue and retry events when they fail to send', async ({ getLocalTestUrl, page }) => { // makeBrowserOfflineTransport is not included in any CDN bundles - if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle')) { + if (process.env.PW_BUNDLE?.startsWith('bundle')) { sentryTest.skip(); } diff --git a/packages/angular/src/zone.ts b/packages/angular/src/zone.ts index fdd45bdf8b0c..22f56e4c3871 100644 --- a/packages/angular/src/zone.ts +++ b/packages/angular/src/zone.ts @@ -8,7 +8,7 @@ declare const Zone: any; // Therefore, it's advisable to safely check whether the `run` function is // available in the `` context. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -const isNgZoneEnabled = typeof Zone !== 'undefined' && Zone.root && Zone.root.run; +const isNgZoneEnabled = typeof Zone !== 'undefined' && Zone.root?.run; /** * The function that does the same job as `NgZone.runOutsideAngular`. diff --git a/packages/browser-utils/src/getNativeImplementation.ts b/packages/browser-utils/src/getNativeImplementation.ts index 42d402eb1b94..398a40045119 100644 --- a/packages/browser-utils/src/getNativeImplementation.ts +++ b/packages/browser-utils/src/getNativeImplementation.ts @@ -47,7 +47,7 @@ export function getNativeImplementation { _collectClsOnce(); - unsubscribeStartNavigation && unsubscribeStartNavigation(); + unsubscribeStartNavigation?.(); }); const activeSpan = getActiveSpan(); @@ -93,7 +93,7 @@ function sendStandaloneClsSpan(clsValue: number, entry: LayoutShift | undefined, const startTime = msToSec((browserPerformanceTimeOrigin || 0) + (entry?.startTime || 0)); const routeName = getCurrentScope().getScopeData().transactionName; - const name = entry ? htmlTreeAsString(entry.sources[0] && entry.sources[0].node) : 'Layout shift'; + const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift'; const attributes: SpanAttributes = dropUndefinedKeys({ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.cls', diff --git a/packages/browser-utils/src/metrics/instrument.ts b/packages/browser-utils/src/metrics/instrument.ts index 3f78c2e28605..b273f9d3eb5e 100644 --- a/packages/browser-utils/src/metrics/instrument.ts +++ b/packages/browser-utils/src/metrics/instrument.ts @@ -201,7 +201,7 @@ export function addPerformanceInstrumentationHandler( function triggerHandlers(type: InstrumentHandlerType, data: unknown): void { const typeHandlers = handlers[type]; - if (!typeHandlers || !typeHandlers.length) { + if (!typeHandlers?.length) { return; } diff --git a/packages/browser-utils/src/metrics/utils.ts b/packages/browser-utils/src/metrics/utils.ts index f9af4d564be1..928df83a9689 100644 --- a/packages/browser-utils/src/metrics/utils.ts +++ b/packages/browser-utils/src/metrics/utils.ts @@ -106,7 +106,7 @@ export function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptio // Web vital score calculation relies on the user agent to account for different // browsers setting different thresholds for what is considered a good/meh/bad value. // For example: Chrome vs. Chrome Mobile - 'user_agent.original': WINDOW.navigator && WINDOW.navigator.userAgent, + 'user_agent.original': WINDOW.navigator?.userAgent, ...passedAttributes, }; diff --git a/packages/browser-utils/src/metrics/web-vitals/lib/getNavigationEntry.ts b/packages/browser-utils/src/metrics/web-vitals/lib/getNavigationEntry.ts index 1e8521c2ddc6..f2c85f6127bc 100644 --- a/packages/browser-utils/src/metrics/web-vitals/lib/getNavigationEntry.ts +++ b/packages/browser-utils/src/metrics/web-vitals/lib/getNavigationEntry.ts @@ -19,8 +19,7 @@ import { WINDOW } from '../../../types'; // sentry-specific change: // add optional param to not check for responseStart (see comment below) export const getNavigationEntry = (checkResponseStart = true): PerformanceNavigationTiming | void => { - const navigationEntry = - WINDOW.performance && WINDOW.performance.getEntriesByType && WINDOW.performance.getEntriesByType('navigation')[0]; + const navigationEntry = WINDOW.performance?.getEntriesByType?.('navigation')[0]; // Check to ensure the `responseStart` property is present and valid. // In some cases no value is reported by the browser (for // privacy/security reasons), and in other cases (bugs) the value is diff --git a/packages/browser-utils/src/metrics/web-vitals/lib/initMetric.ts b/packages/browser-utils/src/metrics/web-vitals/lib/initMetric.ts index fee96d83bf33..b2cfbc609a25 100644 --- a/packages/browser-utils/src/metrics/web-vitals/lib/initMetric.ts +++ b/packages/browser-utils/src/metrics/web-vitals/lib/initMetric.ts @@ -25,9 +25,9 @@ export const initMetric = (name: MetricNa let navigationType: MetricType['navigationType'] = 'navigate'; if (navEntry) { - if ((WINDOW.document && WINDOW.document.prerendering) || getActivationStart() > 0) { + if (WINDOW.document?.prerendering || getActivationStart() > 0) { navigationType = 'prerender'; - } else if (WINDOW.document && WINDOW.document.wasDiscarded) { + } else if (WINDOW.document?.wasDiscarded) { navigationType = 'restore'; } else if (navEntry.type) { navigationType = navEntry.type.replace(/_/g, '-') as MetricType['navigationType']; diff --git a/packages/browser-utils/src/metrics/web-vitals/lib/interactions.ts b/packages/browser-utils/src/metrics/web-vitals/lib/interactions.ts index 6d6390755656..69ca920ddb67 100644 --- a/packages/browser-utils/src/metrics/web-vitals/lib/interactions.ts +++ b/packages/browser-utils/src/metrics/web-vitals/lib/interactions.ts @@ -113,7 +113,7 @@ export const processInteractionEntry = (entry: PerformanceEventTiming) => { existingInteraction.latency = entry.duration; } else if ( entry.duration === existingInteraction.latency && - entry.startTime === (existingInteraction.entries[0] && existingInteraction.entries[0].startTime) + entry.startTime === existingInteraction.entries[0]?.startTime ) { existingInteraction.entries.push(entry); } diff --git a/packages/browser-utils/src/metrics/web-vitals/lib/onHidden.ts b/packages/browser-utils/src/metrics/web-vitals/lib/onHidden.ts index 81d83caa53b5..f1640d4fcdac 100644 --- a/packages/browser-utils/src/metrics/web-vitals/lib/onHidden.ts +++ b/packages/browser-utils/src/metrics/web-vitals/lib/onHidden.ts @@ -32,7 +32,7 @@ export interface OnHiddenCallback { // simulate the page being hidden. export const onHidden = (cb: OnHiddenCallback) => { const onHiddenOrPageHide = (event: Event) => { - if (event.type === 'pagehide' || (WINDOW.document && WINDOW.document.visibilityState === 'hidden')) { + if (event.type === 'pagehide' || WINDOW.document?.visibilityState === 'hidden') { cb(event); } }; diff --git a/packages/browser-utils/src/metrics/web-vitals/lib/whenActivated.ts b/packages/browser-utils/src/metrics/web-vitals/lib/whenActivated.ts index 8463a1d199ef..e5e1ecd45385 100644 --- a/packages/browser-utils/src/metrics/web-vitals/lib/whenActivated.ts +++ b/packages/browser-utils/src/metrics/web-vitals/lib/whenActivated.ts @@ -17,7 +17,7 @@ import { WINDOW } from '../../../types'; export const whenActivated = (callback: () => void) => { - if (WINDOW.document && WINDOW.document.prerendering) { + if (WINDOW.document?.prerendering) { addEventListener('prerenderingchange', () => callback(), true); } else { callback(); diff --git a/packages/browser-utils/src/metrics/web-vitals/lib/whenIdle.ts b/packages/browser-utils/src/metrics/web-vitals/lib/whenIdle.ts index c140864b3539..8914c45d7bb3 100644 --- a/packages/browser-utils/src/metrics/web-vitals/lib/whenIdle.ts +++ b/packages/browser-utils/src/metrics/web-vitals/lib/whenIdle.ts @@ -30,7 +30,7 @@ export const whenIdle = (cb: () => void): number => { cb = runOnce(cb) as () => void; // If the document is hidden, run the callback immediately, otherwise // race an idle callback with the next `visibilitychange` event. - if (WINDOW.document && WINDOW.document.visibilityState === 'hidden') { + if (WINDOW.document?.visibilityState === 'hidden') { cb(); } else { handle = rIC(cb); diff --git a/packages/browser-utils/src/metrics/web-vitals/onTTFB.ts b/packages/browser-utils/src/metrics/web-vitals/onTTFB.ts index 7c8c1bb0b5c1..235895d093aa 100644 --- a/packages/browser-utils/src/metrics/web-vitals/onTTFB.ts +++ b/packages/browser-utils/src/metrics/web-vitals/onTTFB.ts @@ -30,9 +30,9 @@ export const TTFBThresholds: MetricRatingThresholds = [800, 1800]; * @param callback */ const whenReady = (callback: () => void) => { - if (WINDOW.document && WINDOW.document.prerendering) { + if (WINDOW.document?.prerendering) { whenActivated(() => whenReady(callback)); - } else if (WINDOW.document && WINDOW.document.readyState !== 'complete') { + } else if (WINDOW.document?.readyState !== 'complete') { addEventListener('load', () => whenReady(callback), true); } else { // Queue a task so the callback runs after `loadEventEnd`. diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index 488560407d9b..a45048ce2640 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -352,7 +352,7 @@ function _getHistoryBreadcrumbHandler(client: Client): (handlerData: HandlerData const parsedTo = parseUrl(to); // Initial pushState doesn't provide `from` information - if (!parsedFrom || !parsedFrom.path) { + if (!parsedFrom?.path) { parsedFrom = parsedLoc; } diff --git a/packages/browser/src/integrations/browserapierrors.ts b/packages/browser/src/integrations/browserapierrors.ts index 44fc854d03d4..923079b62607 100644 --- a/packages/browser/src/integrations/browserapierrors.ts +++ b/packages/browser/src/integrations/browserapierrors.ts @@ -166,7 +166,7 @@ function _wrapEventTarget(target: string): void { const proto = globalObject[target]?.prototype; // eslint-disable-next-line no-prototype-builtins - if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) { + if (!proto?.hasOwnProperty?.('addEventListener')) { return; } diff --git a/packages/browser/src/integrations/contextlines.ts b/packages/browser/src/integrations/contextlines.ts index f8eac03d894c..775df33f0595 100644 --- a/packages/browser/src/integrations/contextlines.ts +++ b/packages/browser/src/integrations/contextlines.ts @@ -51,8 +51,8 @@ function addSourceContext(event: Event, contextLines: number): Event { return event; } - const exceptions = event.exception && event.exception.values; - if (!exceptions || !exceptions.length) { + const exceptions = event.exception?.values; + if (!exceptions?.length) { return event; } diff --git a/packages/browser/src/integrations/httpcontext.ts b/packages/browser/src/integrations/httpcontext.ts index 0db88cfe355c..78e27713c78f 100644 --- a/packages/browser/src/integrations/httpcontext.ts +++ b/packages/browser/src/integrations/httpcontext.ts @@ -1,4 +1,4 @@ -import { defineIntegration } from '@sentry/core'; +import { defineIntegration, getLocationHref } from '@sentry/core'; import { WINDOW } from '../helpers'; /** @@ -15,16 +15,20 @@ export const httpContextIntegration = defineIntegration(() => { } // grab as much info as exists and add it to the event - const url = (event.request && event.request.url) || (WINDOW.location && WINDOW.location.href); + const url = event.request?.url || getLocationHref(); const { referrer } = WINDOW.document || {}; const { userAgent } = WINDOW.navigator || {}; const headers = { - ...(event.request && event.request.headers), + ...event.request?.headers, ...(referrer && { Referer: referrer }), ...(userAgent && { 'User-Agent': userAgent }), }; - const request = { ...event.request, ...(url && { url }), headers }; + const request = { + ...event.request, + ...(url && { url }), + headers, + }; event.request = request; }, diff --git a/packages/browser/src/profiling/integration.ts b/packages/browser/src/profiling/integration.ts index 2b4156d4ab01..df3c4923d1c9 100644 --- a/packages/browser/src/profiling/integration.ts +++ b/packages/browser/src/profiling/integration.ts @@ -50,8 +50,8 @@ const _browserProfilingIntegration = (() => { for (const profiledTransaction of profiledTransactionEvents) { const context = profiledTransaction?.contexts; - const profile_id = context && context['profile'] && context['profile']['profile_id']; - const start_timestamp = context && context['profile'] && context['profile']['start_timestamp']; + const profile_id = context?.profile?.['profile_id']; + const start_timestamp = context?.profile?.['start_timestamp']; if (typeof profile_id !== 'string') { DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a span without a profile context'); @@ -64,7 +64,7 @@ const _browserProfilingIntegration = (() => { } // Remove the profile from the span context before sending, relay will take care of the rest. - if (context && context['profile']) { + if (context?.profile) { delete context.profile; } diff --git a/packages/browser/src/profiling/utils.ts b/packages/browser/src/profiling/utils.ts index 8d8e79fe9602..f06e1606302b 100644 --- a/packages/browser/src/profiling/utils.ts +++ b/packages/browser/src/profiling/utils.ts @@ -21,16 +21,16 @@ const MS_TO_NS = 1e6; const THREAD_ID_STRING = String(0); const THREAD_NAME = 'main'; +// We force make this optional to be on the safe side... +const navigator = WINDOW.navigator as typeof WINDOW.navigator | undefined; + // Machine properties (eval only once) let OS_PLATFORM = ''; let OS_PLATFORM_VERSION = ''; let OS_ARCH = ''; -let OS_BROWSER = (WINDOW.navigator && WINDOW.navigator.userAgent) || ''; +let OS_BROWSER = navigator?.userAgent || ''; let OS_MODEL = ''; -const OS_LOCALE = - (WINDOW.navigator && WINDOW.navigator.language) || - (WINDOW.navigator && WINDOW.navigator.languages && WINDOW.navigator.languages[0]) || - ''; +const OS_LOCALE = navigator?.language || navigator?.languages?.[0] || ''; type UAData = { platform?: string; @@ -52,7 +52,7 @@ function isUserAgentData(data: unknown): data is UserAgentData { } // @ts-expect-error userAgentData is not part of the navigator interface yet -const userAgentData = WINDOW.navigator && WINDOW.navigator.userAgentData; +const userAgentData = navigator?.userAgentData; if (isUserAgentData(userAgentData)) { userAgentData @@ -63,7 +63,7 @@ if (isUserAgentData(userAgentData)) { OS_MODEL = ua.model || ''; OS_PLATFORM_VERSION = ua.platformVersion || ''; - if (ua.fullVersionList && ua.fullVersionList.length > 0) { + if (ua.fullVersionList?.length) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const firstUa = ua.fullVersionList[ua.fullVersionList.length - 1]!; OS_BROWSER = `${firstUa.brand} ${firstUa.version}`; @@ -199,7 +199,7 @@ export function createProfilePayload( * */ export function isProfiledTransactionEvent(event: Event): event is ProfiledEvent { - return !!(event.sdkProcessingMetadata && event.sdkProcessingMetadata['profile']); + return !!event.sdkProcessingMetadata?.profile; } /* diff --git a/packages/browser/src/sdk.ts b/packages/browser/src/sdk.ts index 73f3646b2c8f..d6fedeba769b 100644 --- a/packages/browser/src/sdk.ts +++ b/packages/browser/src/sdk.ts @@ -53,7 +53,7 @@ export function applyDefaultOptions(optionsArg: BrowserOptions = {}): BrowserOpt release: typeof __SENTRY_RELEASE__ === 'string' // This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value ? __SENTRY_RELEASE__ - : WINDOW.SENTRY_RELEASE && WINDOW.SENTRY_RELEASE.id // This supports the variable that sentry-webpack-plugin injects + : WINDOW.SENTRY_RELEASE?.id // This supports the variable that sentry-webpack-plugin injects ? WINDOW.SENTRY_RELEASE.id : undefined, sendClientReports: true, diff --git a/packages/browser/src/tracing/request.ts b/packages/browser/src/tracing/request.ts index 106e2014f39b..f89c7a8a91df 100644 --- a/packages/browser/src/tracing/request.ts +++ b/packages/browser/src/tracing/request.ts @@ -12,6 +12,7 @@ import { addFetchInstrumentationHandler, browserPerformanceTimeOrigin, getActiveSpan, + getLocationHref, getTraceData, hasTracingEnabled, instrumentFetchRequest, @@ -297,7 +298,7 @@ export function shouldAttachHeaders( ): boolean { // window.location.href not being defined is an edge case in the browser but we need to handle it. // Potentially dangerous situations where it may not be defined: Browser Extensions, Web Workers, patching of the location obj - const href: string | undefined = WINDOW.location && WINDOW.location.href; + const href = getLocationHref(); if (!href) { // If there is no window.location.origin, we default to only attaching tracing headers to relative requests, i.e. ones that start with `/` @@ -345,7 +346,7 @@ export function xhrCallback( spans: Record, ): Span | undefined { const xhr = handlerData.xhr; - const sentryXhrData = xhr && xhr[SENTRY_XHR_DATA_KEY]; + const sentryXhrData = xhr?.[SENTRY_XHR_DATA_KEY]; if (!xhr || xhr.__sentry_own_request__ || !sentryXhrData) { return undefined; diff --git a/packages/browser/src/userfeedback.ts b/packages/browser/src/userfeedback.ts index dcafa6c3c98c..57e42eaafb9a 100644 --- a/packages/browser/src/userfeedback.ts +++ b/packages/browser/src/userfeedback.ts @@ -19,13 +19,12 @@ export function createUserFeedbackEnvelope( const headers: EventEnvelope[0] = { event_id: feedback.event_id, sent_at: new Date().toISOString(), - ...(metadata && - metadata.sdk && { - sdk: { - name: metadata.sdk.name, - version: metadata.sdk.version, - }, - }), + ...(metadata?.sdk && { + sdk: { + name: metadata.sdk.name, + version: metadata.sdk.version, + }, + }), ...(!!tunnel && !!dsn && { dsn: dsnToString(dsn) }), }; const item = createUserFeedbackEnvelopeItem(feedback); diff --git a/packages/browser/test/loader.js b/packages/browser/test/loader.js index cfb749ae50a8..5361aea71b7a 100644 --- a/packages/browser/test/loader.js +++ b/packages/browser/test/loader.js @@ -37,8 +37,8 @@ if ( ('e' in content || 'p' in content || - (content.f && content.f.indexOf('capture') > -1) || - (content.f && content.f.indexOf('showReportDialog') > -1)) && + (content.f?.indexOf('capture') > -1) || + (content.f?.indexOf('showReportDialog') > -1)) && lazy ) { // We only want to lazy inject/load the sdk bundle if @@ -115,7 +115,7 @@ var initAlreadyCalled = false; var __sentry = _window['__SENTRY__']; // If there is a global __SENTRY__ that means that in any of the callbacks init() was already invoked - if (!(typeof __sentry === 'undefined') && __sentry.hub && __sentry.hub.getClient()) { + if (!(typeof __sentry === 'undefined') && __sentry.hub?.getClient()) { initAlreadyCalled = true; } diff --git a/packages/browser/test/sdk.test.ts b/packages/browser/test/sdk.test.ts index a16c72ad04f1..192915c8442d 100644 --- a/packages/browser/test/sdk.test.ts +++ b/packages/browser/test/sdk.test.ts @@ -284,7 +284,7 @@ describe('applyDefaultOptions', () => { sendClientReports: true, }); - expect(actual.defaultIntegrations && actual.defaultIntegrations.map(i => i.name)).toEqual( + expect((actual.defaultIntegrations as { name: string }[]).map(i => i.name)).toEqual( getDefaultIntegrations(options).map(i => i.name), ); }); @@ -303,7 +303,7 @@ describe('applyDefaultOptions', () => { tracesSampleRate: 0.5, }); - expect(actual.defaultIntegrations && actual.defaultIntegrations.map(i => i.name)).toEqual( + expect((actual.defaultIntegrations as { name: string }[]).map(i => i.name)).toEqual( getDefaultIntegrations(options).map(i => i.name), ); }); diff --git a/packages/browser/test/tracing/request.test.ts b/packages/browser/test/tracing/request.test.ts index 337d08caff24..b262053190eb 100644 --- a/packages/browser/test/tracing/request.test.ts +++ b/packages/browser/test/tracing/request.test.ts @@ -1,9 +1,9 @@ -import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import type { MockInstance } from 'vitest'; +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import * as browserUtils from '@sentry-internal/browser-utils'; import * as utils from '@sentry/core'; import type { Client } from '@sentry/core'; -import { WINDOW } from '../../src/helpers'; import { extractNetworkProtocol, instrumentOutgoingRequests, shouldAttachHeaders } from '../../src/tracing/request'; @@ -131,18 +131,14 @@ describe('shouldAttachHeaders', () => { }); describe('with no defined `tracePropagationTargets`', () => { - let originalWindowLocation: Location; - - beforeAll(() => { - originalWindowLocation = WINDOW.location; - // @ts-expect-error Override delete - delete WINDOW.location; - // @ts-expect-error We are missing some fields of the Origin interface but it doesn't matter for these tests. - WINDOW.location = new URL('https://my-origin.com'); + let locationHrefSpy: MockInstance; + + beforeEach(() => { + locationHrefSpy = vi.spyOn(utils, 'getLocationHref').mockImplementation(() => 'https://my-origin.com'); }); - afterAll(() => { - WINDOW.location = originalWindowLocation; + afterEach(() => { + locationHrefSpy.mockReset(); }); it.each([ @@ -173,18 +169,16 @@ describe('shouldAttachHeaders', () => { }); describe('with `tracePropagationTargets`', () => { - let originalWindowLocation: Location; - - beforeAll(() => { - originalWindowLocation = WINDOW.location; - // @ts-expect-error Override delete - delete WINDOW.location; - // @ts-expect-error We are missing some fields of the Origin interface but it doesn't matter for these tests. - WINDOW.location = new URL('https://my-origin.com/api/my-route'); + let locationHrefSpy: MockInstance; + + beforeEach(() => { + locationHrefSpy = vi + .spyOn(utils, 'getLocationHref') + .mockImplementation(() => 'https://my-origin.com/api/my-route'); }); - afterAll(() => { - WINDOW.location = originalWindowLocation; + afterEach(() => { + locationHrefSpy.mockReset(); }); it.each([ @@ -298,18 +292,14 @@ describe('shouldAttachHeaders', () => { }); describe('when window.location.href is not available', () => { - let originalWindowLocation: Location; - - beforeAll(() => { - originalWindowLocation = WINDOW.location; - // @ts-expect-error Override delete - delete WINDOW.location; - // @ts-expect-error We need to simulate an edge-case - WINDOW.location = undefined; + let locationHrefSpy: MockInstance; + + beforeEach(() => { + locationHrefSpy = vi.spyOn(utils, 'getLocationHref').mockImplementation(() => ''); }); - afterAll(() => { - WINDOW.location = originalWindowLocation; + afterEach(() => { + locationHrefSpy.mockReset(); }); describe('with no defined `tracePropagationTargets`', () => { diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index cc555bca8e4d..90b6d294420f 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -612,7 +612,7 @@ export abstract class Client { protected _updateSessionFromEvent(session: Session, event: Event): void { let crashed = false; let errored = false; - const exceptions = event.exception && event.exception.values; + const exceptions = event.exception?.values; if (exceptions) { errored = true; @@ -841,9 +841,7 @@ export abstract class Client { } if (isTransaction) { - const spanCountBefore = - (processedEvent.sdkProcessingMetadata && processedEvent.sdkProcessingMetadata.spanCountBeforeProcessing) || - 0; + const spanCountBefore = processedEvent.sdkProcessingMetadata?.spanCountBeforeProcessing || 0; const spanCountAfter = processedEvent.spans ? processedEvent.spans.length : 0; const droppedSpanCount = spanCountBefore - spanCountAfter; diff --git a/packages/core/src/exports.ts b/packages/core/src/exports.ts index fcf58bec1786..4854ee86efb8 100644 --- a/packages/core/src/exports.ts +++ b/packages/core/src/exports.ts @@ -243,7 +243,7 @@ export function isInitialized(): boolean { /** If the SDK is initialized & enabled. */ export function isEnabled(): boolean { const client = getClient(); - return !!client && client.getOptions().enabled !== false && !!client.getTransport(); + return client?.getOptions().enabled !== false && !!client?.getTransport(); } /** @@ -277,7 +277,7 @@ export function startSession(context?: SessionContext): Session { // End existing session if there's one const currentSession = isolationScope.getSession(); - if (currentSession && currentSession.status === 'ok') { + if (currentSession?.status === 'ok') { updateSession(currentSession, { status: 'exited' }); } diff --git a/packages/core/src/fetch.ts b/packages/core/src/fetch.ts index 95522b3b3b2c..9cd295520926 100644 --- a/packages/core/src/fetch.ts +++ b/packages/core/src/fetch.ts @@ -235,8 +235,7 @@ function endSpan(span: Span, handlerData: HandlerDataFetch): void { if (handlerData.response) { setHttpStatus(span, handlerData.response.status); - const contentLength = - handlerData.response && handlerData.response.headers && handlerData.response.headers.get('content-length'); + const contentLength = handlerData.response?.headers && handlerData.response.headers.get('content-length'); if (contentLength) { const contentLengthNum = parseInt(contentLength); diff --git a/packages/core/src/integrations/dedupe.ts b/packages/core/src/integrations/dedupe.ts index 7687c1f5b73e..5f6b249319aa 100644 --- a/packages/core/src/integrations/dedupe.ts +++ b/packages/core/src/integrations/dedupe.ts @@ -174,5 +174,5 @@ function _isSameFingerprint(currentEvent: Event, previousEvent: Event): boolean } function _getExceptionFromEvent(event: Event): Exception | undefined { - return event.exception && event.exception.values && event.exception.values[0]; + return event.exception?.values && event.exception.values[0]; } diff --git a/packages/core/src/integrations/inboundfilters.ts b/packages/core/src/integrations/inboundfilters.ts index 223490bf9528..17b4442cee57 100644 --- a/packages/core/src/integrations/inboundfilters.ts +++ b/packages/core/src/integrations/inboundfilters.ts @@ -131,8 +131,7 @@ function _isIgnoredTransaction(event: Event, ignoreTransactions?: Array): boolean { - // TODO: Use Glob instead? - if (!denyUrls || !denyUrls.length) { + if (!denyUrls?.length) { return false; } const url = _getEventFilterUrl(event); @@ -140,8 +139,7 @@ function _isDeniedUrl(event: Event, denyUrls?: Array): boolean } function _isAllowedUrl(event: Event, allowUrls?: Array): boolean { - // TODO: Use Glob instead? - if (!allowUrls || !allowUrls.length) { + if (!allowUrls?.length) { return true; } const url = _getEventFilterUrl(event); @@ -193,7 +191,7 @@ function _isUselessError(event: Event): boolean { } // We only want to consider events for dropping that actually have recorded exception values. - if (!event.exception || !event.exception.values || event.exception.values.length === 0) { + if (!event.exception?.values?.length) { return false; } diff --git a/packages/core/src/integrations/rewriteframes.ts b/packages/core/src/integrations/rewriteframes.ts index 3c9a2c8b7472..3c4ab5aee464 100644 --- a/packages/core/src/integrations/rewriteframes.ts +++ b/packages/core/src/integrations/rewriteframes.ts @@ -54,7 +54,7 @@ export const rewriteFramesIntegration = defineIntegration((options: RewriteFrame const root = options.root; const prefix = options.prefix || 'app:///'; - const isBrowser = 'window' in GLOBAL_OBJ && GLOBAL_OBJ.window !== undefined; + const isBrowser = 'window' in GLOBAL_OBJ && !!GLOBAL_OBJ.window; const iteratee: StackFrameIteratee = options.iteratee || generateIteratee({ isBrowser, root, prefix }); diff --git a/packages/core/src/integrations/zoderrors.ts b/packages/core/src/integrations/zoderrors.ts index fc36925eb0ea..a408285800d9 100644 --- a/packages/core/src/integrations/zoderrors.ts +++ b/packages/core/src/integrations/zoderrors.ts @@ -63,7 +63,7 @@ function formatIssueTitle(issue: ZodIssue): SingleLevelZodIssue { function formatIssueMessage(zodError: ZodError): string { const errorKeyMap = new Set(); for (const iss of zodError.issues) { - if (iss.path && iss.path[0]) { + if (iss.path?.[0]) { errorKeyMap.add(iss.path[0]); } } @@ -77,10 +77,8 @@ function formatIssueMessage(zodError: ZodError): string { */ export function applyZodErrorsToEvent(limit: number, event: Event, hint?: EventHint): Event { if ( - !event.exception || - !event.exception.values || - !hint || - !hint.originalException || + !event.exception?.values || + !hint?.originalException || !originalExceptionIsZodError(hint.originalException) || hint.originalException.issues.length === 0 ) { diff --git a/packages/core/src/server-runtime-client.ts b/packages/core/src/server-runtime-client.ts index 52bc6a528ed2..8bb07b976d65 100644 --- a/packages/core/src/server-runtime-client.ts +++ b/packages/core/src/server-runtime-client.ts @@ -88,7 +88,7 @@ export class ServerRuntimeClient< */ public captureEvent(event: Event, hint?: EventHint, scope?: Scope): string { // If the event is of type Exception, then a request session should be captured - const isException = !event.type && event.exception && event.exception.values && event.exception.values.length > 0; + const isException = !event.type && event.exception?.values && event.exception.values.length > 0; if (isException) { setCurrentRequestSessionErroredOrCrashed(hint); } @@ -176,7 +176,7 @@ export class ServerRuntimeClient< if (this._options.runtime) { event.contexts = { ...event.contexts, - runtime: (event.contexts || {}).runtime || this._options.runtime, + runtime: event.contexts?.runtime || this._options.runtime, }; } diff --git a/packages/core/src/transports/offline.ts b/packages/core/src/transports/offline.ts index 4cdd0b4a71af..0b99baba1e4b 100644 --- a/packages/core/src/transports/offline.ts +++ b/packages/core/src/transports/offline.ts @@ -134,9 +134,9 @@ export function makeOfflineTransport( if (result) { // If there's a retry-after header, use that as the next delay. - if (result.headers && result.headers['retry-after']) { + if (result.headers?.['retry-after']) { delay = parseRetryAfterHeader(result.headers['retry-after']); - } else if (result.headers && result.headers['x-sentry-rate-limits']) { + } else if (result.headers?.['x-sentry-rate-limits']) { delay = 60_000; // 60 seconds } // If we have a server error, return now so we don't flush the queue. else if ((result.statusCode || 0) >= 400) { diff --git a/packages/core/src/utils-hoist/aggregate-errors.ts b/packages/core/src/utils-hoist/aggregate-errors.ts index 5f791183f02b..606b2d12161e 100644 --- a/packages/core/src/utils-hoist/aggregate-errors.ts +++ b/packages/core/src/utils-hoist/aggregate-errors.ts @@ -15,7 +15,7 @@ export function applyAggregateErrorsToEvent( event: Event, hint?: EventHint, ): void { - if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) { + if (!event.exception?.values || !hint || !isInstanceOf(hint.originalException, Error)) { return; } diff --git a/packages/core/src/utils-hoist/browser.ts b/packages/core/src/utils-hoist/browser.ts index cf971697df42..bd9775c594ab 100644 --- a/packages/core/src/utils-hoist/browser.ts +++ b/packages/core/src/utils-hoist/browser.ts @@ -76,7 +76,7 @@ function _htmlElementAsString(el: unknown, keyAttrs?: string[]): string { const out = []; - if (!elem || !elem.tagName) { + if (!elem?.tagName) { return ''; } diff --git a/packages/core/src/utils-hoist/envelope.ts b/packages/core/src/utils-hoist/envelope.ts index ea2b733f1dc1..46512850cefc 100644 --- a/packages/core/src/utils-hoist/envelope.ts +++ b/packages/core/src/utils-hoist/envelope.ts @@ -234,7 +234,7 @@ export function envelopeItemTypeToDataCategory(type: EnvelopeItemType): DataCate /** Extracts the minimal SDK info from the metadata or an events */ export function getSdkMetadataForEnvelopeHeader(metadataOrEvent?: SdkMetadata | Event): SdkInfo | undefined { - if (!metadataOrEvent || !metadataOrEvent.sdk) { + if (!metadataOrEvent?.sdk) { return; } const { name, version } = metadataOrEvent.sdk; @@ -251,7 +251,7 @@ export function createEventEnvelopeHeaders( tunnel: string | undefined, dsn?: DsnComponents, ): EventEnvelopeHeaders { - const dynamicSamplingContext = event.sdkProcessingMetadata && event.sdkProcessingMetadata.dynamicSamplingContext; + const dynamicSamplingContext = event.sdkProcessingMetadata?.dynamicSamplingContext; return { event_id: event.event_id as string, sent_at: new Date().toISOString(), diff --git a/packages/core/src/utils-hoist/misc.ts b/packages/core/src/utils-hoist/misc.ts index 83390eae463c..853e11a09894 100644 --- a/packages/core/src/utils-hoist/misc.ts +++ b/packages/core/src/utils-hoist/misc.ts @@ -55,7 +55,7 @@ export function uuid4(): string { } function getFirstException(event: Event): Exception | undefined { - return event.exception && event.exception.values ? event.exception.values[0] : undefined; + return event.exception?.values?.[0]; } /** diff --git a/packages/core/src/utils-hoist/node-stack-trace.ts b/packages/core/src/utils-hoist/node-stack-trace.ts index 1201fefcdc4c..56e94a0457f5 100644 --- a/packages/core/src/utils-hoist/node-stack-trace.ts +++ b/packages/core/src/utils-hoist/node-stack-trace.ts @@ -100,7 +100,7 @@ export function node(getModule?: GetModuleFn): StackLineParserFn { functionName = typeName ? `${typeName}.${methodName}` : methodName; } - let filename = lineMatch[2] && lineMatch[2].startsWith('file://') ? lineMatch[2].slice(7) : lineMatch[2]; + let filename = lineMatch[2]?.startsWith('file://') ? lineMatch[2].slice(7) : lineMatch[2]; const isNative = lineMatch[5] === 'native'; // If it's a Windows path, trim the leading slash so that `/C:/foo` becomes `C:/foo` diff --git a/packages/core/src/utils-hoist/ratelimit.ts b/packages/core/src/utils-hoist/ratelimit.ts index db2053bdabd6..501621245dd0 100644 --- a/packages/core/src/utils-hoist/ratelimit.ts +++ b/packages/core/src/utils-hoist/ratelimit.ts @@ -59,8 +59,8 @@ export function updateRateLimits( // "The name is case-insensitive." // https://developer.mozilla.org/en-US/docs/Web/API/Headers/get - const rateLimitHeader = headers && headers['x-sentry-rate-limits']; - const retryAfterHeader = headers && headers['retry-after']; + const rateLimitHeader = headers?.['x-sentry-rate-limits']; + const retryAfterHeader = headers?.['retry-after']; if (rateLimitHeader) { /** diff --git a/packages/core/src/utils-hoist/supports.ts b/packages/core/src/utils-hoist/supports.ts index 031402bb78b1..d52c06e702ea 100644 --- a/packages/core/src/utils-hoist/supports.ts +++ b/packages/core/src/utils-hoist/supports.ts @@ -124,7 +124,7 @@ export function supportsNativeFetch(): boolean { const sandbox = doc.createElement('iframe'); sandbox.hidden = true; doc.head.appendChild(sandbox); - if (sandbox.contentWindow && sandbox.contentWindow.fetch) { + if (sandbox.contentWindow?.fetch) { // eslint-disable-next-line @typescript-eslint/unbound-method result = isNativeFunction(sandbox.contentWindow.fetch); } diff --git a/packages/core/src/utils-hoist/time.ts b/packages/core/src/utils-hoist/time.ts index e03e7ba4d39b..198705f31f8f 100644 --- a/packages/core/src/utils-hoist/time.ts +++ b/packages/core/src/utils-hoist/time.ts @@ -34,7 +34,7 @@ export function dateTimestampInSeconds(): number { */ function createUnixTimestampInSecondsFunc(): () => number { const { performance } = GLOBAL_OBJ as typeof GLOBAL_OBJ & { performance?: Performance }; - if (!performance || !performance.now) { + if (!performance?.now) { return dateTimestampInSeconds; } @@ -85,7 +85,7 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // data as reliable if they are within a reasonable threshold of the current time. const { performance } = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window; - if (!performance || !performance.now) { + if (!performance?.now) { // eslint-disable-next-line deprecation/deprecation _browserPerformanceTimeOriginMode = 'none'; return undefined; @@ -107,7 +107,7 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the // Date API. // eslint-disable-next-line deprecation/deprecation - const navigationStart = performance.timing && performance.timing.navigationStart; + const navigationStart = performance.timing?.navigationStart; const hasNavigationStart = typeof navigationStart === 'number'; // if navigationStart isn't available set delta to threshold so it isn't used const navigationStartDelta = hasNavigationStart ? Math.abs(navigationStart + performanceNow - dateNow) : threshold; diff --git a/packages/core/src/utils-hoist/tracing.ts b/packages/core/src/utils-hoist/tracing.ts index b0dc6a1a6cdc..59359310f548 100644 --- a/packages/core/src/utils-hoist/tracing.ts +++ b/packages/core/src/utils-hoist/tracing.ts @@ -54,7 +54,7 @@ export function propagationContextFromHeaders( const traceparentData = extractTraceparentData(sentryTrace); const dynamicSamplingContext = baggageHeaderToDynamicSamplingContext(baggage); - if (!traceparentData || !traceparentData.traceId) { + if (!traceparentData?.traceId) { return { traceId: generateTraceId() }; } diff --git a/packages/core/src/utils-hoist/url.ts b/packages/core/src/utils-hoist/url.ts index 7863e208f2cc..e62d22f05e26 100644 --- a/packages/core/src/utils-hoist/url.ts +++ b/packages/core/src/utils-hoist/url.ts @@ -56,15 +56,13 @@ export function getSanitizedUrlString(url: PartialURL): string { const { protocol, host, path } = url; const filteredHost = - (host && - host - // Always filter out authority - .replace(/^.*@/, '[filtered]:[filtered]@') - // Don't show standard :80 (http) and :443 (https) ports to reduce the noise - // TODO: Use new URL global if it exists - .replace(/(:80)$/, '') - .replace(/(:443)$/, '')) || - ''; + host + // Always filter out authority + ?.replace(/^.*@/, '[filtered]:[filtered]@') + // Don't show standard :80 (http) and :443 (https) ports to reduce the noise + // TODO: Use new URL global if it exists + .replace(/(:80)$/, '') + .replace(/(:443)$/, '') || ''; return `${protocol ? `${protocol}://` : ''}${filteredHost}${path}`; } diff --git a/packages/core/src/utils/prepareEvent.ts b/packages/core/src/utils/prepareEvent.ts index e2d26bdbfa69..e417640a387a 100644 --- a/packages/core/src/utils/prepareEvent.ts +++ b/packages/core/src/utils/prepareEvent.ts @@ -148,7 +148,7 @@ export function applyClientOptions(event: Event, options: ClientOptions): void { event.message = truncate(event.message, maxValueLength); } - const exception = event.exception && event.exception.values && event.exception.values[0]; + const exception = event.exception?.values?.[0]; if (exception?.value) { exception.value = truncate(exception.value, maxValueLength); } @@ -265,7 +265,7 @@ function normalizeEvent(event: Event | null, depth: number, maxBreadth: number): // For now the decision is to skip normalization of Transactions and Spans, // so this block overwrites the normalized event to add back the original // Transaction information prior to normalization. - if (event.contexts && event.contexts.trace && normalized.contexts) { + if (event.contexts?.trace && normalized.contexts) { normalized.contexts.trace = event.contexts.trace; // event.contexts.trace.data may contain circular/dangerous data so we need to normalize it @@ -290,7 +290,7 @@ function normalizeEvent(event: Event | null, depth: number, maxBreadth: number): // flag integrations. It has a greater nesting depth than our other typed // Contexts, so we re-normalize with a fixed depth of 3 here. We do not want // to skip this in case of conflicting, user-provided context. - if (event.contexts && event.contexts.flags && normalized.contexts) { + if (event.contexts?.flags && normalized.contexts) { normalized.contexts.flags = normalize(event.contexts.flags, 3, maxBreadth); } diff --git a/packages/core/test/mocks/client.ts b/packages/core/test/mocks/client.ts index 91013d886cc8..eee8a1a6dfe4 100644 --- a/packages/core/test/mocks/client.ts +++ b/packages/core/test/mocks/client.ts @@ -85,7 +85,7 @@ export class TestClient extends Client { // In real life, this will get deleted as part of envelope creation. delete event.sdkProcessingMetadata; - TestClient.sendEventCalled && TestClient.sendEventCalled(event); + TestClient.sendEventCalled?.(event); } public sendSession(session: Session): void { diff --git a/packages/deno/src/integrations/contextlines.ts b/packages/deno/src/integrations/contextlines.ts index d969ab001d7e..d69782affe22 100644 --- a/packages/deno/src/integrations/contextlines.ts +++ b/packages/deno/src/integrations/contextlines.ts @@ -74,9 +74,9 @@ export const contextLinesIntegration = defineIntegration(_contextLinesIntegratio /** Processes an event and adds context lines */ async function addSourceContext(event: Event, contextLines: number): Promise { - if (contextLines > 0 && event.exception && event.exception.values) { + if (contextLines > 0 && event.exception?.values) { for (const exception of event.exception.values) { - if (exception.stacktrace && exception.stacktrace.frames) { + if (exception.stacktrace?.frames) { await addSourceContextToFrames(exception.stacktrace.frames, contextLines); } } diff --git a/packages/ember/addon/instance-initializers/sentry-performance.ts b/packages/ember/addon/instance-initializers/sentry-performance.ts index 26835155f0af..c4e4621e563f 100644 --- a/packages/ember/addon/instance-initializers/sentry-performance.ts +++ b/packages/ember/addon/instance-initializers/sentry-performance.ts @@ -85,7 +85,7 @@ function getTransitionInformation( } function getLocationURL(location: EmberRouterMain['location']): string { - if (!location || !location.getURL || !location.formatURL) { + if (!location?.getURL || !location?.formatURL) { return ''; } const url = location.formatURL(location.getURL()); diff --git a/packages/ember/vendor/initial-load-body.js b/packages/ember/vendor/initial-load-body.js index c538bf091d70..a4924bcc27cf 100644 --- a/packages/ember/vendor/initial-load-body.js +++ b/packages/ember/vendor/initial-load-body.js @@ -1,3 +1,3 @@ -if (window.performance && window.performance.mark) { +if (window.performance?.mark) { window.performance.mark('@sentry/ember:initial-load-end'); } diff --git a/packages/ember/vendor/initial-load-head.js b/packages/ember/vendor/initial-load-head.js index 27152f5aa5ef..36260f8291ad 100644 --- a/packages/ember/vendor/initial-load-head.js +++ b/packages/ember/vendor/initial-load-head.js @@ -1,3 +1,3 @@ -if (window.performance && window.performance.mark) { +if (window.performance?.mark) { window.performance.mark('@sentry/ember:initial-load-start'); } diff --git a/packages/feedback/src/modal/integration.tsx b/packages/feedback/src/modal/integration.tsx index 1d6ece04eff4..bd8b9b84f148 100644 --- a/packages/feedback/src/modal/integration.tsx +++ b/packages/feedback/src/modal/integration.tsx @@ -50,7 +50,7 @@ export const feedbackModalIntegration = ((): FeedbackModalIntegration => { }, open() { renderContent(true); - options.onFormOpen && options.onFormOpen(); + options.onFormOpen?.(); originalOverflow = DOCUMENT.body.style.overflow; DOCUMENT.body.style.overflow = 'hidden'; }, @@ -73,18 +73,18 @@ export const feedbackModalIntegration = ((): FeedbackModalIntegration => { defaultEmail={(userKey && user && user[userKey.email]) || ''} onFormClose={() => { renderContent(false); - options.onFormClose && options.onFormClose(); + options.onFormClose?.(); }} onSubmit={sendFeedback} onSubmitSuccess={(data: FeedbackFormData) => { renderContent(false); - options.onSubmitSuccess && options.onSubmitSuccess(data); + options.onSubmitSuccess?.(data); }} onSubmitError={(error: Error) => { - options.onSubmitError && options.onSubmitError(error); + options.onSubmitError?.(error); }} onFormSubmitted={() => { - options.onFormSubmitted && options.onFormSubmitted(); + options.onFormSubmitted?.(); }} open={open} />, diff --git a/packages/feedback/src/util/mergeOptions.ts b/packages/feedback/src/util/mergeOptions.ts index c3a0c0508fcd..6a7ce49bd79a 100644 --- a/packages/feedback/src/util/mergeOptions.ts +++ b/packages/feedback/src/util/mergeOptions.ts @@ -16,24 +16,24 @@ export function mergeOptions( ...optionOverrides.tags, }, onFormOpen: () => { - optionOverrides.onFormOpen && optionOverrides.onFormOpen(); - defaultOptions.onFormOpen && defaultOptions.onFormOpen(); + optionOverrides.onFormOpen?.(); + defaultOptions.onFormOpen?.(); }, onFormClose: () => { - optionOverrides.onFormClose && optionOverrides.onFormClose(); - defaultOptions.onFormClose && defaultOptions.onFormClose(); + optionOverrides.onFormClose?.(); + defaultOptions.onFormClose?.(); }, onSubmitSuccess: (data: FeedbackFormData) => { - optionOverrides.onSubmitSuccess && optionOverrides.onSubmitSuccess(data); - defaultOptions.onSubmitSuccess && defaultOptions.onSubmitSuccess(data); + optionOverrides.onSubmitSuccess?.(data); + defaultOptions.onSubmitSuccess?.(data); }, onSubmitError: (error: Error) => { - optionOverrides.onSubmitError && optionOverrides.onSubmitError(error); - defaultOptions.onSubmitError && defaultOptions.onSubmitError(error); + optionOverrides.onSubmitError?.(error); + defaultOptions.onSubmitError?.(error); }, onFormSubmitted: () => { - optionOverrides.onFormSubmitted && optionOverrides.onFormSubmitted(); - defaultOptions.onFormSubmitted && defaultOptions.onFormSubmitted(); + optionOverrides.onFormSubmitted?.(); + defaultOptions.onFormSubmitted?.(); }, themeDark: { ...defaultOptions.themeDark, diff --git a/packages/google-cloud-serverless/src/integrations/google-cloud-grpc.ts b/packages/google-cloud-serverless/src/integrations/google-cloud-grpc.ts index 4f658c6e92e5..7d4c49990af6 100644 --- a/packages/google-cloud-serverless/src/integrations/google-cloud-grpc.ts +++ b/packages/google-cloud-serverless/src/integrations/google-cloud-grpc.ts @@ -124,5 +124,5 @@ function fillGrpcFunction(stub: Stub, serviceIdentifier: string, methodName: str /** Identifies service by its address */ function identifyService(servicePath: string): string { const match = servicePath.match(SERVICE_PATH_REGEX); - return match && match[1] ? match[1] : servicePath; + return match?.[1] || servicePath; } diff --git a/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts b/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts index 820f2df49381..44f943933049 100644 --- a/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts +++ b/packages/google-cloud-serverless/src/integrations/google-cloud-http.ts @@ -70,5 +70,5 @@ function wrapRequestFunction(orig: RequestFunction): RequestFunction { /** Identifies service by its base url */ function identifyService(apiEndpoint: string): string { const match = apiEndpoint.match(/^https:\/\/(\w+)\.googleapis.com$/); - return match && match[1] ? match[1] : apiEndpoint.replace(/^(http|https)?:\/\//, ''); + return match?.[1] || apiEndpoint.replace(/^(http|https)?:\/\//, ''); } diff --git a/packages/nextjs/src/client/clientNormalizationIntegration.ts b/packages/nextjs/src/client/clientNormalizationIntegration.ts index 06f010c980c9..e4bbb4881bc3 100644 --- a/packages/nextjs/src/client/clientNormalizationIntegration.ts +++ b/packages/nextjs/src/client/clientNormalizationIntegration.ts @@ -15,13 +15,12 @@ export const nextjsClientStackFrameNormalizationIntegration = defineIntegration( // We need to URI-decode the filename because Next.js has wildcard routes like "/users/[id].js" which show up as "/users/%5id%5.js" in Error stacktraces. // The corresponding sources that Next.js generates have proper brackets so we also need proper brackets in the frame so that source map resolving works. - if (frame.filename && frame.filename.startsWith('app:///_next')) { + if (frame.filename?.startsWith('app:///_next')) { frame.filename = decodeURI(frame.filename); } if ( - frame.filename && - frame.filename.match( + frame.filename?.match( /^app:\/\/\/_next\/static\/chunks\/(main-|main-app-|polyfills-|webpack-|framework-|framework\.)[0-9a-f]+\.js$/, ) ) { diff --git a/packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts b/packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts index c14cb2917723..11e48b3cec40 100644 --- a/packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts +++ b/packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts @@ -113,7 +113,7 @@ export function pagesRouterInstrumentPageLoad(client: Client): void { let name = route || globalObject.location.pathname; // /_error is the fallback page for all errors. If there is a transaction name for /_error, use that instead - if (parsedBaggage && parsedBaggage['sentry-transaction'] && name === '/_error') { + if (parsedBaggage?.['sentry-transaction'] && name === '/_error') { name = parsedBaggage['sentry-transaction']; // Strip any HTTP method from the span name name = name.replace(/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS|TRACE|CONNECT)\s+/i, ''); @@ -172,7 +172,7 @@ export function pagesRouterInstrumentNavigation(client: Client): void { } function getNextRouteFromPathname(pathname: string): string | undefined { - const pageRoutes = (globalObject.__BUILD_MANIFEST || {}).sortedPages; + const pageRoutes = globalObject.__BUILD_MANIFEST?.sortedPages; // Page route should in 99.999% of the cases be defined by now but just to be sure we make a check here if (!pageRoutes) { diff --git a/packages/nextjs/src/common/devErrorSymbolicationEventProcessor.ts b/packages/nextjs/src/common/devErrorSymbolicationEventProcessor.ts index 61365b180d77..b6851f18f3fa 100644 --- a/packages/nextjs/src/common/devErrorSymbolicationEventProcessor.ts +++ b/packages/nextjs/src/common/devErrorSymbolicationEventProcessor.ts @@ -149,7 +149,7 @@ export async function devErrorSymbolicationEventProcessor(event: Event, hint: Ev event.exception.values[0].stacktrace.frames = event.exception.values[0].stacktrace.frames.map( (frame, i, frames) => { const resolvedFrame = resolvedFrames[frames.length - 1 - i]; - if (!resolvedFrame || !resolvedFrame.originalStackFrame || !resolvedFrame.originalCodeFrame) { + if (!resolvedFrame?.originalStackFrame || !resolvedFrame.originalCodeFrame) { return { ...frame, platform: frame.filename?.startsWith('node:internal') ? 'nodejs' : undefined, // simple hack that will prevent a source mapping error from showing up diff --git a/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentryVercelCrons.ts b/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentryVercelCrons.ts index 5ca29b338cda..9a89350289d4 100644 --- a/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentryVercelCrons.ts +++ b/packages/nextjs/src/common/pages-router-instrumentation/wrapApiHandlerWithSentryVercelCrons.ts @@ -19,7 +19,7 @@ export function wrapApiHandlerWithSentryVercelCrons { - if (!args || !args[0]) { + if (!args?.[0]) { return originalFunction.apply(thisArg, args); } @@ -38,7 +38,7 @@ export function wrapApiHandlerWithSentryVercelCrons vercelCron.path === cronsKey); - if (!vercelCron || !vercelCron.path || !vercelCron.schedule) { + if (!vercelCron?.path || !vercelCron.schedule) { return originalFunction.apply(thisArg, args); } diff --git a/packages/nextjs/src/config/loaders/wrappingLoader.ts b/packages/nextjs/src/config/loaders/wrappingLoader.ts index 324dd1b1b1ad..422dbd1fd2aa 100644 --- a/packages/nextjs/src/config/loaders/wrappingLoader.ts +++ b/packages/nextjs/src/config/loaders/wrappingLoader.ts @@ -187,7 +187,7 @@ export default function wrappingLoader( // eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor .match(new RegExp(`(?:^|/)?([^/]+)\\.(?:${pageExtensionRegex})$`)); - if (componentTypeMatch && componentTypeMatch[1]) { + if (componentTypeMatch?.[1]) { let componentType: ServerComponentContext['componentType']; switch (componentTypeMatch[1]) { case 'page': diff --git a/packages/nitro-utils/src/rollupPlugins/wrapServerEntryWithDynamicImport.ts b/packages/nitro-utils/src/rollupPlugins/wrapServerEntryWithDynamicImport.ts index 480256507081..58b838741c32 100644 --- a/packages/nitro-utils/src/rollupPlugins/wrapServerEntryWithDynamicImport.ts +++ b/packages/nitro-utils/src/rollupPlugins/wrapServerEntryWithDynamicImport.ts @@ -144,22 +144,18 @@ export function extractFunctionReexportQueryParameters(query: string): { wrap: s const reexportMatch = query.match(reexportRegex); const wrap = - wrapMatch && wrapMatch[1] - ? wrapMatch[1] - .split(',') - .filter(param => param !== '') - // Sanitize, as code could be injected with another rollup plugin - .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) - : []; + wrapMatch?.[1] + ?.split(',') + .filter(param => param !== '') + // Sanitize, as code could be injected with another rollup plugin + .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) || []; const reexport = - reexportMatch && reexportMatch[1] - ? reexportMatch[1] - .split(',') - .filter(param => param !== '' && param !== 'default') - // Sanitize, as code could be injected with another rollup plugin - .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) - : []; + reexportMatch?.[1] + ?.split(',') + .filter(param => param !== '' && param !== 'default') + // Sanitize, as code could be injected with another rollup plugin + .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) || []; return { wrap, reexport }; } diff --git a/packages/node/src/integrations/context.ts b/packages/node/src/integrations/context.ts index 092d358f640f..ed3e265b952b 100644 --- a/packages/node/src/integrations/context.ts +++ b/packages/node/src/integrations/context.ts @@ -247,7 +247,7 @@ export function getDeviceContext(deviceOpt: DeviceContextOptions | true): Device if (deviceOpt === true || deviceOpt.cpu) { const cpuInfo = os.cpus() as os.CpuInfo[] | undefined; - const firstCpu = cpuInfo && cpuInfo[0]; + const firstCpu = cpuInfo?.[0]; if (firstCpu) { device.processor_count = cpuInfo.length; device.cpu_description = firstCpu.model; diff --git a/packages/node/src/integrations/contextlines.ts b/packages/node/src/integrations/contextlines.ts index 5e1bd75913c9..dd9929dc29a6 100644 --- a/packages/node/src/integrations/contextlines.ts +++ b/packages/node/src/integrations/contextlines.ts @@ -280,7 +280,7 @@ async function addSourceContext(event: Event, contextLines: number): Promise 0 && event.exception?.values) { for (const exception of event.exception.values) { - if (exception.stacktrace && exception.stacktrace.frames && exception.stacktrace.frames.length > 0) { + if (exception.stacktrace?.frames && exception.stacktrace.frames.length > 0) { addSourceContextToFrames(exception.stacktrace.frames, contextLines, LRU_FILE_CONTENTS_CACHE); } } diff --git a/packages/node/src/integrations/http/index.ts b/packages/node/src/integrations/http/index.ts index b63754bb017f..d48a36bf4bc0 100644 --- a/packages/node/src/integrations/http/index.ts +++ b/packages/node/src/integrations/http/index.ts @@ -190,7 +190,7 @@ function getConfigWithDefaults(options: Partial = {}): HttpInstrume } const _ignoreOutgoingRequests = options.ignoreOutgoingRequests; - if (_ignoreOutgoingRequests && _ignoreOutgoingRequests(url, request)) { + if (_ignoreOutgoingRequests?.(url, request)) { return true; } @@ -209,7 +209,7 @@ function getConfigWithDefaults(options: Partial = {}): HttpInstrume } const _ignoreIncomingRequests = options.ignoreIncomingRequests; - if (urlPath && _ignoreIncomingRequests && _ignoreIncomingRequests(urlPath, request)) { + if (urlPath && _ignoreIncomingRequests?.(urlPath, request)) { return true; } diff --git a/packages/node/src/integrations/modules.ts b/packages/node/src/integrations/modules.ts index f3c187589de1..e15aa9dd245b 100644 --- a/packages/node/src/integrations/modules.ts +++ b/packages/node/src/integrations/modules.ts @@ -54,7 +54,7 @@ function getPaths(): string[] { function collectModules(): { [name: string]: string; } { - const mainPaths = (require.main && require.main.paths) || []; + const mainPaths = require.main?.paths || []; const paths = getPaths(); const infos: { [name: string]: string; diff --git a/packages/node/src/integrations/tracing/express.ts b/packages/node/src/integrations/tracing/express.ts index b89665844e4f..13f50cff0202 100644 --- a/packages/node/src/integrations/tracing/express.ts +++ b/packages/node/src/integrations/tracing/express.ts @@ -180,7 +180,7 @@ export function setupExpressErrorHandler( } function getStatusCodeFromResponse(error: MiddlewareError): number { - const statusCode = error.status || error.statusCode || error.status_code || (error.output && error.output.statusCode); + const statusCode = error.status || error.statusCode || error.status_code || error.output?.statusCode; return statusCode ? parseInt(statusCode as string, 10) : 500; } diff --git a/packages/node/src/integrations/tracing/koa.ts b/packages/node/src/integrations/tracing/koa.ts index 944d9d3bd065..527a53ee9007 100644 --- a/packages/node/src/integrations/tracing/koa.ts +++ b/packages/node/src/integrations/tracing/koa.ts @@ -29,7 +29,7 @@ export const instrumentKoa = generateInstrumentOnce( return; } const attributes = spanToJSON(span).data; - const route = attributes && attributes[ATTR_HTTP_ROUTE]; + const route = attributes[ATTR_HTTP_ROUTE]; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const method = info.context?.request?.method?.toUpperCase() || 'GET'; if (route) { diff --git a/packages/node/src/sdk/api.ts b/packages/node/src/sdk/api.ts index 7e4f200d1e06..b014a5f0b806 100644 --- a/packages/node/src/sdk/api.ts +++ b/packages/node/src/sdk/api.ts @@ -15,7 +15,7 @@ export function getSentryRelease(fallback?: string): string | undefined { } // This supports the variable that sentry-webpack-plugin injects - if (GLOBAL_OBJ.SENTRY_RELEASE && GLOBAL_OBJ.SENTRY_RELEASE.id) { + if (GLOBAL_OBJ.SENTRY_RELEASE?.id) { return GLOBAL_OBJ.SENTRY_RELEASE.id; } diff --git a/packages/node/src/sdk/index.ts b/packages/node/src/sdk/index.ts index 354cd56990bf..7592688fdc5e 100644 --- a/packages/node/src/sdk/index.ts +++ b/packages/node/src/sdk/index.ts @@ -319,7 +319,7 @@ function trackSessionForProcess(): void { // Terminal Status i.e. Exited or Crashed because // "When a session is moved away from ok it must not be updated anymore." // Ref: https://develop.sentry.dev/sdk/sessions/ - if (session && session.status !== 'ok') { + if (session?.status !== 'ok') { endSession(); } }); diff --git a/packages/node/src/transports/http.ts b/packages/node/src/transports/http.ts index 39211c281d50..a6024dc53de5 100644 --- a/packages/node/src/transports/http.ts +++ b/packages/node/src/transports/http.ts @@ -92,13 +92,11 @@ export function makeNodeTransport(options: NodeTransportOptions): Transport { function applyNoProxyOption(transportUrlSegments: URL, proxy: string | undefined): string | undefined { const { no_proxy } = process.env; - const urlIsExemptFromProxy = - no_proxy && - no_proxy - .split(',') - .some( - exemption => transportUrlSegments.host.endsWith(exemption) || transportUrlSegments.hostname.endsWith(exemption), - ); + const urlIsExemptFromProxy = no_proxy + ?.split(',') + .some( + exemption => transportUrlSegments.host.endsWith(exemption) || transportUrlSegments.hostname.endsWith(exemption), + ); if (urlIsExemptFromProxy) { return undefined; diff --git a/packages/nuxt/src/runtime/plugins/sentry.server.ts b/packages/nuxt/src/runtime/plugins/sentry.server.ts index b748115f5c81..ec2678e8e7c7 100644 --- a/packages/nuxt/src/runtime/plugins/sentry.server.ts +++ b/packages/nuxt/src/runtime/plugins/sentry.server.ts @@ -27,8 +27,8 @@ export default defineNitroPlugin(nitroApp => { } const { method, path } = { - method: errorContext.event && errorContext.event._method ? errorContext.event._method : '', - path: errorContext.event && errorContext.event._path ? errorContext.event._path : null, + method: errorContext.event?._method ? errorContext.event._method : '', + path: errorContext.event?._path ? errorContext.event._path : null, }; if (path) { diff --git a/packages/nuxt/src/runtime/utils.ts b/packages/nuxt/src/runtime/utils.ts index c4e3091a19e2..23bac2486b74 100644 --- a/packages/nuxt/src/runtime/utils.ts +++ b/packages/nuxt/src/runtime/utils.ts @@ -61,7 +61,7 @@ export function reportNuxtError(options: { // todo: add component name and trace (like in the vue integration) }; - if (instance && instance.$props) { + if (instance?.$props) { const sentryClient = getClient(); const sentryOptions = sentryClient ? (sentryClient.getOptions() as ClientOptions & VueOptions) : null; diff --git a/packages/nuxt/src/vite/utils.ts b/packages/nuxt/src/vite/utils.ts index 85696f76f6ae..59da97499550 100644 --- a/packages/nuxt/src/vite/utils.ts +++ b/packages/nuxt/src/vite/utils.ts @@ -71,22 +71,18 @@ export function extractFunctionReexportQueryParameters(query: string): { wrap: s const reexportMatch = query.match(reexportRegex); const wrap = - wrapMatch && wrapMatch[1] - ? wrapMatch[1] - .split(',') - .filter(param => param !== '') - // Sanitize, as code could be injected with another rollup plugin - .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) - : []; + wrapMatch?.[1] + ?.split(',') + .filter(param => param !== '') + // Sanitize, as code could be injected with another rollup plugin + .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) || []; const reexport = - reexportMatch && reexportMatch[1] - ? reexportMatch[1] - .split(',') - .filter(param => param !== '' && param !== 'default') - // Sanitize, as code could be injected with another rollup plugin - .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) - : []; + reexportMatch?.[1] + ?.split(',') + .filter(param => param !== '' && param !== 'default') + // Sanitize, as code could be injected with another rollup plugin + .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) || []; return { wrap, reexport }; } diff --git a/packages/profiling-node/src/integration.ts b/packages/profiling-node/src/integration.ts index c9b9fe12056d..f4a860d035f0 100644 --- a/packages/profiling-node/src/integration.ts +++ b/packages/profiling-node/src/integration.ts @@ -62,8 +62,7 @@ function setupAutomatedSpanProfiling(client: NodeClient): void { const options = client.getOptions(); // Not intended for external use, hence missing types, but we want to profile a couple of things at Sentry that // currently exceed the default timeout set by the SDKs. - const maxProfileDurationMs = - (options._experiments && options._experiments['maxProfileDurationMs']) || MAX_PROFILE_DURATION_MS; + const maxProfileDurationMs = options._experiments?.maxProfileDurationMs || MAX_PROFILE_DURATION_MS; if (PROFILE_TIMEOUTS[profile_id]) { global.clearTimeout(PROFILE_TIMEOUTS[profile_id]); diff --git a/packages/profiling-node/src/utils.ts b/packages/profiling-node/src/utils.ts index 78844af5fa8e..baf3370d6ce8 100644 --- a/packages/profiling-node/src/utils.ts +++ b/packages/profiling-node/src/utils.ts @@ -134,7 +134,7 @@ function createProfilePayload( // Log a warning if the profile has an invalid traceId (should be uuidv4). // All profiles and transactions are rejected if this is the case and we want to // warn users that this is happening if they enable debug flag - if (trace_id && trace_id.length !== 32) { + if (trace_id?.length !== 32) { DEBUG_BUILD && logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`); } @@ -207,7 +207,7 @@ function createProfileChunkPayload( // Log a warning if the profile has an invalid traceId (should be uuidv4). // All profiles and transactions are rejected if this is the case and we want to // warn users that this is happening if they enable debug flag - if (trace_id && trace_id.length !== 32) { + if (trace_id?.length !== 32) { DEBUG_BUILD && logger.log(`[Profiling] Invalid traceId: ${trace_id} on profiled event`); } @@ -423,7 +423,7 @@ export function makeProfileChunkEnvelope( export function applyDebugMetadata(client: Client, resource_paths: ReadonlyArray): DebugImage[] { const options = client.getOptions(); - if (!options || !options.stackParser) { + if (!options?.stackParser) { return []; } diff --git a/packages/profiling-node/test/cpu_profiler.test.ts b/packages/profiling-node/test/cpu_profiler.test.ts index d1dfd781e227..9240ad636129 100644 --- a/packages/profiling-node/test/cpu_profiler.test.ts +++ b/packages/profiling-node/test/cpu_profiler.test.ts @@ -335,7 +335,7 @@ describe('Profiler bindings', () => { }); // @ts-expect-error deopt reasons are disabled for now as we need to figure out the backend support - const hasDeoptimizedFrame = profile.frames.some(f => f.deopt_reasons && f.deopt_reasons.length > 0); + const hasDeoptimizedFrame = profile.frames.some(f => f.deopt_reasons?.length > 0); expect(hasDeoptimizedFrame).toBe(true); }); diff --git a/packages/react/src/reactrouterv3.ts b/packages/react/src/reactrouterv3.ts index ad3696b306d1..dc1ff26ed38b 100644 --- a/packages/react/src/reactrouterv3.ts +++ b/packages/react/src/reactrouterv3.ts @@ -145,7 +145,7 @@ function getRouteStringFromRoutes(routes: Route[]): string { for (let x = routesWithPaths.length - 1; x >= 0; x--) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const route = routesWithPaths[x]!; - if (route.path && route.path.startsWith('/')) { + if (route.path?.startsWith('/')) { index = x; break; } diff --git a/packages/react/src/reactrouterv6-compat-utils.tsx b/packages/react/src/reactrouterv6-compat-utils.tsx index 17ce3753bdbd..06de135dda40 100644 --- a/packages/react/src/reactrouterv6-compat-utils.tsx +++ b/packages/react/src/reactrouterv6-compat-utils.tsx @@ -330,11 +330,11 @@ function pathEndsWithWildcard(path: string): boolean { } function pathIsWildcardAndHasChildren(path: string, branch: RouteMatch): boolean { - return (pathEndsWithWildcard(path) && branch.route.children && branch.route.children.length > 0) || false; + return (pathEndsWithWildcard(path) && !!branch.route.children?.length) || false; } function routeIsDescendant(route: RouteObject): boolean { - return !!(!route.children && route.element && route.path && route.path.endsWith('/*')); + return !!(!route.children && route.element && route.path?.endsWith('/*')); } function locationIsInsideDescendantRoute(location: Location, routes: RouteObject[]): boolean { diff --git a/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts b/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts index 8a9d1518185f..5ab7e4b69e95 100644 --- a/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts +++ b/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts @@ -39,8 +39,8 @@ function handleTransactionEvent(replay: ReplayContainer, event: TransactionEvent // Collect traceIds in _context regardless of `recordingMode` // In error mode, _context gets cleared on every checkout // We limit to max. 100 transactions linked - if (event.contexts && event.contexts.trace && event.contexts.trace.trace_id && replayContext.traceIds.size < 100) { - replayContext.traceIds.add(event.contexts.trace.trace_id as string); + if (event.contexts?.trace?.trace_id && replayContext.traceIds.size < 100) { + replayContext.traceIds.add(event.contexts.trace.trace_id); } } diff --git a/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts b/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts index d3491dcb4db7..4d50066bc842 100644 --- a/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts +++ b/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts @@ -22,8 +22,7 @@ export function handleBeforeSendEvent(replay: ReplayContainer): BeforeSendEventC } function handleHydrationError(replay: ReplayContainer, event: ErrorEvent): void { - const exceptionValue = - event.exception && event.exception.values && event.exception.values[0] && event.exception.values[0].value; + const exceptionValue = event.exception?.values?.[0]?.value; if (typeof exceptionValue !== 'string') { return; } diff --git a/packages/replay-internal/src/coreHandlers/handleBreadcrumbs.ts b/packages/replay-internal/src/coreHandlers/handleBreadcrumbs.ts index f029fe0854fd..8257ebdb1044 100644 --- a/packages/replay-internal/src/coreHandlers/handleBreadcrumbs.ts +++ b/packages/replay-internal/src/coreHandlers/handleBreadcrumbs.ts @@ -61,7 +61,7 @@ export function normalizeBreadcrumb(breadcrumb: Breadcrumb): Breadcrumb | null { export function normalizeConsoleBreadcrumb( breadcrumb: Omit & BreadcrumbWithCategory, ): ReplayFrame { - const args = breadcrumb.data && breadcrumb.data.arguments; + const args = breadcrumb.data?.arguments; if (!Array.isArray(args) || args.length === 0) { return createBreadcrumb(breadcrumb); diff --git a/packages/replay-internal/src/integration.ts b/packages/replay-internal/src/integration.ts index 49383d9da3b7..c2a9206feb0d 100644 --- a/packages/replay-internal/src/integration.ts +++ b/packages/replay-internal/src/integration.ts @@ -280,7 +280,7 @@ export class Replay implements Integration { * Get the current session ID. */ public getReplayId(): string | undefined { - if (!this._replay || !this._replay.isEnabled()) { + if (!this._replay?.isEnabled()) { return; } @@ -296,7 +296,7 @@ export class Replay implements Integration { * - or calling `flush()` to send the replay */ public getRecordingMode(): ReplayRecordingMode | undefined { - if (!this._replay || !this._replay.isEnabled()) { + if (!this._replay?.isEnabled()) { return; } diff --git a/packages/replay-internal/src/replay.ts b/packages/replay-internal/src/replay.ts index 874a017b4f5e..7a19f1ea7070 100644 --- a/packages/replay-internal/src/replay.ts +++ b/packages/replay-internal/src/replay.ts @@ -518,7 +518,7 @@ export class ReplayContainer implements ReplayContainerInterface { } // After flush, destroy event buffer - this.eventBuffer && this.eventBuffer.destroy(); + this.eventBuffer?.destroy(); this.eventBuffer = null; // Clear session from session storage, note this means if a new session @@ -715,7 +715,7 @@ export class ReplayContainer implements ReplayContainerInterface { /** Get the current session (=replay) ID */ public getSessionId(): string | undefined { - return this.session && this.session.id; + return this.session?.id; } /** @@ -1144,7 +1144,7 @@ export class ReplayContainer implements ReplayContainerInterface { await this._addPerformanceEntries(); // Check eventBuffer again, as it could have been stopped in the meanwhile - if (!this.eventBuffer || !this.eventBuffer.hasEvents) { + if (!this.eventBuffer?.hasEvents) { return; } diff --git a/packages/replay-internal/src/util/addGlobalListeners.ts b/packages/replay-internal/src/util/addGlobalListeners.ts index df1c4475369e..f29ed4087d95 100644 --- a/packages/replay-internal/src/util/addGlobalListeners.ts +++ b/packages/replay-internal/src/util/addGlobalListeners.ts @@ -62,7 +62,7 @@ export function addGlobalListeners(replay: ReplayContainer): void { const replayId = replay.getSessionId(); if (options?.includeReplay && replay.isEnabled() && replayId) { // This should never reject - if (feedbackEvent.contexts && feedbackEvent.contexts.feedback) { + if (feedbackEvent.contexts?.feedback) { feedbackEvent.contexts.feedback.replay_id = replayId; } } diff --git a/packages/replay-internal/src/util/isRrwebError.ts b/packages/replay-internal/src/util/isRrwebError.ts index 275a93777b2e..3348d384d047 100644 --- a/packages/replay-internal/src/util/isRrwebError.ts +++ b/packages/replay-internal/src/util/isRrwebError.ts @@ -9,7 +9,7 @@ export function isRrwebError(event: Event, hint: EventHint): boolean { } // @ts-expect-error this may be set by rrweb when it finds errors - if (hint.originalException && hint.originalException.__rrweb__) { + if (hint.originalException?.__rrweb__) { return true; } diff --git a/packages/replay-internal/src/util/logger.ts b/packages/replay-internal/src/util/logger.ts index 4ee45c44309c..adf3130883dd 100644 --- a/packages/replay-internal/src/util/logger.ts +++ b/packages/replay-internal/src/util/logger.ts @@ -27,7 +27,7 @@ interface ReplayLogger extends LoggerConsoleMethods { /** * Configures the logger with additional debugging behavior */ - setConfig(config: LoggerConfig): void; + setConfig(config: Partial): void; } function _addBreadcrumb(message: unknown, level: SeverityLevel = 'info'): void { @@ -51,9 +51,9 @@ function makeReplayLogger(): ReplayLogger { const _logger: Partial = { exception: () => undefined, infoTick: () => undefined, - setConfig: (opts: LoggerConfig) => { - _capture = opts.captureExceptions; - _trace = opts.traceInternals; + setConfig: (opts: Partial) => { + _capture = !!opts.captureExceptions; + _trace = !!opts.traceInternals; }, }; diff --git a/packages/replay-internal/test/integration/flush.test.ts b/packages/replay-internal/test/integration/flush.test.ts index 11bb57a58b32..5de390581790 100644 --- a/packages/replay-internal/test/integration/flush.test.ts +++ b/packages/replay-internal/test/integration/flush.test.ts @@ -360,7 +360,7 @@ describe('Integration | flush', () => { expect(mockFlush).toHaveBeenCalledTimes(1); expect(mockSendReplay).toHaveBeenCalledTimes(1); - const replayData = mockSendReplay.mock.calls[0][0]; + const replayData = mockSendReplay.mock.calls?.[0]?.[0] as SentryUtils.ReplayRecordingData; expect(JSON.parse(replayData.recordingData)).toEqual([ { @@ -509,28 +509,28 @@ describe('Integration | flush', () => { }); it('resets flush lock when flush is called multiple times before it resolves', async () => { - let _resolve; + let _resolve: undefined | (() => void); mockRunFlush.mockImplementation( () => new Promise(resolve => { _resolve = resolve; }), ); - const mockDebouncedFlush: MockedFunction = vi.spyOn(replay, '_debouncedFlush'); + const mockDebouncedFlush = vi.spyOn(replay, '_debouncedFlush'); mockDebouncedFlush.mockImplementation(vi.fn); mockDebouncedFlush.cancel = vi.fn(); const results = [replay['_flush'](), replay['_flush']()]; expect(replay['_flushLock']).not.toBeUndefined(); - _resolve && _resolve(); + _resolve?.(); await Promise.all(results); expect(replay['_flushLock']).toBeUndefined(); mockDebouncedFlush.mockRestore(); }); it('resets flush lock when flush is called multiple times before it rejects', async () => { - let _reject; + let _reject: undefined | ((error: Error) => void); mockRunFlush.mockImplementation( () => new Promise((_, reject) => { @@ -545,7 +545,7 @@ describe('Integration | flush', () => { const result = replay['_flush'](); expect(replay['_flushLock']).not.toBeUndefined(); - _reject && _reject(new Error('Throw runFlush')); + _reject?.(new Error('Throw runFlush')); await result; expect(replay['_flushLock']).toBeUndefined(); mockDebouncedFlush.mockRestore(); diff --git a/packages/solidstart/src/config/utils.ts b/packages/solidstart/src/config/utils.ts index fd4b70d508d0..f0f11b4d4baa 100644 --- a/packages/solidstart/src/config/utils.ts +++ b/packages/solidstart/src/config/utils.ts @@ -34,22 +34,18 @@ export function extractFunctionReexportQueryParameters(query: string): { wrap: s const reexportMatch = query.match(reexportRegex); const wrap = - wrapMatch && wrapMatch[1] - ? wrapMatch[1] - .split(',') - .filter(param => param !== '') - // Sanitize, as code could be injected with another rollup plugin - .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) - : []; + wrapMatch?.[1] + ?.split(',') + .filter(param => param !== '') + // Sanitize, as code could be injected with another rollup plugin + .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) || []; const reexport = - reexportMatch && reexportMatch[1] - ? reexportMatch[1] - .split(',') - .filter(param => param !== '' && param !== 'default') - // Sanitize, as code could be injected with another rollup plugin - .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) - : []; + reexportMatch?.[1] + ?.split(',') + .filter(param => param !== '' && param !== 'default') + // Sanitize, as code could be injected with another rollup plugin + .map((str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) || []; return { wrap, reexport }; } diff --git a/packages/svelte/src/config.ts b/packages/svelte/src/config.ts index 4c265ad57fc7..b4a0ae7d4f35 100644 --- a/packages/svelte/src/config.ts +++ b/packages/svelte/src/config.ts @@ -31,7 +31,7 @@ export function withSentryConfig( // see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map const sentryPreprocessors = new Map(); - const shouldTrackComponents = mergedOptions.componentTracking && mergedOptions.componentTracking.trackComponents; + const shouldTrackComponents = mergedOptions.componentTracking?.trackComponents; if (shouldTrackComponents) { const firstPassPreproc: SentryPreprocessorGroup = componentTrackingPreprocessor(mergedOptions.componentTracking); sentryPreprocessors.set(firstPassPreproc.sentryId || '', firstPassPreproc); diff --git a/packages/svelte/test/preprocessors.test.ts b/packages/svelte/test/preprocessors.test.ts index 0420f9ec2286..f816c67e706c 100644 --- a/packages/svelte/test/preprocessors.test.ts +++ b/packages/svelte/test/preprocessors.test.ts @@ -60,14 +60,12 @@ describe('componentTrackingPreprocessor', () => { ]; const preprocessedComponents = components.map(cmp => { - const res: any = - preProc.script && - preProc.script({ - content: cmp.originalCode, - filename: cmp.filename, - attributes: {}, - markup: '', - }); + const res: any = preProc.script?.({ + content: cmp.originalCode, + filename: cmp.filename, + attributes: {}, + markup: '', + }); return { ...cmp, newCode: res.code, map: res.map }; }); @@ -83,14 +81,12 @@ describe('componentTrackingPreprocessor', () => { ]; const preprocessedComponents = components.map(cmp => { - const res: any = - preProc.script && - preProc.script({ - content: cmp.originalCode, - filename: cmp.filename, - attributes: {}, - markup: '', - }); + const res: any = preProc.script?.({ + content: cmp.originalCode, + filename: cmp.filename, + attributes: {}, + markup: '', + }); return { ...cmp, newCode: res.code, map: res.map }; }); @@ -108,14 +104,12 @@ describe('componentTrackingPreprocessor', () => { ]; const [cmp1, cmp2, cmp3] = components.map(cmp => { - const res: any = - preProc.script && - preProc.script({ - content: cmp.originalCode, - filename: cmp.filename, - attributes: {}, - markup: '', - }); + const res: any = preProc.script?.({ + content: cmp.originalCode, + filename: cmp.filename, + attributes: {}, + markup: '', + }); return { ...cmp, newCode: res.code, map: res.map }; }); @@ -146,14 +140,12 @@ describe('componentTrackingPreprocessor', () => { ]; const [cmp11, cmp12, cmp2] = components.map(cmp => { - const res: any = - preProc.script && - preProc.script({ - content: cmp.originalCode, - filename: cmp.filename, - attributes: {}, - markup: '', - }); + const res: any = preProc.script?.({ + content: cmp.originalCode, + filename: cmp.filename, + attributes: {}, + markup: '', + }); return { ...cmp, newCode: res.code, map: res.map }; }); @@ -169,14 +161,12 @@ describe('componentTrackingPreprocessor', () => { name: 'Cmp2', }; - const res: any = - preProc.script && - preProc.script({ - content: component.originalCode, - filename: component.filename, - attributes: { context: 'module' }, - markup: '', - }); + const res: any = preProc.script?.({ + content: component.originalCode, + filename: component.filename, + attributes: { context: 'module' }, + markup: '', + }); const processedComponent = { ...component, newCode: res.code, map: res.map }; @@ -193,12 +183,10 @@ describe('componentTrackingPreprocessor', () => { name: 'Cmp2', }; - const res: any = - preProc.markup && - preProc.markup({ - content: component.originalCode, - filename: component.filename, - }); + const res: any = preProc.markup?.({ + content: component.originalCode, + filename: component.filename, + }); expect(res.code).toEqual( "\n

I'm just a plain component

\n", @@ -214,12 +202,10 @@ describe('componentTrackingPreprocessor', () => { name: 'Cmp2', }; - const res: any = - preProc.markup && - preProc.markup({ - content: component.originalCode, - filename: component.filename, - }); + const res: any = preProc.markup?.({ + content: component.originalCode, + filename: component.filename, + }); expect(res.code).toEqual( "\n

I'm a component with a script

\n", diff --git a/packages/svelte/test/sdk.test.ts b/packages/svelte/test/sdk.test.ts index 02d01d27fae9..aab3641379e2 100644 --- a/packages/svelte/test/sdk.test.ts +++ b/packages/svelte/test/sdk.test.ts @@ -104,7 +104,7 @@ describe('detectAndReportSvelteKit()', () => { document.body.innerHTML += '
Home
'; detectAndReportSvelteKit(); - const processedEvent = passedEventProcessor && passedEventProcessor({} as unknown as any, {}); + const processedEvent = passedEventProcessor?.({} as unknown as any, {}); expect(processedEvent).toBeDefined(); expect(processedEvent).toEqual({ modules: { svelteKit: 'latest' } }); @@ -114,7 +114,7 @@ describe('detectAndReportSvelteKit()', () => { document.body.innerHTML = ''; detectAndReportSvelteKit(); - const processedEvent = passedEventProcessor && passedEventProcessor({} as unknown as any, {}); + const processedEvent = passedEventProcessor?.({} as unknown as any, {}); expect(processedEvent).toBeDefined(); expect(processedEvent).toEqual({}); diff --git a/packages/sveltekit/src/client/browserTracingIntegration.ts b/packages/sveltekit/src/client/browserTracingIntegration.ts index 9148bb3bcd29..3659014a9be1 100644 --- a/packages/sveltekit/src/client/browserTracingIntegration.ts +++ b/packages/sveltekit/src/client/browserTracingIntegration.ts @@ -60,7 +60,7 @@ function _instrumentPageload(client: Client): void { return; } - const routeId = page.route && page.route.id; + const routeId = page.route?.id; if (routeId) { pageloadSpan.updateName(routeId); diff --git a/packages/sveltekit/src/server/handleError.ts b/packages/sveltekit/src/server/handleError.ts index 41605c014e51..30ca4e28de1a 100644 --- a/packages/sveltekit/src/server/handleError.ts +++ b/packages/sveltekit/src/server/handleError.ts @@ -66,7 +66,7 @@ function isNotFoundError(input: SafeHandleServerErrorInput): boolean { // SvelteKit 1.x doesn't offer a reliable way to check for a Not Found error. // So we check the route id (shouldn't exist) and the raw stack trace // We can delete all of this below whenever we drop Kit 1.x support - const hasNoRouteId = !event.route || !event.route.id; + const hasNoRouteId = !event.route?.id; const rawStack: string = (error != null && diff --git a/packages/sveltekit/src/server/load.ts b/packages/sveltekit/src/server/load.ts index c4a67eaf3482..30fab345e05b 100644 --- a/packages/sveltekit/src/server/load.ts +++ b/packages/sveltekit/src/server/load.ts @@ -29,7 +29,7 @@ export function wrapLoadWithSentry any>(origLoad: T) addNonEnumerableProperty(event as unknown as Record, '__sentry_wrapped__', true); - const routeId = event.route && event.route.id; + const routeId = event.route?.id; try { // We need to await before returning, otherwise we won't catch any errors thrown by the load function diff --git a/packages/sveltekit/src/server/serverRoute.ts b/packages/sveltekit/src/server/serverRoute.ts index dbf930ce1180..9d2cba3dbcdc 100644 --- a/packages/sveltekit/src/server/serverRoute.ts +++ b/packages/sveltekit/src/server/serverRoute.ts @@ -38,7 +38,7 @@ export function wrapServerRouteWithSentry( return wrappingTarget.apply(thisArg, args); } - const routeId = event.route && event.route.id; + const routeId = event.route?.id; const httpMethod = event.request.method; addNonEnumerableProperty(event as unknown as Record, '__sentry_wrapped__', true); diff --git a/packages/sveltekit/src/vite/autoInstrument.ts b/packages/sveltekit/src/vite/autoInstrument.ts index 7194a3ae3ac8..1e11f2f61500 100644 --- a/packages/sveltekit/src/vite/autoInstrument.ts +++ b/packages/sveltekit/src/vite/autoInstrument.ts @@ -115,13 +115,13 @@ export async function canWrapLoad(id: string, debug: boolean): Promise .filter((statement): statement is ExportNamedDeclaration => statement.type === 'ExportNamedDeclaration') .find(exportDecl => { // find `export const load = ...` - if (exportDecl.declaration && exportDecl.declaration.type === 'VariableDeclaration') { + if (exportDecl.declaration?.type === 'VariableDeclaration') { const variableDeclarations = exportDecl.declaration.declarations; return variableDeclarations.find(decl => decl.id.type === 'Identifier' && decl.id.name === 'load'); } // find `export function load = ...` - if (exportDecl.declaration && exportDecl.declaration.type === 'FunctionDeclaration') { + if (exportDecl.declaration?.type === 'FunctionDeclaration') { const functionId = exportDecl.declaration.id; return functionId?.name === 'load'; } diff --git a/packages/vercel-edge/src/sdk.ts b/packages/vercel-edge/src/sdk.ts index 8e09b3aa189e..fb6c524df4b4 100644 --- a/packages/vercel-edge/src/sdk.ts +++ b/packages/vercel-edge/src/sdk.ts @@ -205,7 +205,7 @@ export function getSentryRelease(fallback?: string): string | undefined { } // This supports the variable that sentry-webpack-plugin injects - if (GLOBAL_OBJ.SENTRY_RELEASE && GLOBAL_OBJ.SENTRY_RELEASE.id) { + if (GLOBAL_OBJ.SENTRY_RELEASE?.id) { return GLOBAL_OBJ.SENTRY_RELEASE.id; } diff --git a/packages/vue/src/errorhandler.ts b/packages/vue/src/errorhandler.ts index 3f011d281095..c3dc88deb00f 100644 --- a/packages/vue/src/errorhandler.ts +++ b/packages/vue/src/errorhandler.ts @@ -19,7 +19,7 @@ export const attachErrorHandler = (app: Vue, options: VueOptions): void => { if (options.attachProps && vm) { // Vue2 - $options.propsData // Vue3 - $props - if (vm.$options && vm.$options.propsData) { + if (vm.$options?.propsData) { metadata.propsData = vm.$options.propsData; } else if (vm.$props) { metadata.propsData = vm.$props; diff --git a/packages/vue/src/integration.ts b/packages/vue/src/integration.ts index c3ee8baaa03f..93fe25aee3d9 100644 --- a/packages/vue/src/integration.ts +++ b/packages/vue/src/integration.ts @@ -59,7 +59,7 @@ const vueInit = (app: Vue, options: Options): void => { }; }; - const isMounted = appWithInstance._instance && appWithInstance._instance.isMounted; + const isMounted = appWithInstance._instance?.isMounted; if (isMounted === true) { consoleSandbox(() => { // eslint-disable-next-line no-console diff --git a/packages/vue/src/tracing.ts b/packages/vue/src/tracing.ts index 3ece35d9fe5d..65053bddc5c6 100644 --- a/packages/vue/src/tracing.ts +++ b/packages/vue/src/tracing.ts @@ -39,7 +39,7 @@ function finishRootSpan(vm: VueSentry, timestamp: number, timeout: number): void } vm.$_sentryRootSpanTimer = setTimeout(() => { - if (vm.$root && vm.$root.$_sentryRootSpan) { + if (vm.$root?.$_sentryRootSpan) { vm.$root.$_sentryRootSpan.end(timestamp); vm.$root.$_sentryRootSpan = undefined; } @@ -110,7 +110,7 @@ export const createTracingMixins = (options: Partial = {}): Mixi // Start a new span if current hook is a 'before' hook. // Otherwise, retrieve the current span and finish it. if (internalHook == internalHooks[0]) { - const activeSpan = (this.$root && this.$root.$_sentryRootSpan) || getActiveSpan(); + const activeSpan = this.$root?.$_sentryRootSpan || getActiveSpan(); if (activeSpan) { // Cancel old span for this hook operation in case it didn't get cleaned up. We're not actually sure if it // will ever be the case that cleanup hooks re not called, but we had users report that spans didn't get diff --git a/packages/wasm/src/index.ts b/packages/wasm/src/index.ts index adad9fa35480..a7f2db7d3828 100644 --- a/packages/wasm/src/index.ts +++ b/packages/wasm/src/index.ts @@ -15,9 +15,9 @@ const _wasmIntegration = (() => { processEvent(event: Event): Event { let hasAtLeastOneWasmFrameWithImage = false; - if (event.exception && event.exception.values) { + if (event.exception?.values) { event.exception.values.forEach(exception => { - if (exception.stacktrace && exception.stacktrace.frames) { + if (exception.stacktrace?.frames) { hasAtLeastOneWasmFrameWithImage = hasAtLeastOneWasmFrameWithImage || patchFrames(exception.stacktrace.frames); }