168 lines
4.3 KiB
JavaScript
168 lines
4.3 KiB
JavaScript
import { getLogger } from '@sitespeed.io/log';
|
||
|
||
const log = getLogger('sitespeedio');
|
||
|
||
function joinNonEmpty(strings, delimeter) {
|
||
return strings.filter(Boolean).join(delimeter);
|
||
}
|
||
|
||
function toSafeKey(key) {
|
||
// U+2013 : EN DASH – as used on https://en.wikipedia.org/wiki/2019–20_coronavirus_pandemic
|
||
return key.replaceAll(/[ %&()+,./:?|~–]|%7C/g, '_');
|
||
}
|
||
|
||
export function keypathFromUrl(
|
||
urlString,
|
||
includeQueryParameters,
|
||
useHash,
|
||
group
|
||
) {
|
||
function flattenQueryParameters(parameters) {
|
||
return Object.keys(parameters).reduce(
|
||
(result, key) => joinNonEmpty([result, key, parameters[key]], '_'),
|
||
''
|
||
);
|
||
}
|
||
|
||
const url = new URL(urlString);
|
||
|
||
let path = toSafeKey(url.pathname);
|
||
|
||
if (includeQueryParameters) {
|
||
const parameters = {};
|
||
for (const [key, value] of url.searchParams) {
|
||
parameters[key] = value;
|
||
}
|
||
|
||
path = joinNonEmpty(
|
||
[path, toSafeKey(flattenQueryParameters(parameters))],
|
||
'_'
|
||
);
|
||
}
|
||
|
||
if (useHash && url.hash) {
|
||
path = joinNonEmpty([path, toSafeKey(url.hash)], '_');
|
||
}
|
||
|
||
const keys = [toSafeKey(group || url.hostname), path];
|
||
|
||
return joinNonEmpty(keys, '.');
|
||
}
|
||
|
||
function isNumericString(n) {
|
||
// eslint-disable-next-line unicorn/prefer-number-properties
|
||
return !isNaN(Number.parseFloat(n)) && isFinite(n);
|
||
}
|
||
|
||
export function flattenMessageData({ data, type }) {
|
||
function recursiveFlatten(target, keyPrefix, value) {
|
||
// super simple version to avoid flatten HAR and screenshot data
|
||
if (/(screenshots\.|har\.)/.test(keyPrefix)) {
|
||
return;
|
||
}
|
||
|
||
// Google is overloading User Timing marks
|
||
// See https://github.com/sitespeedio/browsertime/issues/257
|
||
if (keyPrefix.includes('userTimings.marks.goog_')) {
|
||
return;
|
||
}
|
||
|
||
// Google is overloading User Timing marks = the same using WebPageTest
|
||
// See https://github.com/sitespeedio/browsertime/issues/257
|
||
if (keyPrefix.includes('userTimes.goog_')) {
|
||
return;
|
||
}
|
||
|
||
// Hack to remove visual progress from default metrics
|
||
if (keyPrefix.includes('visualMetrics.VisualProgress')) {
|
||
return;
|
||
}
|
||
|
||
if (keyPrefix.includes('visualMetrics.videoRecordingStart')) {
|
||
return;
|
||
}
|
||
|
||
const valueType = typeof value;
|
||
|
||
switch (valueType) {
|
||
case 'number': {
|
||
{
|
||
if (Number.isFinite(value)) {
|
||
target[keyPrefix] = value;
|
||
} else {
|
||
log.warn(
|
||
`Non-finite number '${value}' found at path '${keyPrefix}' for '${type}' message (url = ${data.url})`
|
||
);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'object': {
|
||
{
|
||
if (value === null) {
|
||
break;
|
||
}
|
||
|
||
for (const key of Object.keys(value)) {
|
||
// Hey are you coming to the future from 1980s? Please don't
|
||
// look at this code, it's a ugly hack to make sure we can send assets
|
||
// to Graphite and don't send them with array position, instead
|
||
// use the url to generate the key
|
||
if (type === 'pagexray.pageSummary' && keyPrefix === 'assets') {
|
||
recursiveFlatten(
|
||
target,
|
||
joinNonEmpty(
|
||
[keyPrefix, toSafeKey(value[key].url || key)],
|
||
'.'
|
||
),
|
||
value[key]
|
||
);
|
||
} else {
|
||
recursiveFlatten(
|
||
target,
|
||
joinNonEmpty([keyPrefix, toSafeKey(key)], '.'),
|
||
value[key]
|
||
);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'string': {
|
||
{
|
||
if (isNumericString(value)) {
|
||
target[keyPrefix] = Number.parseFloat(value);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'boolean': {
|
||
{
|
||
target[keyPrefix] = value ? 1 : 0;
|
||
}
|
||
break;
|
||
}
|
||
case 'undefined': {
|
||
{
|
||
log.debug(
|
||
`Undefined value found at path '${keyPrefix}' for '${type}' message (url = ${data.url})`
|
||
);
|
||
}
|
||
break;
|
||
}
|
||
default: {
|
||
throw new Error(
|
||
'Unhandled value type ' +
|
||
valueType +
|
||
' found when flattening data for prefix ' +
|
||
keyPrefix
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
let returnValueValue = {};
|
||
recursiveFlatten(returnValueValue, '', data);
|
||
return returnValueValue;
|
||
}
|