Skip to content

Commit e6e89fd

Browse files
authored
feat(utils): Add function for ensuring input is an array (#5668)
In a number of places in our codebase, we have the pattern `const something = Array.isArray(somethingElse) ? somethingElse : [ somethingElse ];`, where we need something (which might already be an array) to be an array. This introduces a utility function, `arrayify`, which does that work for us, mostly because I just got tired of typing it. (As a bonus, it's slightly shorter and therefore might save a few bytes on bundle size.)
1 parent 27ad67f commit e6e89fd

File tree

6 files changed

+35
-11
lines changed

6 files changed

+35
-11
lines changed

packages/hub/src/scope.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
User,
2323
} from '@sentry/types';
2424
import {
25+
arrayify,
2526
dateTimestampInSeconds,
2627
getGlobalSingleton,
2728
isPlainObject,
@@ -553,11 +554,7 @@ export class Scope implements ScopeInterface {
553554
*/
554555
private _applyFingerprint(event: Event): void {
555556
// Make sure it's an array first and we actually have something in place
556-
event.fingerprint = event.fingerprint
557-
? Array.isArray(event.fingerprint)
558-
? event.fingerprint
559-
: [event.fingerprint]
560-
: [];
557+
event.fingerprint = event.fingerprint ? arrayify(event.fingerprint) : [];
561558

562559
// If we have something on the scope, then merge it with event
563560
if (this._fingerprint) {

packages/nextjs/src/config/webpack.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable max-lines */
22
import { getSentryRelease } from '@sentry/node';
3-
import { dropUndefinedKeys, escapeStringForRegex, logger } from '@sentry/utils';
3+
import { arrayify, dropUndefinedKeys, escapeStringForRegex, logger } from '@sentry/utils';
44
import { default as SentryWebpackPlugin } from '@sentry/webpack-plugin';
55
import * as chalk from 'chalk';
66
import * as fs from 'fs';
@@ -186,7 +186,7 @@ function isMatchingRule(rule: WebpackModuleRule, projectDir: string): boolean {
186186
}
187187

188188
// `rule.use` can be an object or an array of objects. For simplicity, force it to be an array.
189-
const useEntries = Array.isArray(rule.use) ? rule.use : [rule.use];
189+
const useEntries = arrayify(rule.use);
190190

191191
// Depending on the version of nextjs we're talking about, the loader which does the transpiling is either
192192
//

packages/tracing/src/integrations/node/apollo.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Hub } from '@sentry/hub';
22
import { EventProcessor, Integration } from '@sentry/types';
3-
import { fill, isThenable, loadModule, logger } from '@sentry/utils';
3+
import { arrayify, fill, isThenable, loadModule, logger } from '@sentry/utils';
44

55
type ApolloResolverGroup = {
66
[key: string]: () => unknown;
@@ -44,7 +44,7 @@ export class Apollo implements Integration {
4444
*/
4545
fill(pkg.ApolloServerBase.prototype, 'constructSchema', function (orig: () => unknown) {
4646
return function (this: { config: { resolvers: ApolloModelResolvers[] } }) {
47-
const resolvers = Array.isArray(this.config.resolvers) ? this.config.resolvers : [this.config.resolvers];
47+
const resolvers = arrayify(this.config.resolvers);
4848

4949
this.config.resolvers = resolvers.map(model => {
5050
Object.keys(model).forEach(resolverGroupName => {

packages/utils/src/misc.ts

+10
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,13 @@ export function checkOrSetAlreadyCaught(exception: unknown): boolean {
200200

201201
return false;
202202
}
203+
204+
/**
205+
* Checks whether the given input is already an array, and if it isn't, wraps it in one.
206+
*
207+
* @param maybeArray Input to turn into an array, if necessary
208+
* @returns The input, if already an array, or an array with the input as the only element, if not
209+
*/
210+
export function arrayify<T = unknown>(maybeArray: T | T[]): T[] {
211+
return Array.isArray(maybeArray) ? maybeArray : [maybeArray];
212+
}

packages/utils/test/misc.test.ts

+17
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Event, Mechanism, StackFrame } from '@sentry/types';
33
import {
44
addContextToFrame,
55
addExceptionMechanism,
6+
arrayify,
67
checkOrSetAlreadyCaught,
78
getEventDescription,
89
uuid4,
@@ -309,3 +310,19 @@ describe('uuid4 generation', () => {
309310
}
310311
});
311312
});
313+
314+
describe('arrayify()', () => {
315+
it('returns arrays untouched', () => {
316+
expect(arrayify([])).toEqual([]);
317+
expect(arrayify(['dogs', 'are', 'great'])).toEqual(['dogs', 'are', 'great']);
318+
});
319+
320+
it('wraps non-arrays with an array', () => {
321+
expect(arrayify(1231)).toEqual([1231]);
322+
expect(arrayify('dogs are great')).toEqual(['dogs are great']);
323+
expect(arrayify(true)).toEqual([true]);
324+
expect(arrayify({})).toEqual([{}]);
325+
expect(arrayify(null)).toEqual([null]);
326+
expect(arrayify(undefined)).toEqual([undefined]);
327+
});
328+
});

packages/vue/src/sdk.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { init as browserInit, SDK_VERSION } from '@sentry/browser';
2-
import { getGlobalObject, logger } from '@sentry/utils';
2+
import { arrayify, getGlobalObject, logger } from '@sentry/utils';
33

44
import { DEFAULT_HOOKS } from './constants';
55
import { attachErrorHandler } from './errorhandler';
@@ -51,7 +51,7 @@ export function init(
5151
}
5252

5353
if (options.app) {
54-
const apps = Array.isArray(options.app) ? options.app : [options.app];
54+
const apps = arrayify(options.app);
5555
apps.forEach(app => vueInit(app, options));
5656
} else if (options.Vue) {
5757
vueInit(options.Vue, options);

0 commit comments

Comments
 (0)