mirror of
https://github.com/rxliuli/apps.apple.com.git
synced 2025-11-09 22:00:32 +00:00
155 lines
6.7 KiB
JavaScript
155 lines
6.7 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.EventLinter = void 0;
|
|
const object_reader_1 = require("../json/reader/object-reader");
|
|
const optional_1 = require("../types/optional");
|
|
const numerics = require("./helpers/numerics");
|
|
/**
|
|
* A type which applies common business rules to metrics fields
|
|
* and generates events which are ready for posting to Figaro.
|
|
*
|
|
* The common business rules are:
|
|
* - Add base event fields provided by linter configuration provider object
|
|
* - Set clientBuiltType and resourceRevNum fields based on EventLinterEnvironment object values
|
|
* - Set xpSendMethod field to "jet-js"
|
|
* - Combine pageType and pageId using compound separator provided by linter configuration provider
|
|
* and set result to "page" field.
|
|
* - Apply event field de-resolution rules provided by linter configuration provider object
|
|
* - Set the "position" field for events of "media" type.
|
|
*/
|
|
class EventLinter {
|
|
/**
|
|
* Create an event linter.
|
|
*
|
|
* @param options - The options which specify various behaviors of the new linter.
|
|
* This object will be frozen.
|
|
*/
|
|
constructor(options) {
|
|
this.options = Object.freeze(options);
|
|
}
|
|
// MARK: Public Properties
|
|
/**
|
|
* Topic to use if an event fields blob does not specify one.
|
|
*/
|
|
get defaultTopic() {
|
|
return this.options.defaultTopic;
|
|
}
|
|
// MARK: Utilities
|
|
/**
|
|
* Reduce the accuracy of fields in a blob according to
|
|
* a given array of rules provided by linter configuration object.
|
|
*
|
|
* @param eventFields - The fields of an event to reduce the accuracy of.
|
|
* @param rules - An array of de-resolution rules to apply to event fields.
|
|
*/
|
|
applyDeResolutionRules(eventFields, rules) {
|
|
const eventFieldsReader = new object_reader_1.ObjectReader(eventFields);
|
|
for (const rule of rules) {
|
|
const value = eventFieldsReader.asNumber(rule.fieldName);
|
|
if ((0, optional_1.isNothing)(value)) {
|
|
continue;
|
|
}
|
|
let magnitude = rule.magnitude;
|
|
if ((0, optional_1.isNothing)(magnitude)) {
|
|
magnitude = 1024 * 1024;
|
|
}
|
|
let significantDigits = rule.significantDigits;
|
|
if ((0, optional_1.isNothing)(significantDigits)) {
|
|
significantDigits = 2;
|
|
}
|
|
if (magnitude <= 0.0 || significantDigits < 0.0) {
|
|
// This is the failure mode from MetricsKit.
|
|
eventFields[rule.fieldName] = Number.NaN;
|
|
continue;
|
|
}
|
|
const scaledValue = value / magnitude;
|
|
eventFields[rule.fieldName] = numerics.reduceSignificantDigits(scaledValue, significantDigits);
|
|
}
|
|
}
|
|
// MARK: Rules
|
|
/**
|
|
* Apply the rules which are universal to all metrics events
|
|
* to a given metrics fields linter.
|
|
*
|
|
* @param eventFields - The fields which will be used to construct a built event.
|
|
* @param topic - The topic the built event will be submitted to.
|
|
*/
|
|
decorateCommonEventFields(eventFields, topic) {
|
|
const eventFieldsReader = new object_reader_1.ObjectReader(eventFields);
|
|
const configurationProvider = this.options.configuration;
|
|
// - Base metrics fields.
|
|
const baseFields = configurationProvider.baseFields(topic);
|
|
if ((0, optional_1.isSome)(baseFields)) {
|
|
Object.assign(eventFields, baseFields);
|
|
}
|
|
// - Universal basic fields.
|
|
eventFields["clientBuildType"] = this.options.environment.buildType;
|
|
eventFields["resourceRevNum"] = this.options.environment.jsVersion;
|
|
eventFields["xpSendMethod"] = "jet-js";
|
|
// - Page.
|
|
const pageType = eventFieldsReader.asString("pageType");
|
|
const pageId = eventFieldsReader.asString("pageId");
|
|
if ((0, optional_1.isSome)(pageType) && (0, optional_1.isSome)(pageId) && (0, optional_1.isNothing)(eventFields["page"])) {
|
|
const bagValue = configurationProvider.compoundSeparator(topic);
|
|
const separator = (0, optional_1.isSome)(bagValue) ? (0, optional_1.unwrapOptional)(bagValue) : "_";
|
|
eventFields["page"] = `${pageType}${separator}${pageId}`;
|
|
}
|
|
// - Field value resolution reduction.
|
|
const rules = configurationProvider.deResolutionRules(topic);
|
|
this.applyDeResolutionRules(eventFields, rules);
|
|
}
|
|
/**
|
|
* Apply the rules specific to the `media` event.
|
|
*
|
|
* @param eventFields - The fields which will be used to construct a built event.
|
|
*/
|
|
decorateMediaEventEvents(eventFields) {
|
|
const eventFieldsReader = new object_reader_1.ObjectReader(eventFields);
|
|
const position = eventFieldsReader.asNumber("position");
|
|
if ((0, optional_1.isSome)(position)) {
|
|
eventFields["position"] = Math.round(position);
|
|
}
|
|
}
|
|
// MARK: Decorating Event Fields
|
|
/**
|
|
* Lint metrics event fields by applying the common business rules to a given fields blob.
|
|
*
|
|
* @remarks
|
|
*
|
|
* Note: A deep copy of event fields is created by linter using `JSON.parse(JSON.stringify(eventFields))`.
|
|
* The original event fields are not modified.
|
|
*
|
|
* @param eventFields - The fields to decorate.
|
|
* @param context - The additional event linter context to be passed to all
|
|
* event linter rules. This is a free-form object so clients can pass custom
|
|
* context information.
|
|
* @returns Decorated fields ready for creating a metrics event.
|
|
*/
|
|
lint(eventFields, context = {}) {
|
|
const eventFieldsReader = new object_reader_1.ObjectReader(eventFields);
|
|
const eventType = eventFieldsReader.asString("eventType");
|
|
if (this.options.isLoggingEnabled) {
|
|
console.log(`Building event for event type: ${eventType !== null && eventType !== void 0 ? eventType : "<null>"}`);
|
|
}
|
|
// Make sure we have a deep copy of an object.
|
|
const decoratedEventFields = JSON.parse(JSON.stringify(eventFields));
|
|
const value = eventFieldsReader.asString("topic");
|
|
const topic = (0, optional_1.isSome)(value) ? (0, optional_1.unwrapOptional)(value) : this.options.defaultTopic;
|
|
this.decorateCommonEventFields(decoratedEventFields, topic);
|
|
switch (eventType) {
|
|
case "media" /* MetricsEventType.media */:
|
|
this.decorateMediaEventEvents(decoratedEventFields);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
for (const rule of this.options.rules) {
|
|
rule.apply(decoratedEventFields, context);
|
|
}
|
|
return {
|
|
fields: decoratedEventFields,
|
|
};
|
|
}
|
|
}
|
|
exports.EventLinter = EventLinter;
|
|
//# sourceMappingURL=event-linter.js.map
|