Skip to content

Commit bcc8a1c

Browse files
committed
Add support for named global context
1 parent d97797f commit bcc8a1c

File tree

7 files changed

+154
-24
lines changed

7 files changed

+154
-24
lines changed

api-docs/docs/browser-tracker/browser-tracker.api.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface ActivityTrackingConfigurationCallback {
2929
}
3030

3131
// @public
32-
export function addGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive>, trackers?: Array<string>): void;
32+
export function addGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive> | Record<string, ConditionalContextProvider | ContextPrimitive>, trackers?: Array<string>): void;
3333

3434
// @public
3535
export function addPlugin(configuration: BrowserPluginConfiguration, trackers?: Array<string>): void;
@@ -293,7 +293,7 @@ export function preservePageViewId(trackers?: Array<string>): void;
293293
export type PreservePageViewIdForUrl = boolean | "full" | "pathname" | "pathnameAndSearch";
294294

295295
// @public
296-
export function removeGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive>, trackers?: Array<string>): void;
296+
export function removeGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive | string>, trackers?: Array<string>): void;
297297

298298
// @public
299299
export type RequestFailure = {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@snowplow/browser-tracker",
5+
"comment": "Add support for named global context",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@snowplow/browser-tracker"
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@snowplow/tracker-core",
5+
"comment": "Add support for named global context",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@snowplow/tracker-core"
10+
}

libraries/tracker-core/src/contexts.ts

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,11 @@ export interface GlobalContexts {
116116
* Adds conditional or primitive global contexts
117117
* @param contexts - An Array of either Conditional Contexts or Primitive Contexts
118118
*/
119-
addGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive>): void;
119+
addGlobalContexts(
120+
contexts:
121+
| Array<ConditionalContextProvider | ContextPrimitive>
122+
| Record<string, ConditionalContextProvider | ContextPrimitive>
123+
): void;
120124

121125
/**
122126
* Removes all global contexts
@@ -127,7 +131,7 @@ export interface GlobalContexts {
127131
* Removes previously added global context, performs a deep comparison of the contexts or conditional contexts
128132
* @param contexts - An Array of either Condition Contexts or Primitive Contexts
129133
*/
130-
removeGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive>): void;
134+
removeGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive | string>): void;
131135

