Skip to content
This repository was archived by the owner on Sep 3, 2022. It is now read-only.

Commit 7b59f34

Browse files
Replace @ndhoule/defaults with ES6 spread syntax merging (#185)
1 parent c70c3af commit 7b59f34

13 files changed

+151
-30
lines changed

HISTORY.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 4.1.5 / 2020-09-17
2+
3+
- Replace @ndhoule/defaults with merging via ES6 spread syntax
4+
15
# 4.1.4 / 2020-09-16
26

37
- Replace `@ndhoule/includes` with `lodash.includes`

lib/analytics.ts

+47-13
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
InitOptions,
66
SegmentAnalytics,
77
SegmentOpts,
8-
SegmentIntegration
8+
SegmentIntegration,
9+
PageDefaults, Message
910
} from './types';
1011

1112
import cloneDeep from 'lodash.clonedeep'
@@ -323,8 +324,13 @@ Analytics.prototype.identify = function(
323324
});
324325

325326
// Add the initialize integrations so the server-side ones can be disabled too
327+
// NOTE: We need to merge integrations, not override them with assign
328+
// since it is possible to change the initialized integrations at runtime.
326329
if (this.options.integrations) {
327-
defaults(msg.integrations, this.options.integrations);
330+
msg.integrations = {
331+
...this.options.integrations,
332+
...msg.integrations
333+
}
328334
}
329335

330336
this._invoke('identify', new Identify(msg));
@@ -379,8 +385,13 @@ Analytics.prototype.group = function(
379385
});
380386

381387
// Add the initialize integrations so the server-side ones can be disabled too
388+
// NOTE: We need to merge integrations, not override them with assign
389+
// since it is possible to change the initialized integrations at runtime.
382390
if (this.options.integrations) {
383-
defaults(msg.integrations, this.options.integrations);
391+
msg.integrations = {
392+
...this.options.integrations,
393+
...msg.integrations
394+
}
384395
}
385396

386397
this._invoke('group', new Group(msg));
@@ -444,10 +455,12 @@ Analytics.prototype.track = function(
444455
}
445456

446457
// Add the initialize integrations so the server-side ones can be disabled too
447-
defaults(
448-
msg.integrations,
449-
this._mergeInitializeAndPlanIntegrations(planIntegrationOptions)
450-
);
458+
// NOTE: We need to merge integrations, not override them with assign
459+
// since it is possible to change the initialized integrations at runtime.
460+
msg.integrations = {
461+
...this._mergeInitializeAndPlanIntegrations(planIntegrationOptions),
462+
...msg.integrations
463+
}
451464

452465
this._invoke('track', new Track(msg));
453466

@@ -600,8 +613,15 @@ Analytics.prototype.page = function(
600613

601614
// Ensure properties has baseline spec properties.
602615
// TODO: Eventually move these entirely to `options.context.page`
603-
const defs = pageDefaults();
604-
defaults(properties, defs);
616+
// FIXME: This is purposely not overriding `defs`. There was a bug in the logic implemented by `@ndhoule/defaults`.
617+
// This bug made it so we only would overwrite values in `defs` that were set to `undefined`.
618+
// In some cases, though, pageDefaults will return defaults with values set to "" (such as `window.location.search` defaulting to "").
619+
// The decision to not fix this bus was made to preserve backwards compatibility.
620+
const defs = pageDefaults()
621+
properties = {
622+
...properties,
623+
...defs
624+
}
605625

606626
// Mirror user overrides to `options.context.page` (but exclude custom properties)
607627
// (Any page defaults get applied in `this.normalize` for consistency.)
@@ -621,8 +641,13 @@ Analytics.prototype.page = function(
621641
});
622642

623643
// Add the initialize integrations so the server-side ones can be disabled too
644+
// NOTE: We need to merge integrations, not override them with assign
645+
// since it is possible to change the initialized integrations at runtime.
624646
if (this.options.integrations) {
625-
defaults(msg.integrations, this.options.integrations);
647+
msg.integrations = {
648+
...this.options.integrations,
649+
...msg.integrations
650+
}
626651
}
627652

628653
this._invoke('page', new Page(msg));
@@ -674,8 +699,13 @@ Analytics.prototype.alias = function(
674699
});
675700

676701
// Add the initialize integrations so the server-side ones can be disabled too
702+
// NOTE: We need to merge integrations, not override them with assign
703+
// since it is possible to change the initialized integrations at runtime.
677704
if (this.options.integrations) {
678-
defaults(msg.integrations, this.options.integrations);
705+
msg.integrations = {
706+
...this.options.integrations,
707+
...msg.integrations
708+
}
679709
}
680710

