Ghost/ghost/member-attribution/lib/UrlHistory.js
Fabien "egg" O'Carroll 104f84f252 Added eslint rule for file naming convention
As discussed with the product team we want to enforce kebab-case file names for
all files, with the exception of files which export a single class, in which
case they should be PascalCase and reflect the class which they export.

This will help find classes faster, and should push better naming for them too.

Some files and packages have been excluded from this linting, specifically when
a library or framework depends on the naming of a file for the functionality
e.g. Ember, knex-migrator, adapter-manager
2023-05-09 12:34:34 -04:00

92 lines
2.0 KiB
JavaScript

/**
* @typedef {Object} UrlHistoryItem
* @prop {string} [path]
* @prop {string} [id]
* @prop {string} [type]
* @prop {string} [referrerSource]
* @prop {string} [referrerMedium]
* @prop {string} [referrerUrl]
* @prop {number} time
*/
/**
* @typedef {UrlHistoryItem[]} UrlHistoryArray
*/
/**
* Types allowed to add in the URLHistory manually
*/
const ALLOWED_TYPES = ['post'];
/**
* Represents a validated history
*/
class UrlHistory {
/**
* @private
* @param {UrlHistoryArray} urlHistory
*/
constructor(urlHistory) {
/** @private */
this.history = urlHistory;
}
get length() {
return this.history.length;
}
/**
* Iterate from latest item to newest item (reversed!)
*/
*[Symbol.iterator]() {
yield* this.history.slice().reverse();
}
/**
* @private
* @param {any[]} history
* @returns {boolean}
*/
static isValidHistory(history) {
for (const item of history) {
const isValidIdEntry = typeof item?.id === 'string' && typeof item?.type === 'string' && ALLOWED_TYPES.includes(item.type);
const isValidPathEntry = typeof item?.path === 'string';
const isValidEntry = isValidPathEntry || isValidIdEntry;
if (!isValidEntry || !Number.isSafeInteger(item?.time)) {
return false;
}
}
return true;
}
/**
* @param {unknown} urlHistory
* @returns {UrlHistory}
*/
static create(urlHistory) {
if (!Array.isArray(urlHistory)) {
return new UrlHistory([]);
}
if (!this.isValidHistory(urlHistory)) {
return new UrlHistory([]);
}
const now = Date.now();
const filteredHistory = urlHistory.filter((item) => {
return now - item.time < this.MAX_AGE;
});
return new UrlHistory(filteredHistory);
}
/**
* @private
*/
static MAX_AGE = 1000 * 60 * 60 * 24;
}
module.exports = UrlHistory;