132136
/**
133137
* Returns all applicable global contexts for a specified event
@@ -142,6 +146,8 @@ export interface GlobalContexts {
142146
export function globalContexts(): GlobalContexts {
143147
let globalPrimitives: Array<ContextPrimitive> = [];
144148
let conditionalProviders: Array<ConditionalContextProvider> = [];
149+
let namedPrimitives: Record<string, ContextPrimitive> = {};
150+
let namedConditionalProviders: Record<string, ConditionalContextProvider> = {};
145151

146152
/**
147153
* Returns all applicable global contexts for a specified event
@@ -152,46 +158,75 @@ export function globalContexts(): GlobalContexts {
152158
const eventSchema = getUsefulSchema(event);
153159
const eventType = getEventType(event);
154160
const contexts: Array<SelfDescribingJson> = [];
155-
const generatedPrimitives = generatePrimitives(globalPrimitives, event, eventType, eventSchema);
161+
const generatedPrimitives = generatePrimitives(
162+
globalPrimitives.concat(Object.values(namedPrimitives)),
163+
event,
164+
eventType,
165+
eventSchema
166+
);
156167
contexts.push(...generatedPrimitives);
157168

158-
const generatedConditionals = generateConditionals(conditionalProviders, event, eventType, eventSchema);
169+
const generatedConditionals = generateConditionals(
170+
conditionalProviders.concat(Object.values(namedConditionalProviders)),
171+
event,
172+
eventType,
173+
eventSchema
174+
);
159175
contexts.push(...generatedConditionals);
160176

161177
return contexts;
162178
};
163179

164180
return {
165181
getGlobalPrimitives(): Array<ContextPrimitive> {
166-
return globalPrimitives;
182+
return globalPrimitives.concat(Object.values(namedPrimitives));
167183
},
168184

169185
getConditionalProviders(): Array<ConditionalContextProvider> {
170-
return conditionalProviders;
186+
return conditionalProviders.concat(Object.values(namedConditionalProviders));
171187
},
172188

173-
addGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive>): void {
174-
const acceptedConditionalContexts: ConditionalContextProvider[] = [];
175-
const acceptedContextPrimitives: ContextPrimitive[] = [];
176-
for (const context of contexts) {
177-
if (isConditionalContextProvider(context)) {
178-
acceptedConditionalContexts.push(context);
179-
} else if (isContextPrimitive(context)) {
180-
acceptedContextPrimitives.push(context);
189+
addGlobalContexts(
190+
contexts:
191+
| Array<ConditionalContextProvider | ContextPrimitive>
192+
| Record<string, ConditionalContextProvider | ContextPrimitive>
193+
): void {
194+
if (Array.isArray(contexts)) {
195+
const acceptedConditionalContexts: ConditionalContextProvider[] = [];
196+
const acceptedContextPrimitives: ContextPrimitive[] = [];
197+
for (const context of contexts) {
198+
if (isConditionalContextProvider(context)) {
199+
acceptedConditionalContexts.push(context);
200+
} else if (isContextPrimitive(context)) {
201+
acceptedContextPrimitives.push(context);
202+
}
203+
}
204+
globalPrimitives = globalPrimitives.concat(acceptedContextPrimitives);
205+
conditionalProviders = conditionalProviders.concat(acceptedConditionalContexts);
206+
} else {
207+
for (const [name, context] of Object.entries(contexts)) {
208+
if (isConditionalContextProvider(context)) {
209+
namedConditionalProviders[name] = context;
210+
} else if (isContextPrimitive(context)) {
211+
namedPrimitives[name] = context;
212+
}
181213
}
182214
}
183-
globalPrimitives = globalPrimitives.concat(acceptedContextPrimitives);
184-
conditionalProviders = conditionalProviders.concat(acceptedConditionalContexts);
185215
},
186216

187217
clearGlobalContexts(): void {
188218
conditionalProviders = [];
189219
globalPrimitives = [];
220+
namedConditionalProviders = {};
221+
namedPrimitives = {};
190222
},
191223

192-
removeGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive>): void {
224+
removeGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive | string>): void {
193225
for (const context of contexts) {
194-
if (isConditionalContextProvider(context)) {
226+
if (typeof context === 'string') {
227+
delete namedConditionalProviders[context];
228+
delete namedPrimitives[context];
229+
} else if (isConditionalContextProvider(context)) {
195230
conditionalProviders = conditionalProviders.filter(
196231
(item) => JSON.stringify(item) !== JSON.stringify(context)
197232
);

libraries/tracker-core/src/core.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,11 @@ export interface TrackerCore {
273273
* Adds contexts globally, contexts added here will be attached to all applicable events
274274
* @param contexts - An array containing either contexts or a conditional contexts
275275
*/
276-
addGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive>): void;
276+
addGlobalContexts(
277+
contexts:
278+
| Array<ConditionalContextProvider | ContextPrimitive>
279+
| Record<string, ConditionalContextProvider | ContextPrimitive>
280+
): void;
277281

278282
/**
279283
* Removes all global contexts
@@ -284,7 +288,7 @@ export interface TrackerCore {
284288
* Removes previously added global context, performs a deep comparison of the contexts or conditional contexts
285289
* @param contexts - An array containing either contexts or a conditional contexts
286290
*/
287-
removeGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive>): void;
291+
removeGlobalContexts(contexts: Array<ConditionalContextProvider | ContextPrimitive | string>): void;
288292

