Skip to content

Commit de2c1ad

Browse files
authored
ref: Rewrite to use optional chaining & add eslint rule (#14966)
This adds an eslint rule to enforce usage of optional chaining, to keep things consistent. It also fixes remaining places that "violate" this.
1 parent 6a6e05b commit de2c1ad

File tree

113 files changed

+299
-343
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+299
-343
lines changed

dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ sentryTest(
1919
const errorEvent = events.find(event => event.message === 'console error');
2020
const traceEvent = events.find(event => event.message === 'console trace');
2121
const errorWithErrorEvent = events.find(
22-
event => event.exception && event.exception.values?.[0].value === 'console error with error object',
22+
event => event.exception?.values?.[0].value === 'console error with error object',
2323
);
2424
const traceWithErrorEvent = events.find(
25-
event => event.exception && event.exception.values?.[0].value === 'console trace with error object',
25+
event => event.exception?.values?.[0].value === 'console trace with error object',
2626
);
2727

2828
expect(logEvent).toEqual(

dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ sentryTest('it captures console messages correctly', async ({ getLocalTestUrl, p
1717
const errorEvent = events.find(event => event.message === 'console error');
1818
const traceEvent = events.find(event => event.message === 'console trace');
1919
const errorWithErrorEvent = events.find(
20-
event => event.exception && event.exception.values?.[0].value === 'console error with error object',
20+
event => event.exception?.values?.[0].value === 'console error with error object',
2121
);
2222
const traceWithErrorEvent = events.find(
23-
event => event.exception && event.exception.values?.[0].value === 'console trace with error object',
23+
event => event.exception?.values?.[0].value === 'console trace with error object',
2424
);
2525

2626
expect(logEvent).toEqual(

dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/withScope/test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({
2222
const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true });
2323
await page.goto(url);
2424

25-
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true);
26-
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false);
25+
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true);
26+
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false);
2727

2828
await page.evaluate(() => {
2929
const Sentry = (window as any).Sentry;

dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/withScope/test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({
2222
const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true });
2323
await page.goto(url);
2424

25-
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true);
26-
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false);
25+
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true);
26+
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false);
2727

2828
await page.evaluate(() => {
2929
const Sentry = (window as any).Sentry;

dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/withScope/test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({
2222
const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true });
2323
await page.goto(url);
2424

25-
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true);
26-
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false);
25+
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true);
26+
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false);
2727

