Skip to content

Commit 492a84e

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

17 files changed

+347
-815
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 & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ var each = require('./utils/each');
3737
var group = require('./group');
3838
var is = require('is');
3939
var isMeta = require('@segment/is-meta');
40-
var keys = require('@ndhoule/keys');
4140
var memory = require('./memory');
4241
var nextTick = require('next-tick');
4342
var normalize = require('./normalize');
@@ -68,8 +67,9 @@ function Analytics() {
6867
this.log = debug('analytics.js');
6968
bindAll(this);
7069

71-
var self = this;
72-
this.on('initialize', function(settings, options) {
70+
71+
const self = this;
72+
this.on('initialize', function(_, options) {
7373
if (options.initialPageview) self.page();
7474
self._parseQuery(window.location.search);
7575
});
@@ -168,13 +168,16 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
168168

169169
// clean unknown integrations from settings
170170
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);
171+
Object.keys(settings).forEach(key => {
172+
var Integration = self.Integrations[key];
173+
if (!Integration) delete settings[key];
174+
});
175175

176176
// add integrations
177-
each(function(opts: unknown, name: string | number) {
177+
Object.keys(settings).forEach(key => {
178+
const opts = settings[key]
179+
const name = key
180+
178181
// Don't load disabled integrations
179182
if (options.integrations) {
180183
if (
@@ -185,13 +188,13 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
185188
}
186189
}
187190

188-
var Integration = self.Integrations[name];
189-
var clonedOpts = {};
191+
const Integration = self.Integrations[name];
192+
const clonedOpts = {};
190193
extend(true, clonedOpts, opts); // deep clone opts
191-
var integration = new Integration(clonedOpts);
194+
const integration = new Integration(clonedOpts);
192195
self.log('initialize %o - %o', name, opts);
193196
self.add(integration);
194-
}, settings);
197+
});
195198

196199
var integrations = this._integrations;
197200

@@ -201,7 +204,7 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
201204

202205
// make ready callback
203206
var readyCallCount = 0;
204-
var integrationCount = keys(integrations).length;
207+
var integrationCount = Object.keys(integrations).length;
205208
var ready = function() {
206209
readyCallCount++;
207210
if (readyCallCount >= integrationCount) {
@@ -218,14 +221,15 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
218221
// initialize integrations, passing ready
219222
// create a list of any integrations that did not initialize - this will be passed with all events for replay support:
220223
this.failedInitializations = [];
221-
var initialPageSkipped = false;
222-
each(function(integration) {
224+
let initialPageSkipped = false;
225+
Object.keys(integrations).forEach(key => {
226+
const integration = integrations[key]
223227
if (
224228
options.initialPageview &&
225229
integration.options.initialPageview === false
226230
) {
227231
// We've assumed one initial pageview, so make sure we don't count the first page call.
228-
var page = integration.page;
232+
let page = integration.page;
229233
integration.page = function() {
230234
if (initialPageSkipped) {
231235
return page.apply(this, arguments);
@@ -245,7 +249,7 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
245249
});
246250
integration.initialize();
247251
} catch (e) {
248-
var integrationName = integration.name;
252+
let integrationName = integration.name;
249253
metrics.increment('analytics_js.integration.invoke.error', {
250254
method: 'initialize',
251255
integration_name: integration.name
@@ -256,7 +260,7 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(
256260

257261
integration.ready();
258262
}
259-
}, integrations);
263+
});
260264

261265
// backwards compat with angular plugin and used for init logic checks
262266
this.initialized = true;
@@ -465,37 +469,44 @@ Analytics.prototype.track = function(
465469
*/
466470

467471
Analytics.prototype.trackClick = Analytics.prototype.trackLink = function(
468-
links: Element | Array<unknown>,
472+
links: Element | Array<Element> | JQuery,
469473
event: any,
470474
properties?: any
471475
): SegmentAnalytics {
476+
let elements: Array<Element> = []
472477
if (!links) return this;
473478
// always arrays, handles jquery
474-
if (type(links) === 'element') links = [links];
479+
if (links instanceof Element) {
480+
elements = [links]
481+
} else if ("toArray" in links) {
482+
elements = links.toArray()
483+
} else {
484+
elements = links as Array<Element>
485+
}
475486

476-
var self = this;
477-
each(function(el) {
487+
elements.forEach(el => {
478488
if (type(el) !== 'element') {
479489
throw new TypeError('Must pass HTMLElement to `analytics.trackLink`.');
480490
}
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 =
491+
on(el, 'click', (e) => {
492+
const ev = is.fn(event) ? event(el) : event;
493+
const props = is.fn(properties) ? properties(el) : properties;
494+
const href =
485495
el.getAttribute('href') ||
486496
el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') ||
487497
el.getAttribute('xlink:href');
488498

489-
self.track(ev, props);
499+
this.track(ev, props);
490500

501+
// @ts-ignore
491502
if (href && el.target !== '_blank' && !isMeta(e)) {
492503
prevent(e);
493-
self._callback(function() {
504+
this._callback(function() {
494505
window.location.href = href;
495506
});
496507
}
497508
});
498-
}, links);
509+
});
499510

500511
return this;
501512
};
@@ -521,18 +532,19 @@ Analytics.prototype.trackSubmit = Analytics.prototype.trackForm = function(
521532
// always arrays, handles jquery
522533
if (type(forms) === 'element') forms = [forms];
523534

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

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

535-
self._callback(function() {
547+
this._callback(function() {
536548
el.submit();
537549
});
538550
}
@@ -545,7 +557,7 @@ Analytics.prototype.trackSubmit = Analytics.prototype.trackForm = function(
545557
} else {
546558
on(el, 'submit', handler);
547559
}
548-
}, forms);
560+
});
549561

550562
return this;
551563
};
@@ -582,7 +594,7 @@ Analytics.prototype.page = function(
582594
(name = category), (category = null);
583595
/* eslint-enable no-unused-expressions, no-sequences */
584596

585-
properties = clone(properties) || {};
597+
properties = cloneDeep(properties) || {};
586598
if (name) properties.name = name;
587599
if (category) properties.category = category;
588600

@@ -594,7 +606,7 @@ Analytics.prototype.page = function(
594606
// Mirror user overrides to `options.context.page` (but exclude custom properties)
595607
// (Any page defaults get applied in `this.normalize` for consistency.)
596608
// Weird, yeah--moving special props to `context.page` will fix this in the long term.
597-
var overrides = pick(keys(defs), properties);
609+
var overrides = pick(Object.keys(defs), properties);
598610
if (!is.empty(overrides)) {
599611
options = options || {};
600612
options.context = options.context || {};
@@ -795,9 +807,11 @@ Analytics.prototype._invoke = function(
795807
return this;
796808

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

802816
if (!facadeCopy.enabled(name)) return;
803817
// Check if an integration failed to initialize.
@@ -881,7 +895,7 @@ Analytics.prototype._invoke = function(
881895
);
882896
}
883897
}
884-
}, self._integrations);
898+
});
885899
}
886900
};
887901

@@ -963,7 +977,7 @@ Analytics.prototype.normalize = function(msg: {
963977
context: { page };
964978
anonymousId: string;
965979
}): object {
966-
msg = normalize(msg, keys(this._integrations));
980+
msg = normalize(msg, Object.keys(this._integrations));
967981
if (msg.anonymousId) user.anonymousId(msg.anonymousId);
968982
msg.anonymousId = user.anonymousId();
969983

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)