Skip to content

Commit

Permalink
feat(utils): Add function for ensuring input is an array (#5668)
Browse files Browse the repository at this point in the history
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.)
  • Loading branch information
lobsterkatie committed Sep 1, 2022
1 parent 27ad67f commit e6e89fd
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 11 deletions.
7 changes: 2 additions & 5 deletions packages/hub/src/scope.ts
Expand Up @@ -22,6 +22,7 @@ import {
User,
} from '@sentry/types';
import {
arrayify,
dateTimestampInSeconds,
getGlobalSingleton,
isPlainObject,
Expand Down Expand Up @@ -553,11 +554,7 @@ export class Scope implements ScopeInterface {
*/
private _applyFingerprint(event: Event): void {
// Make sure it's an array first and we actually have something in place
event.fingerprint = event.fingerprint
? Array.isArray(event.fingerprint)
? event.fingerprint
: [event.fingerprint]
: [];
event.fingerprint = event.fingerprint ? arrayify(event.fingerprint) : [];

// If we have something on the scope, then merge it with event
if (this._fingerprint) {
Expand Down
4 changes: 2 additions & 2 deletions packages/nextjs/src/config/webpack.ts
@@ -1,6 +1,6 @@
/* eslint-disable max-lines */
import { getSentryRelease } from '@sentry/node';
import { dropUndefinedKeys, escapeStringForRegex, logger } from '@sentry/utils';
import { arrayify, dropUndefinedKeys, escapeStringForRegex, logger } from '@sentry/utils';
import { default as SentryWebpackPlugin } from '@sentry/webpack-plugin';
import * as chalk from 'chalk';
import * as fs from 'fs';
Expand Down Expand Up @@ -186,7 +186,7 @@ function isMatchingRule(rule: WebpackModuleRule, projectDir: string): boolean {
}

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

// Depending on the version of nextjs we're talking about, the loader which does the transpiling is either
//
Expand Down
4 changes: 2 additions & 2 deletions packages/tracing/src/integrations/node/apollo.ts
@@ -1,6 +1,6 @@
import { Hub } from '@sentry/hub';
import { EventProcessor, Integration } from '@sentry/types';
import { fill, isThenable, loadModule, logger } from '@sentry/utils';
import { arrayify, fill, isThenable, loadModule, logger } from '@sentry/utils';

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

this.config.resolvers = resolvers.map(model => {
Object.keys(model).forEach(resolverGroupName => {
Expand Down
10 changes: 10 additions & 0 deletions packages/utils/src/misc.ts
Expand Up @@ -200,3 +200,13 @@ export function checkOrSetAlreadyCaught(exception: unknown): boolean {

return false;
}

/**
* Checks whether the given input is already an array, and if it isn't, wraps it in one.
*
* @param maybeArray Input to turn into an array, if necessary
* @returns The input, if already an array, or an array with the input as the only element, if not
*/
export function arrayify<T = unknown>(maybeArray: T | T[]): T[] {
return Array.isArray(maybeArray) ? maybeArray : [maybeArray];
}
17 changes: 17 additions & 0 deletions packages/utils/test/misc.test.ts
Expand Up @@ -3,6 +3,7 @@ import { Event, Mechanism, StackFrame } from '@sentry/types';
import {
addContextToFrame,
addExceptionMechanism,
arrayify,
checkOrSetAlreadyCaught,
getEventDescription,
uuid4,
Expand Down Expand Up @@ -309,3 +310,19 @@ describe('uuid4 generation', () => {
}
});
});

describe('arrayify()', () => {
it('returns arrays untouched', () => {
expect(arrayify([])).toEqual([]);
expect(arrayify(['dogs', 'are', 'great'])).toEqual(['dogs', 'are', 'great']);
});

it('wraps non-arrays with an array', () => {
expect(arrayify(1231)).toEqual([1231]);
expect(arrayify('dogs are great')).toEqual(['dogs are great']);
expect(arrayify(true)).toEqual([true]);
expect(arrayify({})).toEqual([{}]);
expect(arrayify(null)).toEqual([null]);
expect(arrayify(undefined)).toEqual([undefined]);
});
});
4 changes: 2 additions & 2 deletions packages/vue/src/sdk.ts
@@ -1,5 +1,5 @@
import { init as browserInit, SDK_VERSION } from '@sentry/browser';
import { getGlobalObject, logger } from '@sentry/utils';
import { arrayify, getGlobalObject, logger } from '@sentry/utils';

import { DEFAULT_HOOKS } from './constants';
import { attachErrorHandler } from './errorhandler';
Expand Down Expand Up @@ -51,7 +51,7 @@ export function init(
}

if (options.app) {
const apps = Array.isArray(options.app) ? options.app : [options.app];
const apps = arrayify(options.app);
apps.forEach(app => vueInit(app, options));
} else if (options.Vue) {
vueInit(options.Vue, options);
Expand Down

0 comments on commit e6e89fd

Please sign in to comment.