Skip to content

Commit 42b71f5

Browse files
msonnbcodex
andcommitted
ref: Reuse isObjectLike for object guards
Co-Authored-By: OpenAI Codex <codex@openai.com>
1 parent ad1d641 commit 42b71f5

17 files changed

Lines changed: 56 additions & 43 deletions

File tree

‎packages/cloudflare/src/options.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function getEnvVar<T extends Record<string, unknown>>(env: unknown, varName: key
3939
* @returns The final options.
4040
*/
4141
export function getFinalOptions(userOptions: CloudflareOptions = {}, env: unknown): CloudflareOptions {
42-
if (typeof env !== 'object' || env === null) {
42+
if (!isObjectLike(env)) {
4343
return userOptions;
4444
}
4545

‎packages/deno/src/opentelemetry/tracer.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SENTRY_ORIGIN } from '@sentry/conventions/attributes';
22
import type { Context, Span, SpanOptions, Tracer, TracerProvider } from '@opentelemetry/api';
33
import { trace } from '@opentelemetry/api';
4-
import { startInactiveSpan, startSpanManual } from '@sentry/core';
4+
import { isObjectLike, startInactiveSpan, startSpanManual } from '@sentry/core';
55

66
/**
77
* Set up a mock OTEL tracer to allow inter-op with OpenTelemetry emitted spans.
@@ -58,7 +58,7 @@ class SentryDenoTracer implements Tracer {
5858
context?: unknown,
5959
fn?: F,
6060
): ReturnType<F> {
61-
const opts = (typeof options === 'object' && options !== null ? options : {}) as SpanOptions;
61+
const opts = (isObjectLike(options) ? options : {}) as SpanOptions;
6262

6363
const spanOpts = {
6464
...opts,

‎packages/nestjs/src/helpers.ts‎

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { isObjectLike } from '@sentry/core';
2+
13
/**
24
* Determines if the exception is an expected NestJS control flow error.
35
* - HttpException have getStatus and getResponse methods: https://github.com/nestjs/nest/blob/master/packages/microservices/exceptions/rpc-exception.ts
@@ -10,17 +12,15 @@
1012
* @returns `true` if the exception is expected and should not be reported to Sentry, otherwise `false`.
1113
*/
1214
export function isExpectedError(exception: unknown): boolean {
13-
if (typeof exception !== 'object' || exception === null) {
15+
if (!isObjectLike(exception)) {
1416
return false;
1517
}
1618

17-
const ex = exception as Record<string, unknown>;
18-
1919
// HttpException
2020
if (
21-
typeof ex.getStatus === 'function' &&
22-
typeof ex.getResponse === 'function' &&
23-
typeof ex.initMessage === 'function'
21+
typeof exception.getStatus === 'function' &&
22+
typeof exception.getResponse === 'function' &&
23+
typeof exception.initMessage === 'function'
2424
) {
2525
return true;
2626
}
@@ -39,10 +39,9 @@ export function isExpectedError(exception: unknown): boolean {
3939
* We use duck-typing to avoid importing from `@nestjs/websockets` or `@nestjs/microservices`.
4040
*/
4141
export function isWsOrRpcException(exception: unknown): boolean {
42-
if (typeof exception !== 'object' || exception === null) {
42+
if (!isObjectLike(exception)) {
4343
return false;
4444
}
4545

46-
const ex = exception as Record<string, unknown>;
47-
return typeof ex.getError === 'function' && typeof ex.initMessage === 'function';
46+
return typeof exception.getError === 'function' && typeof exception.initMessage === 'function';
4847
}

‎packages/nestjs/src/setup.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
} from '@nestjs/common';
99
import { Catch, Global, HttpException, Injectable, Logger, Module } from '@nestjs/common';
1010
import { APP_INTERCEPTOR, BaseExceptionFilter } from '@nestjs/core';
11-
import { captureException, debug, getDefaultIsolationScope, getIsolationScope } from '@sentry/core';
11+
import { captureException, debug, getDefaultIsolationScope, getIsolationScope, isObjectLike } from '@sentry/core';
1212
import type { Observable } from 'rxjs';
1313
import { isExpectedError, isWsOrRpcException } from './helpers';
1414

@@ -166,7 +166,7 @@ class SentryGlobalFilter extends BaseExceptionFilter {
166166

167167
if (isWsOrRpcException(exception)) {
168168
const result = (exception as { getError: () => unknown }).getError();
169-
const response = typeof result === 'object' && result !== null ? result : { status: 'error', message: result };
169+
const response = isObjectLike(result) ? result : { status: 'error', message: result };
170170
client.emit?.('exception', response);
171171
return;
172172
}

‎packages/nestjs/test/sentry-global-filter.test.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ vi.mock('../src/helpers', () => ({
1111
isWsOrRpcException: vi.fn(),
1212
}));
1313

14-
vi.mock('@sentry/core', () => ({
14+
vi.mock('@sentry/core', async importOriginal => ({
15+
isObjectLike: (await importOriginal<typeof SentryCore>()).isObjectLike,
1516
captureException: vi.fn().mockReturnValue('mock-event-id'),
1617
getIsolationScope: vi.fn(),
1718
getDefaultIsolationScope: vi.fn(),

‎packages/nextjs/src/client/routing/appRouterRoutingInstrumentation.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Client, Span } from '@sentry/core';
22
import {
33
GLOBAL_OBJ,
44
hasSpanStreamingEnabled,
5+
isObjectLike,
56
NAVIGATION_SPAN_NAME_FALLBACK,
67
PAGELOAD_SPAN_NAME_FALLBACK,
78
filterCollectedUrl,
@@ -250,8 +251,8 @@ export function appRouterInstrumentNavigation(client: Client): void {
250251
if (globalValue) {
251252
GLOBAL_OBJ_WITH_NEXT_ROUTER.next = new Proxy(globalValue, {
252253
set(target, p, newValue) {
253-
if (p === 'router' && typeof newValue === 'object' && newValue !== null) {
254-
patchRouter(client, newValue, currentRouterPatchingNavigationSpanRef);
254+
if (p === 'router' && isObjectLike(newValue)) {
255+
patchRouter(client, newValue as unknown as NextRouter, currentRouterPatchingNavigationSpanRef);
255256
}
256257

257258
// @ts-expect-error we cannot possibly type this

‎packages/nextjs/src/common/pages-router-instrumentation/wrapAppGetInitialPropsWithSentry.ts‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isObjectLike } from '@sentry/core';
12
import type App from 'next/app';
23
import { isBuild } from '../utils/isBuild';
34
import { withErrorInstrumentation, withTracedServerSideDataFetcher } from '../utils/wrapperUtils';
@@ -45,23 +46,23 @@ export function wrapAppGetInitialPropsWithSentry(origAppGetInitialProps: AppGetI
4546
baggage?: string;
4647
} = await tracedGetInitialProps.apply(thisArg, args);
4748

48-
if (typeof appGetInitialProps === 'object' && appGetInitialProps !== null) {
49+
if (isObjectLike(appGetInitialProps)) {
4950
// Per definition, `pageProps` is not optional, however an increased amount of users doesn't seem to call
5051
// `App.getInitialProps(appContext)` in their custom `_app` pages which is required as per
5152
// https://nextjs.org/docs/advanced-features/custom-app - resulting in missing `pageProps`.
5253
// For this reason, we just handle the case where `pageProps` doesn't exist explicitly.
53-
if (!(appGetInitialProps as Record<string, unknown>).pageProps) {
54-
(appGetInitialProps as Record<string, unknown>).pageProps = {};
54+
if (!appGetInitialProps.pageProps) {
55+
appGetInitialProps.pageProps = {};
5556
}
5657

5758
// The Next.js serializer throws on undefined values so we need to guard for it (#12102)
5859
if (sentryTrace) {
59-
(appGetInitialProps as { pageProps: Record<string, unknown> }).pageProps._sentryTraceData = sentryTrace;
60+
(appGetInitialProps.pageProps as Record<string, unknown>)._sentryTraceData = sentryTrace;
6061
}
6162

6263
// The Next.js serializer throws on undefined values so we need to guard for it (#12102)
6364
if (baggage) {
64-
(appGetInitialProps as { pageProps: Record<string, unknown> }).pageProps._sentryBaggage = baggage;
65+
(appGetInitialProps.pageProps as Record<string, unknown>)._sentryBaggage = baggage;
6566
}
6667
}
6768

‎packages/nextjs/src/common/pages-router-instrumentation/wrapErrorGetInitialPropsWithSentry.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isObjectLike } from '@sentry/core';
12
import type { NextPageContext } from 'next';
23
import type { ErrorProps } from 'next/error';
34
import { isBuild } from '../utils/isBuild';
@@ -47,15 +48,15 @@ export function wrapErrorGetInitialPropsWithSentry(
4748
sentryTrace?: string;
4849
} = await tracedGetInitialProps.apply(thisArg, args);
4950

50-
if (typeof errorGetInitialProps === 'object' && errorGetInitialProps !== null) {
51+
if (isObjectLike(errorGetInitialProps)) {
5152
if (sentryTrace) {
5253
// The Next.js serializer throws on undefined values so we need to guard for it (#12102)
53-
(errorGetInitialProps as Record<string, unknown>)._sentryTraceData = sentryTrace;
54+
errorGetInitialProps._sentryTraceData = sentryTrace;
5455
}
5556

5657
// The Next.js serializer throws on undefined values so we need to guard for it (#12102)
5758
if (baggage) {
58-
(errorGetInitialProps as Record<string, unknown>)._sentryBaggage = baggage;
59+
errorGetInitialProps._sentryBaggage = baggage;
5960
}
6061
}
6162

‎packages/nextjs/src/common/pages-router-instrumentation/wrapGetInitialPropsWithSentry.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isObjectLike } from '@sentry/core';
12
import type { NextPage } from 'next';
23
import { isBuild } from '../utils/isBuild';
34
import { withErrorInstrumentation, withTracedServerSideDataFetcher } from '../utils/wrapperUtils';
@@ -43,15 +44,15 @@ export function wrapGetInitialPropsWithSentry(origGetInitialProps: GetInitialPro
4344
sentryTrace?: string;
4445
} = (await tracedGetInitialProps.apply(thisArg, args)) ?? {}; // Next.js allows undefined to be returned from a getInitialPropsFunction.
4546

46-
if (typeof initialProps === 'object' && initialProps !== null) {
47+
if (isObjectLike(initialProps)) {
4748
// The Next.js serializer throws on undefined values so we need to guard for it (#12102)
4849
if (sentryTrace) {
49-
(initialProps as Record<string, unknown>)._sentryTraceData = sentryTrace;
50+
initialProps._sentryTraceData = sentryTrace;
5051
}
5152

5253
// The Next.js serializer throws on undefined values so we need to guard for it (#12102)
5354
if (baggage) {
54-
(initialProps as Record<string, unknown>)._sentryBaggage = baggage;
55+
initialProps._sentryBaggage = baggage;
5556
}
5657
}
5758

‎packages/nextjs/src/common/pages-router-instrumentation/wrapGetServerSidePropsWithSentry.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isObjectLike } from '@sentry/core';
12
import type { GetServerSideProps } from 'next';
23
import { isBuild } from '../utils/isBuild';
34
import { withErrorInstrumentation, withTracedServerSideDataFetcher } from '../utils/wrapperUtils';
@@ -39,7 +40,7 @@ export function wrapGetServerSidePropsWithSentry(
3940
sentryTrace?: string;
4041
} = await (tracedGetServerSideProps.apply(thisArg, args) as ReturnType<typeof tracedGetServerSideProps>);
4142

42-
if (typeof serverSideProps === 'object' && serverSideProps !== null && 'props' in serverSideProps) {
43+
if (isObjectLike(serverSideProps) && 'props' in serverSideProps) {
4344
// The Next.js serializer throws on undefined values so we need to guard for it (#12102)
4445
if (sentryTrace) {
4546
(serverSideProps.props as Record<string, unknown>)._sentryTraceData = sentryTrace;

0 commit comments

Comments
 (0)