681711
this._invoke('alias', new Alias(msg));
@@ -967,15 +997,19 @@ Analytics.prototype._parseQuery = function(query: string): SegmentAnalytics {
967997
*/
968998

969999
Analytics.prototype.normalize = function(msg: {
970-
context: { page };
1000+
options: { [key: string]: unknown }
1001+
context: { page: Partial<PageDefaults> };
9711002
anonymousId: string;
9721003
}): object {
9731004
msg = normalize(msg, Object.keys(this._integrations));
9741005
if (msg.anonymousId) user.anonymousId(msg.anonymousId);
9751006
msg.anonymousId = user.anonymousId();
9761007

9771008
// Ensure all outgoing requests include page data in their contexts.
978-
msg.context.page = defaults(msg.context.page || {}, pageDefaults());
1009+
msg.context.page = {
1010+
...pageDefaults(),
1011+
...msg.context.page
1012+
};
9791013

9801014
return msg;
9811015
};

lib/cookie.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import cloneDeep from 'lodash.clonedeep'
1010
var bindAll = require('bind-all');
1111
var cookie = require('@segment/cookie');
1212
var debug = require('debug')('analytics.js:cookie');
13-
var defaults = require('@ndhoule/defaults');
1413
var topDomain = require('@segment/top-domain');
1514

15+
const MAX_AGE_ONE_YEAR = 31536000000
16+
1617
/**
1718
* Initialize a new `Cookie` with `options`.
1819
*
@@ -32,16 +33,20 @@ Cookie.prototype.options = function(options?: CookieOptions) {
3233

3334
options = options || {};
3435

35-
var domain = '.' + topDomain(window.location.href);
36+
let domain = '.' + topDomain(window.location.href);
3637
if (domain === '.') domain = null;
3738

38-
this._options = defaults(options, {
39-
// default to a year
40-
maxage: 31536000000,
41-
path: '/',
39+
const defaults: CookieOptions = {
40+
maxage: MAX_AGE_ONE_YEAR,
4241
domain: domain,
42+
path: '/',
4343
sameSite: 'Lax'
44-
});
44+
}
45+
46+
this._options = {
47+
...defaults,
48+
...options
49+
};
4550

4651
// http://curl.haxx.se/rfc/cookie_spec.html
4752
// https://publicsuffix.org/list/effective_tld_names.dat

lib/entity.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import assignIn from 'lodash.assignin'
1010

1111
var cookie = require('./cookie');
1212
var debug = require('debug')('analytics:entity');
13-
var defaults = require('@ndhoule/defaults');
1413
var memory = require('./memory');
1514
var store = require('./store');
1615
var isodateTraverse = require('@segment/isodate-traverse');
@@ -74,7 +73,10 @@ Entity.prototype.storage = function() {
7473

7574
Entity.prototype.options = function(options?: InitOptions) {
7675
if (arguments.length === 0) return this._options;
77-
this._options = defaults(options || {}, this.defaults || {});
76+
this._options = {
77+
...this.defaults,
78+
...options
79+
}
7880
};
7981

8082
/**

lib/normalize.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import includes from 'lodash.includes'
66
*/
77

88
var debug = require('debug')('analytics.js:normalize');
9-
var defaults = require('@ndhoule/defaults');
109
var type = require('component-type');
1110
var uuid = require('uuid/v4');
1211
var md5 = require('spark-md5').hash;
1312

13+
1414
/**
1515
* HOP.
1616
*/
@@ -88,7 +88,11 @@ function normalize(msg: Message, list: Array<any>): NormalizedMessage {
8888
delete msg.options;
8989
ret.integrations = integrations;
9090
ret.context = context;
91-
ret = defaults(ret, msg);
91+
ret = {
92+
...msg,
93+
...ret
94+
}
95+
9296
debug('->', ret);
9397
return ret;
9498

lib/store.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
'use strict';
22

3+
import { StoreOptions } from './types';
4+
35
/*
46
* Module dependencies.
57
*/
68

79
var bindAll = require('bind-all');
8-
var defaults = require('@ndhoule/defaults');
910
var store = require('@segment/store');
1011

1112
/**
@@ -22,11 +23,14 @@ function Store(options?: { enabled: boolean }) {
2223
* Set the `options` for the store.
2324
*/
2425

25-
Store.prototype.options = function(options?: { enabled?: boolean }) {
26+
Store.prototype.options = function(options?: StoreOptions) {
2627
if (arguments.length === 0) return this._options;
2728

2829
options = options || {};
29-
defaults(options, { enabled: true });
30+
options = {
31+
enabled: true,
32+
...options
33+
};
3034

3135
this.enabled = options.enabled && store.enabled;
3236
this._options = options;

lib/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface CookieOptions {
3737
domain?: string;
3838
path?: string;
3939
secure?: boolean;
40+
sameSite?: string
4041
}
4142

4243
export interface MetricsOptions {
@@ -46,7 +47,7 @@ export interface MetricsOptions {
4647
maxQueueSize?: number;
4748
}
4849

49-
interface StoreOptions {
50+
export interface StoreOptions {
5051
enabled?: boolean;
5152
}
5253

package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@segment/analytics.js-core",
33
"author": "Segment <[email protected]>",
4-
"version": "4.1.4",
4+
"version": "4.1.5",
55
"description": "The hassle-free way to integrate analytics into any web application.",
66
"types": "lib/index.d.ts",
77
"keywords": [
@@ -30,7 +30,6 @@
3030
},
3131
"homepage": "https://github.com/segmentio/analytics.js-core#readme",
3232
"dependencies": {
33-
"@ndhoule/defaults": "^2.0.1",
3433
"@segment/canonical": "^1.0.0",
3534
"@segment/cookie": "^1.1.5",
3635
"@segment/is-meta": "^1.0.0",

test/analytics.test.ts

+40
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var pageDefaults = require('../build/pageDefaults');
1111
var sinon = require('sinon');
1212
var tick = require('next-tick');
1313
var trigger = require('compat-trigger-event');
14+
1415
var Identify = Facade.Identify;
1516
var cookie = Analytics.cookie;
1617
var group = analytics.group();
@@ -828,6 +829,22 @@ describe('Analytics', function() {
828829
});
829830
});
830831

832+
it('should should not overwrite context.page values due to an existing bug', function() {
833+
analytics.page({ prop: true, context: { page: { search: "lol" } } }, { context: { page: { search: "" } } });
834+
var page = analytics._invoke.args[0][1];
835+
// FIXME: This assert should fail once the bug is fixed
836+
assert.notDeepEqual(page.context(), {
837+
page: {
838+
...defaults,
839+
search: "lol",
840+
},
841+
});
842+
// FIXME: This assert should fail once the bug is fixed
843+
assert.deepEqual(page.context(), {
844+
page: defaults,
845+
});
846+
});
847+
831848
it('should emit page', function(done) {
832849
analytics.once('page', function(category, name, props, opts) {
833850
assert(category === 'category');
@@ -1608,6 +1625,29 @@ describe('Analytics', function() {
16081625
assert.deepEqual(track.context(), { page: contextPage });
16091626
});
16101627

1628+
it('should support overwriting context.page fields', function() {
1629+
analytics.track(
1630+
'event',
1631+
{},
1632+
{
1633+
context: {
1634+
page: {
1635+
title: 'lol'
1636+
}
1637+
}
1638+
}
1639+
);
1640+
1641+
var track = analytics._invoke.args[0][1];
1642+
assert.deepEqual(
1643+
track.context().page,
1644+
{
1645+
...contextPage,
1646+
title: 'lol'
1647+
}
1648+
);
1649+
});
1650+
16111651
it('should accept context.traits', function() {
16121652
analytics.track('event', { prop: 1 }, { traits: { trait: true } });
16131653
var track = analytics._invoke.args[0][1];

test/cookie.test.ts

+9
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ describe('cookie', function() {
6363
assert(cookie.options().maxage === 31536000000);
6464
});
6565

66+
it('should have default options', function() {
67+
cookie.options({ domain: '' });
68+
69+
assert(cookie.options().maxage === 31536000000);
70+
assert(cookie.options().path === '/');
71+
assert(cookie.options().domain === '');
72+
assert(cookie.options().sameSite === 'Lax');
73+
});
74+
6675
it('should set the domain correctly', function() {
6776
cookie.options({ domain: '' });
6877
assert(cookie.options().domain === '');

test/normalize.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ describe('normalize', function() {
6464
}
6565
});
6666
});
67+
68+
it('should merge with defaults', function() {
69+
opts.context = { foo: 5 };
70+
var out = normalize(msg, list);
71+
assert.deepEqual(out.integrations, {});
72+
assert.deepEqual(out.context, { foo: 5 });
73+
74+
msg.options = { integrations: { Segment: true }, context: { foo: 6 } };
75+
out = normalize(msg, list);
76+
assert.deepEqual(out.integrations, { Segment: true });
77+
assert.deepEqual(out.context, { foo: 6 });
78+
});
6779
});
6880

6981
describe('integrations', function() {

test/store.test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,11 @@ describe('store', function() {
4343
assert(store.options().enabled === false);
4444
assert(store.enabled === false);
4545
});
46+
47+
it('should have default options', function() {
48+
store.options({});
49+
50+
assert(store.options().enabled);
51+
});
4652
});
4753
});

0 commit comments

Comments
 (0)