Skip to content

Commit ad00442

Browse files
bryanmikaelianhbrls
authored andcommitted
Remove utils and @ndhoule/keys (segmentio#194)
1 parent da69129 commit ad00442

17 files changed

+347
-814
lines changed

.eslintrc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
11
{
2-
"extends": ["@segment/eslint-config/browser/legacy", "prettier"]
2+
"parser": "@typescript-eslint/parser",
3+
"plugins": [
4+
"@typescript-eslint"
5+
],
6+
"extends": [
7+
"@segment/eslint-config/browser/legacy",
8+
"prettier",
9+
"plugin:@typescript-eslint/recommended"
10+
],
11+
"rules": {
12+
"no-use-before-define": "warn",
13+
"no-var": "warn",
14+
"prefer-const": "warn",
15+
"prefer-rest-params": "warn",
16+
"prefer-spread": "warn",
17+
"strict": "warn",
18+
"@typescript-eslint/adjacent-overload-signatures": "warn",
19+
"@typescript-eslint/ban-ts-comment": "warn",
20+
"@typescript-eslint/ban-types": "warn",
21+
"@typescript-eslint/no-empty-function": "warn",
22+
"@typescript-eslint/no-this-alias": "warn",
23+
"@typescript-eslint/no-var-requires": "warn"
24+
}
325
}

HISTORY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010

1111
- Fix Potential DOM-based XSS via prototype pollution
1212

13+
# 4.1.0 / 2020-09-14
14+
15+
- Replaces `utils/clone` with `lodash.deepclone`
16+
- Replaces `utils/map` with `Array.prototype.map`
17+
- Replaces `utils/each` with `Array.prototype.each`
18+
- Removes the `utils` directory and tests
19+
1320
# 4.0.4 / 2020-09-11
1421

1522
- Change the arguments of the main methods to be optional in the typedef to match the documentation. (#203)

lib/analytics.ts

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ function Analytics() {
6868
this.log = debug('analytics.js');
6969
bindAll(this);
7070

71-
var self = this;
72-
this.on('initialize', function(settings, options) {
71+
72+
const self = this;
73+
this.on('initialize', function(_, options) {
7374
if (options.initialPageview) self.page();
7475
self._parseQuery(window.location.search);
7576
});
@@ -168,13 +169,16 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
168169

169170
// clean unknown integrations from settings
170171
var self = this;
171-
each(function(_opts: unknown, name: string | number) {
172-
var Integration = self.Integrations[name];
173-
if (!Integration) delete settings[name];
174-
}, settings);
172+
Object.keys(settings).forEach(key => {
173+
var Integration = self.Integrations[key];
174+
if (!Integration) delete settings[key];
175+
});
175176

176177
// add integrations
177-
each(function(opts: unknown, name: string | number) {
178+
Object.keys(settings).forEach(key => {
179+
const opts = settings[key]
180+
const name = key
181+
178182
// Don't load disabled integrations
179183
if (options.integrations) {
180184
if (
@@ -185,13 +189,13 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
185189
}
186190
}
187191

188-
var Integration = self.Integrations[name];
189-
var clonedOpts = {};
192+
const Integration = self.Integrations[name];
193+
const clonedOpts = {};
190194
extend(true, clonedOpts, opts); // deep clone opts
191-
var integration = new Integration(clonedOpts);
195+
const integration = new Integration(clonedOpts);
192196
self.log('initialize %o - %o', name, opts);
193197
self.add(integration);
194-
}, settings);
198+
});
195199

196200
var integrations = this._integrations;
197201

@@ -201,7 +205,7 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
201205

202206
// make ready callback
203207
var readyCallCount = 0;
204-
var integrationCount = keys(integrations).length;
208+
var integrationCount = Object.keys(integrations).length;
205209
var ready = function() {
206210
readyCallCount++;
207211
if (readyCallCount >= integrationCount) {
@@ -218,14 +222,15 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
218222
// initialize integrations, passing ready
219223
// create a list of any integrations that did not initialize - this will be passed with all events for replay support:
220224
this.failedInitializations = [];
221-
var initialPageSkipped = false;
222-
each(function(integration) {
225+
let initialPageSkipped = false;
226+
Object.keys(integrations).forEach(key => {
227+
const integration = integrations[key]
223228
if (
224229
options.initialPageview &&
225230
integration.options.initialPageview === false
226231
) {
227232
// We've assumed one initial pageview, so make sure we don't count the first page call.
228-
var page = integration.page;
233+
let page = integration.page;
229234
integration.page = function() {
230235
if (initialPageSkipped) {
231236
return page.apply(this, arguments);
@@ -245,7 +250,7 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
245250
});
246251
integration.initialize();
247252
} catch (e) {
248-
var integrationName = integration.name;
253+
let integrationName = integration.name;
249254
metrics.increment('analytics_js.integration.invoke.error', {
250255
method: 'initialize',
251256
integration_name: integration.name
@@ -256,7 +261,7 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
256261

257262
integration.ready();
258263
}
259-
}, integrations);
264+
});
260265

261266
// backwards compat with angular plugin and used for init logic checks
262267
this.initialized = true;
@@ -465,37 +470,44 @@ Analytics.prototype.track = function(
465470
*/
466471

467472
Analytics.prototype.trackClick = Analytics.prototype.trackLink = function(
468-
links: Element | Array<unknown>,
473+
links: Element | Array<Element> | JQuery,
469474
event: any,
470475
properties?: any
471476
): SegmentAnalytics {
477+
let elements: Array<Element> = []
472478
if (!links) return this;
473479
// always arrays, handles jquery
474-
if (type(links) === 'element') links = [links];
480+
if (links instanceof Element) {
481+
elements = [links]
482+
} else if ("toArray" in links) {
483+
elements = links.toArray()
484+
} else {
485+
elements = links as Array<Element>
486+
}
475487

476-
var self = this;
477-
each(function(el) {
488+
elements.forEach(el => {
478489
if (type(el) !== 'element') {
479490
throw new TypeError('Must pass HTMLElement to `analytics.trackLink`.');
480491
}
481-
on(el, 'click', function(e) {
482-
var ev = is.fn(event) ? event(el) : event;
483-
var props = is.fn(properties) ? properties(el) : properties;
484-
var href =
492+
on(el, 'click', (e) => {
493+
const ev = is.fn(event) ? event(el) : event;
494+
const props = is.fn(properties) ? properties(el) : properties;
495+
const href =
485496
el.getAttribute('href') ||
486497
el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') ||
487498
el.getAttribute('xlink:href');
488499

489-
self.track(ev, props);
500+
this.track(ev, props);
490501

502+
// @ts-ignore
491503
if (href && el.target !== '_blank' && !isMeta(e)) {
492504
prevent(e);
493-
self._callback(function() {
505+
this._callback(function() {
494506
window.location.href = href;
495507
});
496508
}
497509
});
498-
}, links);
510+
});
499511

500512
return this;
501513
};
@@ -521,18 +533,19 @@ Analytics.prototype.trackSubmit = Analytics.prototype.trackForm = function(
521533
// always arrays, handles jquery
522534
if (type(forms) === 'element') forms = [forms];
523535

524-
var self = this;
525-
each(function(el: { submit: () => void }) {
536+
const elements = forms as Array<unknown>
537+
538+
elements.forEach((el: { submit: () => void }) => {
526539
if (type(el) !== 'element')
527540
throw new TypeError('Must pass HTMLElement to `analytics.trackForm`.');
528-
function handler(e) {
541+
const handler = (e) => {
529542
prevent(e);
530543

531-
var ev = is.fn(event) ? event(el) : event;
532-
var props = is.fn(properties) ? properties(el) : properties;
533-
self.track(ev, props);
544+
const ev = is.fn(event) ? event(el) : event;
545+
const props = is.fn(properties) ? properties(el) : properties;
546+
this.track(ev, props);
534547

535-
self._callback(function() {
548+
this._callback(function() {
536549
el.submit();
537550
});
538551
}
@@ -545,7 +558,7 @@ Analytics.prototype.trackSubmit = Analytics.prototype.trackForm = function(
545558
} else {
546559
on(el, 'submit', handler);
547560
}
548-
}, forms);
561+
});
549562

550563
return this;
551564
};
@@ -582,7 +595,7 @@ Analytics.prototype.page = function(
582595
(name = category), (category = null);
583596
/* eslint-enable no-unused-expressions, no-sequences */
584597

585-
properties = clone(properties) || {};
598+
properties = cloneDeep(properties) || {};
586599
if (name) properties.name = name;
587600
if (category) properties.category = category;
588601

@@ -594,7 +607,7 @@ Analytics.prototype.page = function(
594607
// Mirror user overrides to `options.context.page` (but exclude custom properties)
595608
// (Any page defaults get applied in `this.normalize` for consistency.)
596609
// Weird, yeah--moving special props to `context.page` will fix this in the long term.
597-
var overrides = pick(keys(defs), properties);
610+
var overrides = pick(Object.keys(defs), properties);
598611
if (!is.empty(overrides)) {
599612
options = options || {};
600613
options.context = options.context || {};
@@ -795,9 +808,11 @@ Analytics.prototype._invoke = function(
795808
return this;
796809

797810
function applyIntegrationMiddlewares(facade) {
798-
var failedInitializations = self.failedInitializations || [];
799-
each(function(integration, name) {
800-
var facadeCopy = extend(true, new Facade({}), facade);
811+
let failedInitializations = self.failedInitializations || [];
812+
Object.keys(self._integrations).forEach(key => {
813+
const integration = self._integrations[key]
814+
const { name } = integration
815+
const facadeCopy = extend(true, new Facade({}), facade);
801816

802817
if (!facadeCopy.enabled(name)) return;
803818
// Check if an integration failed to initialize.
@@ -881,7 +896,7 @@ Analytics.prototype._invoke = function(
881896
);
882897
}
883898
}
884-
}, self._integrations);
899+
});
885900
}
886901
};
887902

@@ -963,7 +978,7 @@ Analytics.prototype.normalize = function(msg: {
963978
context: { page };
964979
anonymousId: string;
965980
}): object {
966-
msg = normalize(msg, keys(this._integrations));
981+
msg = normalize(msg, Object.keys(this._integrations));
967982
if (msg.anonymousId) user.anonymousId(msg.anonymousId);
968983
msg.anonymousId = user.anonymousId();
969984

lib/cookie.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
'use strict';
22

33
import { CookieOptions } from './types';
4+
import cloneDeep from 'lodash.clonedeep'
45

56
/**
67
* Module dependencies.
78
*/
89

910
var bindAll = require('bind-all');
10-
var clone = require('./utils/clone');
1111
var cookie = require('@segment/cookie');
1212
var debug = require('debug')('analytics.js:cookie');
1313
var defaults = require('@ndhoule/defaults');
@@ -65,7 +65,7 @@ Cookie.prototype.options = function(options?: CookieOptions) {
6565
Cookie.prototype.set = function(key: string, value?: object | string): boolean {
6666
try {
6767
value = window.JSON.stringify(value);
68-
cookie(key, value === 'null' ? null : value, clone(this._options));
68+
cookie(key, value === 'null' ? null : value, cloneDeep(this._options));
6969
return true;
7070
} catch (e) {
7171
return false;
@@ -92,7 +92,7 @@ Cookie.prototype.get = function(key: string): object {
9292

9393
Cookie.prototype.remove = function(key: string): boolean {
9494
try {
95-
cookie(key, null, clone(this._options));
95+
cookie(key, null, cloneDeep(this._options));
9696
return true;
9797
} catch (e) {
9898
return false;

lib/entity.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
'use strict';
22

33
import { InitOptions } from './types';
4+
import cloneDeep from 'lodash.clonedeep'
45

56
/*
67
* Module dependencies.
78
*/
89

9-
var clone = require('./utils/clone');
1010
var cookie = require('./cookie');
1111
var debug = require('debug')('analytics:entity');
1212
var defaults = require('@ndhoule/defaults');
@@ -198,7 +198,7 @@ Entity.prototype._getTraits = function(): object {
198198
var ret = this._options.persist
199199
? store.get(this._options.localStorage.key)
200200
: this._traits;
201-
return ret ? isodateTraverse(clone(ret)) : {};
201+
return ret ? isodateTraverse(cloneDeep(ret)) : {};
202202
};
203203

204204
/**

lib/memory.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
* Module Dependencies.
55
*/
66

7+
import cloneDeep from 'lodash.clonedeep'
8+
79
var bindAll = require('bind-all');
8-
var clone = require('./utils/clone');
910

1011
/**
1112
* HOP.
@@ -32,7 +33,7 @@ function Memory() {
3233
*/
3334

3435
Memory.prototype.set = function(key: string, value: unknown): boolean {
35-
this.store[key] = clone(value);
36+
this.store[key] = cloneDeep(value);
3637
return true;
3738
};
3839

@@ -42,7 +43,7 @@ Memory.prototype.set = function(key: string, value: unknown): boolean {
4243

4344
Memory.prototype.get = function(key: string): unknown | undefined {
4445
if (!has.call(this.store, key)) return;
45-
return clone(this.store[key]);
46+
return cloneDeep(this.store[key]);
4647
};
4748

4849
/**

0 commit comments

Comments
 (0)