2828
await page.evaluate(() => {
2929
const Sentry = (window as any).Sentry;

dev-packages/browser-integration-tests/suites/old-sdk-interop/acs/getCurrentScope/subject.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const sentryCarrier = window?.__SENTRY__;
44
* Simulate an old pre v8 SDK obtaining the hub from the global sentry carrier
55
* and checking for the hub version.
66
*/
7-
const res = sentryCarrier.acs && sentryCarrier.acs.getCurrentScope();
7+
const res = sentryCarrier.acs?.getCurrentScope();
88

99
// Write back result into the document
1010
document.getElementById('currentScope').innerText = res && 'scope';

dev-packages/browser-integration-tests/suites/old-sdk-interop/hub/isOlderThan/subject.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const sentryCarrier = window?.__SENTRY__;
44
* Simulate an old pre v8 SDK obtaining the hub from the global sentry carrier
55
* and checking for the hub version.
66
*/
7-
const res = sentryCarrier.hub && sentryCarrier.hub.isOlderThan(7);
7+
const res = sentryCarrier.hub?.isOlderThan(7);
88

99
// Write back result into the document
1010
document.getElementById('olderThan').innerText = res;

dev-packages/browser-integration-tests/suites/replay/captureReplayOffline/test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getReplayEvent, shouldSkipReplayTest, waitForReplayRequest } from '../.
55

66
sentryTest('should capture replays offline', async ({ getLocalTestUrl, page }) => {
77
// makeBrowserOfflineTransport is not included in any CDN bundles
8-
if (shouldSkipReplayTest() || (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle'))) {
8+
if (shouldSkipReplayTest() || process.env.PW_BUNDLE?.startsWith('bundle')) {
99
sentryTest.skip();
1010
}
1111

dev-packages/browser-integration-tests/suites/replay/replayIntegrationShim/test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sentryTest(
77
async ({ getLocalTestUrl, page, forceFlushReplay }) => {
88
const bundle = process.env.PW_BUNDLE;
99

10-
if (!bundle || !bundle.startsWith('bundle_') || bundle.includes('replay')) {
10+
if (!bundle?.startsWith('bundle_') || bundle.includes('replay')) {
1111
sentryTest.skip();
1212
}
1313

dev-packages/browser-integration-tests/suites/replay/replayShim/test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sentryTest(
77
async ({ getLocalTestUrl, page, forceFlushReplay }) => {
88
const bundle = process.env.PW_BUNDLE;
99

10-
if (!bundle || !bundle.startsWith('bundle_') || bundle.includes('replay')) {
10+
if (!bundle?.startsWith('bundle_') || bundle.includes('replay')) {
1111
sentryTest.skip();
1212
}
1313

dev-packages/browser-integration-tests/suites/transport/offline/queued/test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function delay(ms: number) {
1010

1111
sentryTest('should queue and retry events when they fail to send', async ({ getLocalTestUrl, page }) => {
1212
// makeBrowserOfflineTransport is not included in any CDN bundles
13-
if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle')) {
13+
if (process.env.PW_BUNDLE?.startsWith('bundle')) {
1414
sentryTest.skip();
1515
}
1616

packages/angular/src/zone.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ declare const Zone: any;
88
// Therefore, it's advisable to safely check whether the `run` function is
99
// available in the `<root>` context.
1010
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
11-
const isNgZoneEnabled = typeof Zone !== 'undefined' && Zone.root && Zone.root.run;
11+
const isNgZoneEnabled = typeof Zone !== 'undefined' && Zone.root?.run;
1212

1313
/**
1414
* The function that does the same job as `NgZone.runOutsideAngular`.

packages/browser-utils/src/getNativeImplementation.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function getNativeImplementation<T extends keyof CacheableImplementations
4747
sandbox.hidden = true;
4848
document.head.appendChild(sandbox);
4949
const contentWindow = sandbox.contentWindow;
50-
if (contentWindow && contentWindow[name]) {
50+
if (contentWindow?.[name]) {
5151
impl = contentWindow[name] as CacheableImplementations[T];
5252
}
5353
document.head.removeChild(sandbox);

packages/browser-utils/src/instrument/dom.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function instrumentDOM(): void {
6767
const proto = globalObject[target]?.prototype;
6868

6969
// eslint-disable-next-line no-prototype-builtins
70-
if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {
70+
if (!proto?.hasOwnProperty?.('addEventListener')) {
7171
return;
7272
}
7373

@@ -169,7 +169,7 @@ function shouldSkipDOMEvent(eventType: string, target: SentryWrappedTarget | nul
169169
return false;
170170
}
171171

172-
if (!target || !target.tagName) {
172+
if (!target?.tagName) {
173173
return true;
174174
}
175175

packages/browser-utils/src/metrics/browserMetrics.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export function startTrackingWebVitals({ recordClsStandaloneSpans }: StartTracki
9797
fidCleanupCallback();
9898
lcpCleanupCallback();
9999
ttfbCleanupCallback();
100-
clsCleanupCallback && clsCleanupCallback();
100+
clsCleanupCallback?.();
101101
};
102102
}
103103

@@ -300,7 +300,7 @@ interface AddPerformanceEntriesOptions {
300300
/** Add performance related spans to a transaction */
301301
export function addPerformanceEntries(span: Span, options: AddPerformanceEntriesOptions): void {
302302
const performance = getBrowserPerformanceAPI();
303-
if (!performance || !performance.getEntries || !browserPerformanceTimeOrigin) {
303+
if (!performance?.getEntries || !browserPerformanceTimeOrigin) {
304304
// Gatekeeper if performance API not available
305305
return;
306306
}

packages/browser-utils/src/metrics/cls.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export function trackClsAsStandaloneSpan(): void {
7373

7474
const unsubscribeStartNavigation = client.on('startNavigationSpan', () => {
7575
_collectClsOnce();
76-
unsubscribeStartNavigation && unsubscribeStartNavigation();
76+
unsubscribeStartNavigation?.();
7777
});
7878

7979
const activeSpan = getActiveSpan();
@@ -93,7 +93,7 @@ function sendStandaloneClsSpan(clsValue: number, entry: LayoutShift | undefined,
9393
const startTime = msToSec((browserPerformanceTimeOrigin || 0) + (entry?.startTime || 0));
9494
const routeName = getCurrentScope().getScopeData().transactionName;
9595

96-
const name = entry ? htmlTreeAsString(entry.sources[0] && entry.sources[0].node) : 'Layout shift';
96+
const name = entry ? htmlTreeAsString(entry.sources[0]?.node) : 'Layout shift';
9797

9898
const attributes: SpanAttributes = dropUndefinedKeys({
9999
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.cls',

packages/browser-utils/src/metrics/instrument.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ export function addPerformanceInstrumentationHandler(
201201
function triggerHandlers(type: InstrumentHandlerType, data: unknown): void {
202202
const typeHandlers = handlers[type];
203203

204-
if (!typeHandlers || !typeHandlers.length) {
204+
if (!typeHandlers?.length) {
205205
return;
206206
}
207207

packages/browser-utils/src/metrics/utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export function startStandaloneWebVitalSpan(options: StandaloneWebVitalSpanOptio
106106
// Web vital score calculation relies on the user agent to account for different
107107
// browsers setting different thresholds for what is considered a good/meh/bad value.
108108
// For example: Chrome vs. Chrome Mobile
109-
'user_agent.original': WINDOW.navigator && WINDOW.navigator.userAgent,
109+
'user_agent.original': WINDOW.navigator?.userAgent,
110110

111111
...passedAttributes,
112112
};

packages/browser-utils/src/metrics/web-vitals/lib/getNavigationEntry.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ import { WINDOW } from '../../../types';
1919
// sentry-specific change:
2020
// add optional param to not check for responseStart (see comment below)
2121
export const getNavigationEntry = (checkResponseStart = true): PerformanceNavigationTiming | void => {
22-
const navigationEntry =
23-
WINDOW.performance && WINDOW.performance.getEntriesByType && WINDOW.performance.getEntriesByType('navigation')[0];
22+
const navigationEntry = WINDOW.performance?.getEntriesByType?.('navigation')[0];
2423
// Check to ensure the `responseStart` property is present and valid.
2524
// In some cases no value is reported by the browser (for
2625
// privacy/security reasons), and in other cases (bugs) the value is

packages/browser-utils/src/metrics/web-vitals/lib/initMetric.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ export const initMetric = <MetricName extends MetricType['name']>(name: MetricNa
2525
let navigationType: MetricType['navigationType'] = 'navigate';
2626

2727
if (navEntry) {
28-
if ((WINDOW.document && WINDOW.document.prerendering) || getActivationStart() > 0) {
28+
if (WINDOW.document?.prerendering || getActivationStart() > 0) {
2929
navigationType = 'prerender';
30-
} else if (WINDOW.document && WINDOW.document.wasDiscarded) {
30+
} else if (WINDOW.document?.wasDiscarded) {
3131
navigationType = 'restore';
3232
} else if (navEntry.type) {
3333
navigationType = navEntry.type.replace(/_/g, '-') as MetricType['navigationType'];

packages/browser-utils/src/metrics/web-vitals/lib/interactions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export const processInteractionEntry = (entry: PerformanceEventTiming) => {
113113
existingInteraction.latency = entry.duration;
114114
} else if (
115115
entry.duration === existingInteraction.latency &&
116-
entry.startTime === (existingInteraction.entries[0] && existingInteraction.entries[0].startTime)
116+
entry.startTime === existingInteraction.entries[0]?.startTime
117117
) {
118118
existingInteraction.entries.push(entry);
119119
}

packages/browser-utils/src/metrics/web-vitals/lib/onHidden.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export interface OnHiddenCallback {
3232
// simulate the page being hidden.
3333
export const onHidden = (cb: OnHiddenCallback) => {
3434
const onHiddenOrPageHide = (event: Event) => {
35-
if (event.type === 'pagehide' || (WINDOW.document && WINDOW.document.visibilityState === 'hidden')) {
35+
if (event.type === 'pagehide' || WINDOW.document?.visibilityState === 'hidden') {
3636
cb(event);
3737
}
3838
};

packages/browser-utils/src/metrics/web-vitals/lib/whenActivated.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import { WINDOW } from '../../../types';
1818

1919
export const whenActivated = (callback: () => void) => {
20-
if (WINDOW.document && WINDOW.document.prerendering) {
20+
if (WINDOW.document?.prerendering) {
2121
addEventListener('prerenderingchange', () => callback(), true);
2222
} else {
2323
callback();

packages/browser-utils/src/metrics/web-vitals/lib/whenIdle.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const whenIdle = (cb: () => void): number => {
3030
cb = runOnce(cb) as () => void;
3131
// If the document is hidden, run the callback immediately, otherwise
3232
// race an idle callback with the next `visibilitychange` event.
33-
if (WINDOW.document && WINDOW.document.visibilityState === 'hidden') {
33+
if (WINDOW.document?.visibilityState === 'hidden') {
3434
cb();
3535
} else {
3636
handle = rIC(cb);

packages/browser-utils/src/metrics/web-vitals/onTTFB.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ export const TTFBThresholds: MetricRatingThresholds = [800, 1800];
3030
* @param callback
3131
*/
3232
const whenReady = (callback: () => void) => {
33-
if (WINDOW.document && WINDOW.document.prerendering) {
33+
if (WINDOW.document?.prerendering) {
3434
whenActivated(() => whenReady(callback));
35-
} else if (WINDOW.document && WINDOW.document.readyState !== 'complete') {
35+
} else if (WINDOW.document?.readyState !== 'complete') {
3636
addEventListener('load', () => whenReady(callback), true);
3737
} else {
3838
// Queue a task so the callback runs after `loadEventEnd`.

packages/browser/src/integrations/breadcrumbs.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ function _getHistoryBreadcrumbHandler(client: Client): (handlerData: HandlerData
352352
const parsedTo = parseUrl(to);
353353

354354
// Initial pushState doesn't provide `from` information
355-
if (!parsedFrom || !parsedFrom.path) {
355+
if (!parsedFrom?.path) {
356356
parsedFrom = parsedLoc;
357357
}
358358

packages/browser/src/integrations/browserapierrors.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ function _wrapEventTarget(target: string): void {
166166
const proto = globalObject[target]?.prototype;
167167

168168
// eslint-disable-next-line no-prototype-builtins
169-
if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {
169+
if (!proto?.hasOwnProperty?.('addEventListener')) {
170170
return;
171171
}
172172

packages/browser/src/integrations/contextlines.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ function addSourceContext(event: Event, contextLines: number): Event {
5151
return event;
5252
}
5353

54-
const exceptions = event.exception && event.exception.values;
55-
if (!exceptions || !exceptions.length) {
54+
const exceptions = event.exception?.values;
55+
if (!exceptions?.length) {
5656
return event;
5757
}
5858

packages/browser/src/integrations/httpcontext.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineIntegration } from '@sentry/core';
1+
import { defineIntegration, getLocationHref } from '@sentry/core';
22
import { WINDOW } from '../helpers';
33

44
/**
@@ -15,16 +15,20 @@ export const httpContextIntegration = defineIntegration(() => {
1515
}
1616

1717
// grab as much info as exists and add it to the event
18-
const url = (event.request && event.request.url) || (WINDOW.location && WINDOW.location.href);
18+
const url = event.request?.url || getLocationHref();
1919
const { referrer } = WINDOW.document || {};
2020
const { userAgent } = WINDOW.navigator || {};
2121

2222
const headers = {
23-
...(event.request && event.request.headers),
23+
...event.request?.headers,
2424
...(referrer && { Referer: referrer }),
2525
...(userAgent && { 'User-Agent': userAgent }),
2626
};
27-
const request = { ...event.request, ...(url && { url }), headers };
27+
const request = {
28+
...event.request,
29+
...(url && { url }),
30+
headers,
31+
};
2832

2933
event.request = request;
3034
},

packages/browser/src/profiling/integration.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ const _browserProfilingIntegration = (() => {
5050

5151
for (const profiledTransaction of profiledTransactionEvents) {
5252
const context = profiledTransaction?.contexts;
53-
const profile_id = context && context['profile'] && context['profile']['profile_id'];
54-
const start_timestamp = context && context['profile'] && context['profile']['start_timestamp'];
53+
const profile_id = context?.profile?.['profile_id'];
54+
const start_timestamp = context?.profile?.['start_timestamp'];
5555

5656
if (typeof profile_id !== 'string') {
5757
DEBUG_BUILD && logger.log('[Profiling] cannot find profile for a span without a profile context');
@@ -64,7 +64,7 @@ const _browserProfilingIntegration = (() => {
6464
}
6565

6666
// Remove the profile from the span context before sending, relay will take care of the rest.
67-
if (context && context['profile']) {
67+
if (context?.profile) {
6868
delete context.profile;
6969
}
7070

0 commit comments

Comments
 (0)