Skip to content

Commit e259483

Browse files
authored
Merge pull request #33 from adobe/max-call-stack
Guard against max call stack
2 parents eb1dc6b + b94e899 commit e259483

File tree

5 files changed

+45
-34
lines changed

5 files changed

+45
-34
lines changed

distiller.js

+22-16
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
* OF ANY KIND, either express or implied. See the License for the specific language
1010
* governing permissions and limitations under the License.
1111
*/
12+
/* eslint-disable max-classes-per-file */
1213
/*
14+
* @module distiller
1315
* This module is another service worker, which will handle the number crunching, i.e.
1416
* filtering, aggregating, and summarizing the data.
1517
*/
16-
import { producer } from "./utils.js";
17-
/* eslint-disable max-classes-per-file */
18+
import { urlProducer } from './utils.js';
1819
/**
1920
* @typedef {Object} RawEvent - a raw RUM event
2021
* @property {string} checkpoint - the name of the event that happened
@@ -105,11 +106,11 @@ class Aggregate {
105106
}
106107

107108
get min() {
108-
return Math.min(...this.values);
109+
return this.values.reduce((min, val) => Math.min(min, val), Infinity);
109110
}
110111

111112
get max() {
112-
return Math.max(...this.values);
113+
return this.values.reduce((max, val) => Math.max(max, val), -Infinity);
113114
}
114115

115116
get share() {
@@ -393,16 +394,19 @@ export class DataChunks {
393394
* @param {string} baseFacet name of the base facet, from which to derive the clusters
394395
* @param {object} clusterOptions options
395396
* @param {number} clusterOptions.count number of clusters, The default value is log10(nValues)
396-
* @param {function} clusterOptions.producer function that takes the cluster value and returns all possible cluster values
397+
* @param {function} clusterOptions.producer function that takes the cluster value and returns
398+
* all possible cluster values
397399
*/
398-
addClusterFacet(facetName, baseFacet, { count: clustercount = Math.floor(Math.log10(this.facets[baseFacet].length)),
399-
producer: urlProducer }) {
400+
addClusterFacet(facetName, baseFacet, {
401+
count: clustercount = Math.floor(Math.log10(this.facets[baseFacet].length)),
402+
producer = urlProducer,
403+
}) {
400404
const facetValues = this.facets[baseFacet];
401405

402406
const createClusterMap = () => {
403407
const clusterMap = facetValues.reduce((map, facet) => {
404408
const clusters = producer(facet.value);
405-
clusters.forEach(cluster => {
409+
clusters.forEach((cluster) => {
406410
if (!map.has(cluster)) {
407411
map.set(cluster, 0);
408412
}
@@ -412,24 +416,26 @@ export class DataChunks {
412416
}, new Map());
413417

414418
// Find the most occurring cluster
415-
const [mostOccurringCluster] = [...clusterMap.entries()].sort((a, b) => b[1] - a[1]).map(([cluster]) => cluster);
419+
const [mostOccurringCluster] = [...clusterMap.entries()]
420+
.sort((a, b) => b[1] - a[1])
421+
.map(([cluster]) => cluster);
416422

417423
// Calculate the total number of items in the superset cluster
418424
const totalItemsInSupersetCluster = Math.floor(facetValues.length + clustercount);
419425

420426
return { clusterMap, mostOccurringCluster, totalItemsInSupersetCluster };
421427
};
422428

423-
const { clusterMap, mostOccurringCluster, totalItemsInSupersetCluster } = createClusterMap();
429+
const { clusterMap } = createClusterMap();
424430
const sortedClusters = [...clusterMap.entries()]
425-
.sort((a, b) => b[1] - a[1])
426-
.slice(0, clustercount)
427-
.map(([cluster]) => cluster);
431+
.sort((a, b) => b[1] - a[1])
432+
.slice(0, clustercount)
433+
.map(([cluster]) => cluster);
428434

429435
this.addFacet(facetName, (bundle) => {
430-
const facetMatch = facetValues.find(f => f.entries.some(e => e.id === bundle.id));
431-
const clusters = producer(facetMatch.value);
432-
return [ facetMatch, ...clusters.filter(cluster => sortedClusters.includes(cluster)) ];
436+
const facetMatch = facetValues.find((f) => f.entries.some((e) => e.id === bundle.id));
437+
const clusters = producer(facetMatch.value);
438+
return [facetMatch, ...clusters.filter((cluster) => sortedClusters.includes(cluster))];
433439
});
434440
}
435441

facets.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export const facets = {
193193
}
194194
return u.toString();
195195
}),
196-
};
196+
};
197197

198198
/**
199199
* A facet function takes a bundle and returns an array of facet values.

stats.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,15 @@ export function roundToConfidenceInterval(
215215
// e.g. 3.14 and 3.16 have 2 significant digits in common
216216
const maxStr = max.toPrecision(`${max}`.length);
217217
const minStr = min.toPrecision(`${min}`.length);
218-
const common = Math.min(maxStr.split('').reduce((acc, digit, i) => {
219-
if (digit === minStr[i]) {
220-
return acc + 1;
221-
}
222-
return acc;
223-
}, 0), Number.isNaN(maxPrecision) ? Infinity : maxPrecision);
218+
const common = Math.min(
219+
maxStr.length > 0 ? [...maxStr].reduce((acc, digit, i) => {
220+
if (digit === minStr[i]) {
221+
return acc + 1;
222+
}
223+
return acc;
224+
}, 0) : 0,
225+
Number.isNaN(maxPrecision) ? Infinity : maxPrecision,
226+
);
224227
const precision = Math.max(
225228
Math.min(2, Number.isNaN(maxPrecision) ? Infinity : maxPrecision),
226229
common,

test/distiller.test.js

+10-8
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,8 @@ describe('DataChunks', () => {
449449
assert.equal(totals.toptime.mean, 150);
450450
assert.equal(totals.clickcount.sum, 1);
451451
assert.equal(totals.clickcount.mean, 0.5);
452+
assert.equal(totals.clickcount.min, 0);
453+
assert.equal(totals.clickcount.max, 1);
452454
});
453455

454456
it('DataChunk.aggregate()', () => {
@@ -822,7 +824,7 @@ describe('DataChunks', () => {
822824
});
823825

824826
describe('DataChunks.hasConversion', () => {
825-
const chunks = [
827+
const testChunks = [
826828
{
827829
date: '2024-05-06',
828830
rumBundles: [
@@ -887,7 +889,7 @@ describe('DataChunks.hasConversion', () => {
887889

888890
it('will tag bundles with convert and not-convert based on a filter spec', () => {
889891
const d = new DataChunks();
890-
d.load(chunks);
892+
d.load(testChunks);
891893

892894
const spec = {
893895
facetOne: ['top'],
@@ -906,7 +908,7 @@ describe('DataChunks.hasConversion', () => {
906908

907909
it('unknown facet in filter spec', () => {
908910
const d = new DataChunks();
909-
d.load(chunks);
911+
d.load(testChunks);
910912

911913
const spec = {
912914
facetOne: ['top'],
@@ -937,7 +939,7 @@ describe('DataChunks.addClusterFacet()', () => {
937939

938940
// Add a cluster facet based on the 'url' facet
939941
d.addClusterFacet('urlCluster', 'url', {
940-
count: Math.log10(d.facets.url.length),
942+
count: Math.log10(d.facets.url.length),
941943
});
942944

943945
const { facets } = d;
@@ -954,7 +956,7 @@ describe('DataChunks.addClusterFacet()', () => {
954956

955957
// Add a cluster facet based on the 'url' facet
956958
d.addClusterFacet('urlCluster', 'url', {
957-
count: Math.log10(d.facets.url.length),
959+
count: Math.log10(d.facets.url.length),
958960
});
959961

960962
const { facets } = d;
@@ -972,7 +974,7 @@ describe('DataChunks.addClusterFacet()', () => {
972974
// Add a cluster facet based on the 'url' facet
973975
const count = Math.floor(Math.log10(92));
974976
d.addClusterFacet('urlCluster', 'url', {
975-
count,
977+
count,
976978
});
977979

978980
// Check if the count is correct
@@ -988,7 +990,7 @@ describe('DataChunks.addClusterFacet()', () => {
988990

989991
// Add a cluster facet based on the 'url' facet
990992
d.addClusterFacet('urlCluster', 'url', {
991-
count: Math.log10(d.facets.url.length),
993+
count: Math.log10(d.facets.url.length),
992994
});
993995

994996
const { facets } = d;
@@ -997,4 +999,4 @@ describe('DataChunks.addClusterFacet()', () => {
997999
const mostOccurringCluster = facets.urlCluster[0];
9981000
assert.ok(mostOccurringCluster.value, '/developer');
9991001
});
1000-
});
1002+
});

utils.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ export function addCalculatedProps(bundle) {
237237
return bundle;
238238
}
239239

240-
export function producer(url) {
240+
export function urlProducer(url) {
241241
const path = new URL(url).pathname;
242242
return path
243243
.split('/')
@@ -246,10 +246,10 @@ export function producer(url) {
246246
...acc,
247247
[
248248
...acc.length ? [acc[acc.length - 1].split('/').slice(1)] : [],
249-
part
249+
part,
250250
]
251251
.flat()
252252
.join('/')
253-
.padStart(part.length + 1, '/')
253+
.padStart(part.length + 1, '/'),
254254
], []);
255255
}

0 commit comments

Comments
 (0)