289293
/**
290294
* Add a plugin into the plugin collection after Core has already been initialised

libraries/tracker-core/test/contexts.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,75 @@ test('Add global contexts', (t) => {
215215
t.is(globalContexts.getConditionalProviders().length, 2, 'Correct number of conditional providers added');
216216
});
217217

218+
test('Handle named global contexts', (t) => {
219+
const geolocationContext = {
220+
schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0',
221+
data: {
222+
latitude: 40.0,
223+
longitude: 55.1,
224+
},
225+
};
226+
227+
function eventTypeContextGenerator(args?: contexts.ContextEvent) {
228+
const context: SelfDescribingJson = {
229+
schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1',
230+
data: {
231+
osType: 'ubuntu',
232+
osVersion: '2018.04',
233+
deviceManufacturer: 'ASUS',
234+
deviceModel: args ? String(args['eventType']) : '',
235+
},
236+
};
237+
return context;
238+
}
239+
240+
const bothRuleSet = {
241+
accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'],
242+
reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'],
243+
};
244+
245+
const filterFunction = function (args?: contexts.ContextEvent) {
246+
return args?.eventType === 'ue';
247+
};
248+
249+
const filterProvider: contexts.FilterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]];
250+
const ruleSetProvider: contexts.RuleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]];
251+
252+
const namedContexts = {
253+
filters: filterProvider,
254+
rules: ruleSetProvider,
255+
static: geolocationContext,
256+
generator: eventTypeContextGenerator,
257+
};
258+
const globalContexts = contexts.globalContexts();
259+
260+
globalContexts.addGlobalContexts(namedContexts);
261+
t.is(globalContexts.getGlobalPrimitives().length, 2, 'Correct number of primitives added');
262+
t.is(globalContexts.getConditionalProviders().length, 2, 'Correct number of conditional providers added');
263+
264+
globalContexts.removeGlobalContexts(['static', 'rules']);
265+
t.is(globalContexts.getGlobalPrimitives().length, 1, 'Correct number of primitives removed');
266+
t.is(globalContexts.getConditionalProviders().length, 1, 'Correct number of conditional providers removed');
267+
268+
globalContexts.clearGlobalContexts();
269+
t.is(globalContexts.getGlobalPrimitives().length, 0, 'All primitives removed');
270+
t.is(globalContexts.getConditionalProviders().length, 0, 'All conditional providers removed');
271+
272+
globalContexts.addGlobalContexts([geolocationContext]);
273+
globalContexts.addGlobalContexts({ geo: geolocationContext });
274+
t.is(globalContexts.getGlobalPrimitives().length, 2, 'Treats anonymous and named globals separately');
275+
276+
const mutatedGeolocationContext = JSON.parse(JSON.stringify(geolocationContext));
277+
mutatedGeolocationContext.data.latitude = 30;
278+
279+
globalContexts.addGlobalContexts({ geo: mutatedGeolocationContext });
280+
t.deepEqual(
281+
globalContexts.getGlobalPrimitives(),
282+
[geolocationContext, mutatedGeolocationContext],
283+
'Upserts named globals'
284+
);
285+
});
286+
218287
test('Remove one of two global context primitives', (t) => {
219288
const geolocationContext = {
220289
schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0',

trackers/browser-tracker/src/api.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,9 @@ export function trackSelfDescribingEvent(event: SelfDescribingEvent & CommonEven
411411
* @param trackers - The tracker identifiers which the global contexts will be added to
412412
*/
413413
export function addGlobalContexts(
414-
contexts: Array<ConditionalContextProvider | ContextPrimitive>,
414+
contexts:
415+
| Array<ConditionalContextProvider | ContextPrimitive>
416+
| Record<string, ConditionalContextProvider | ContextPrimitive>,
415417
trackers?: Array<string>
416418
) {
417419
dispatchToTrackers(trackers, (t) => {
@@ -426,7 +428,7 @@ export function addGlobalContexts(
426428
* @param trackers - The tracker identifiers which the global contexts will be remove from
427429
*/
428430
export function removeGlobalContexts(
429-
contexts: Array<ConditionalContextProvider | ContextPrimitive>,
431+
contexts: Array<ConditionalContextProvider | ContextPrimitive | string>,
430432
trackers?: Array<string>
431433
) {
432434
dispatchToTrackers(trackers, (t) => {

0 commit comments

Comments
 (0)