clarity-js 0.8.9 → 0.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.lintstagedrc.yml +3 -0
- package/biome.json +43 -0
- package/build/clarity.extended.js +1 -1
- package/build/clarity.insight.js +1 -1
- package/build/clarity.js +3095 -2876
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +3095 -2876
- package/build/clarity.performance.js +1 -1
- package/package.json +17 -10
- package/rollup.config.ts +84 -88
- package/src/clarity.ts +34 -28
- package/src/core/config.ts +2 -2
- package/src/core/event.ts +36 -32
- package/src/core/hash.ts +5 -6
- package/src/core/history.ts +10 -11
- package/src/core/index.ts +21 -11
- package/src/core/measure.ts +9 -5
- package/src/core/report.ts +9 -5
- package/src/core/scrub.ts +29 -20
- package/src/core/task.ts +73 -45
- package/src/core/time.ts +3 -3
- package/src/core/timeout.ts +2 -2
- package/src/core/version.ts +1 -1
- package/src/data/baseline.ts +60 -55
- package/src/data/consent.ts +2 -2
- package/src/data/custom.ts +8 -13
- package/src/data/dimension.ts +11 -7
- package/src/data/encode.ts +36 -30
- package/src/data/envelope.ts +38 -38
- package/src/data/extract.ts +86 -77
- package/src/data/index.ts +10 -6
- package/src/data/limit.ts +1 -1
- package/src/data/metadata.ts +305 -266
- package/src/data/metric.ts +18 -8
- package/src/data/ping.ts +8 -4
- package/src/data/signal.ts +18 -18
- package/src/data/summary.ts +6 -4
- package/src/data/token.ts +10 -8
- package/src/data/upgrade.ts +7 -3
- package/src/data/upload.ts +100 -49
- package/src/data/variable.ts +27 -20
- package/src/diagnostic/encode.ts +2 -2
- package/src/diagnostic/fraud.ts +3 -4
- package/src/diagnostic/internal.ts +11 -5
- package/src/diagnostic/script.ts +12 -8
- package/src/global.ts +1 -1
- package/src/insight/blank.ts +4 -4
- package/src/insight/encode.ts +23 -17
- package/src/insight/snapshot.ts +57 -37
- package/src/interaction/change.ts +9 -6
- package/src/interaction/click.ts +34 -28
- package/src/interaction/clipboard.ts +2 -2
- package/src/interaction/encode.ts +35 -31
- package/src/interaction/input.ts +11 -9
- package/src/interaction/pointer.ts +41 -30
- package/src/interaction/resize.ts +5 -5
- package/src/interaction/scroll.ts +20 -17
- package/src/interaction/selection.ts +12 -8
- package/src/interaction/submit.ts +2 -2
- package/src/interaction/timeline.ts +13 -9
- package/src/interaction/unload.ts +1 -1
- package/src/interaction/visibility.ts +2 -2
- package/src/layout/animation.ts +47 -41
- package/src/layout/discover.ts +5 -5
- package/src/layout/document.ts +31 -19
- package/src/layout/dom.ts +141 -91
- package/src/layout/encode.ts +52 -37
- package/src/layout/mutation.ts +321 -318
- package/src/layout/node.ts +104 -81
- package/src/layout/offset.ts +7 -6
- package/src/layout/region.ts +66 -43
- package/src/layout/schema.ts +15 -8
- package/src/layout/selector.ts +47 -25
- package/src/layout/style.ts +45 -37
- package/src/layout/target.ts +14 -10
- package/src/layout/traverse.ts +17 -11
- package/src/performance/blank.ts +1 -1
- package/src/performance/encode.ts +4 -4
- package/src/performance/interaction.ts +58 -70
- package/src/performance/navigation.ts +2 -2
- package/src/performance/observer.ts +59 -26
- package/src/queue.ts +16 -9
- package/tsconfig.json +1 -1
- package/tslint.json +25 -32
- package/types/core.d.ts +13 -13
- package/types/data.d.ts +32 -29
- package/types/diagnostic.d.ts +1 -1
- package/types/interaction.d.ts +5 -4
- package/types/layout.d.ts +36 -21
- package/types/performance.d.ts +6 -5
package/src/data/consent.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as dimension from "@src/data/dimension";
|
|
|
4
4
|
const enum ConsentType {
|
|
5
5
|
None = 0,
|
|
6
6
|
Implicit = 1,
|
|
7
|
-
General = 2
|
|
7
|
+
General = 2,
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export function config(track: boolean): void {
|
|
@@ -18,4 +18,4 @@ export function consent(): void {
|
|
|
18
18
|
|
|
19
19
|
function trackConsent(consent: ConsentType): void {
|
|
20
20
|
dimension.log(Dimension.Consent, consent.toString());
|
|
21
|
-
}
|
|
21
|
+
}
|
package/src/data/custom.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type CustomData, Event } from "@clarity-types/data";
|
|
2
2
|
import * as core from "@src/core";
|
|
3
3
|
import encode from "./encode";
|
|
4
4
|
|
|
@@ -7,17 +7,12 @@ export let data: CustomData = null;
|
|
|
7
7
|
// custom events allow 2 parameters or 1 parameter to be passed. If 2 are passed we
|
|
8
8
|
// consider it a key value pair. If only 1 is passed we only consider the event to have a value.
|
|
9
9
|
export function event(a: string, b: string): void {
|
|
10
|
-
if (core.active() &&
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} else {
|
|
18
|
-
data = { value: a }
|
|
19
|
-
}
|
|
20
|
-
encode(Event.Custom);
|
|
21
|
-
|
|
10
|
+
if (core.active() && a && typeof a === "string" && a.length < 255) {
|
|
11
|
+
if (b && typeof b === "string" && b.length < 255) {
|
|
12
|
+
data = { key: a, value: b };
|
|
13
|
+
} else {
|
|
14
|
+
data = { value: a };
|
|
15
|
+
}
|
|
16
|
+
encode(Event.Custom);
|
|
22
17
|
}
|
|
23
18
|
}
|
package/src/data/dimension.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Check,
|
|
1
|
+
import { Check, type Dimension, type DimensionData, Event, Setting } from "@clarity-types/data";
|
|
2
2
|
import * as limit from "@src/data/limit";
|
|
3
3
|
import encode from "./encode";
|
|
4
4
|
|
|
@@ -18,18 +18,20 @@ export function stop(): void {
|
|
|
18
18
|
limited = false;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export function log(dimension: Dimension,
|
|
21
|
+
export function log(dimension: Dimension, inputValue: string): void {
|
|
22
22
|
// Check valid value before moving ahead
|
|
23
|
-
if (
|
|
23
|
+
if (inputValue) {
|
|
24
24
|
// Ensure received value is casted into a string if it wasn't a string to begin with
|
|
25
|
-
value = `${
|
|
26
|
-
if (!(dimension in data)) {
|
|
25
|
+
const value = `${inputValue}`;
|
|
26
|
+
if (!(dimension in data)) {
|
|
27
|
+
data[dimension] = [];
|
|
28
|
+
}
|
|
27
29
|
if (data[dimension].indexOf(value) < 0) {
|
|
28
30
|
// Limit check to ensure we have a cap on number of dimensions we can collect
|
|
29
31
|
if (data[dimension].length > Setting.CollectionLimit) {
|
|
30
32
|
if (!limited) {
|
|
31
33
|
limited = true;
|
|
32
|
-
limit.trigger(Check.Collection);
|
|
34
|
+
limit.trigger(Check.Collection);
|
|
33
35
|
}
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
@@ -37,7 +39,9 @@ export function log(dimension: Dimension, value: string): void {
|
|
|
37
39
|
data[dimension].push(value);
|
|
38
40
|
// If this is a new value, track it as part of updates object
|
|
39
41
|
// This allows us to only send back new values in subsequent payloads
|
|
40
|
-
if (!(dimension in updates)) {
|
|
42
|
+
if (!(dimension in updates)) {
|
|
43
|
+
updates[dimension] = [];
|
|
44
|
+
}
|
|
41
45
|
updates[dimension].push(value);
|
|
42
46
|
}
|
|
43
47
|
}
|
package/src/data/encode.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { Event, Token } from "@clarity-types/data";
|
|
1
|
+
import { Event, type Token } from "@clarity-types/data";
|
|
2
2
|
import { time } from "@src/core/time";
|
|
3
3
|
import * as baseline from "@src/data/baseline";
|
|
4
4
|
import * as custom from "@src/data/custom";
|
|
5
5
|
import * as dimension from "@src/data/dimension";
|
|
6
|
+
import * as extract from "@src/data/extract";
|
|
6
7
|
import * as limit from "@src/data/limit";
|
|
7
8
|
import * as metric from "@src/data/metric";
|
|
8
9
|
import * as ping from "@src/data/ping";
|
|
9
10
|
import * as summary from "@src/data/summary";
|
|
10
11
|
import * as upgrade from "@src/data/upgrade";
|
|
11
12
|
import * as variable from "@src/data/variable";
|
|
12
|
-
import * as extract from "@src/data/extract";
|
|
13
13
|
import { queue, track } from "./upload";
|
|
14
14
|
|
|
15
|
-
export default function(event: Event): void {
|
|
16
|
-
|
|
17
|
-
let tokens: Token[] = [t, event];
|
|
15
|
+
export default function (event: Event): void {
|
|
16
|
+
const t = time();
|
|
17
|
+
let tokens: Token[] = [t, event];
|
|
18
18
|
switch (event) {
|
|
19
|
-
case Event.Baseline:
|
|
20
|
-
|
|
19
|
+
case Event.Baseline: {
|
|
20
|
+
const b = baseline.state;
|
|
21
21
|
if (b) {
|
|
22
22
|
tokens = [b.time, b.event];
|
|
23
23
|
tokens.push(b.data.visible);
|
|
@@ -48,6 +48,7 @@ export default function(event: Event): void {
|
|
|
48
48
|
}
|
|
49
49
|
baseline.reset();
|
|
50
50
|
break;
|
|
51
|
+
}
|
|
51
52
|
case Event.Ping:
|
|
52
53
|
tokens.push(ping.data.gap);
|
|
53
54
|
queue(tokens);
|
|
@@ -72,10 +73,10 @@ export default function(event: Event): void {
|
|
|
72
73
|
tokens.push(custom.data.value);
|
|
73
74
|
queue(tokens);
|
|
74
75
|
break;
|
|
75
|
-
case Event.Variable:
|
|
76
|
-
|
|
76
|
+
case Event.Variable: {
|
|
77
|
+
const variableKeys = Object.keys(variable.data);
|
|
77
78
|
if (variableKeys.length > 0) {
|
|
78
|
-
for (
|
|
79
|
+
for (const v of variableKeys) {
|
|
79
80
|
tokens.push(v);
|
|
80
81
|
tokens.push(variable.data[v]);
|
|
81
82
|
}
|
|
@@ -83,11 +84,12 @@ export default function(event: Event): void {
|
|
|
83
84
|
queue(tokens, false);
|
|
84
85
|
}
|
|
85
86
|
break;
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
}
|
|
88
|
+
case Event.Metric: {
|
|
89
|
+
const metricKeys = Object.keys(metric.updates);
|
|
88
90
|
if (metricKeys.length > 0) {
|
|
89
|
-
for (
|
|
90
|
-
|
|
91
|
+
for (const m of metricKeys) {
|
|
92
|
+
const key = Number.parseInt(m, 10);
|
|
91
93
|
tokens.push(key);
|
|
92
94
|
// For computation, we need microseconds precision that performance.now() API offers
|
|
93
95
|
// However, for data over the wire, we round it off to milliseconds precision.
|
|
@@ -97,11 +99,12 @@ export default function(event: Event): void {
|
|
|
97
99
|
queue(tokens, false);
|
|
98
100
|
}
|
|
99
101
|
break;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
}
|
|
103
|
+
case Event.Dimension: {
|
|
104
|
+
const dimensionKeys = Object.keys(dimension.updates);
|
|
102
105
|
if (dimensionKeys.length > 0) {
|
|
103
|
-
for (
|
|
104
|
-
|
|
106
|
+
for (const d of dimensionKeys) {
|
|
107
|
+
const key = Number.parseInt(d, 10);
|
|
105
108
|
tokens.push(key);
|
|
106
109
|
tokens.push(dimension.updates[d]);
|
|
107
110
|
}
|
|
@@ -109,11 +112,12 @@ export default function(event: Event): void {
|
|
|
109
112
|
queue(tokens, false);
|
|
110
113
|
}
|
|
111
114
|
break;
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
}
|
|
116
|
+
case Event.Summary: {
|
|
117
|
+
const eventKeys = Object.keys(summary.data);
|
|
114
118
|
if (eventKeys.length > 0) {
|
|
115
|
-
for (
|
|
116
|
-
|
|
119
|
+
for (const e of eventKeys) {
|
|
120
|
+
const key = Number.parseInt(e, 10);
|
|
117
121
|
tokens.push(key);
|
|
118
122
|
tokens.push([].concat(...summary.data[e]));
|
|
119
123
|
}
|
|
@@ -121,20 +125,22 @@ export default function(event: Event): void {
|
|
|
121
125
|
queue(tokens, false);
|
|
122
126
|
}
|
|
123
127
|
break;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
extractKeys
|
|
128
|
+
}
|
|
129
|
+
case Event.Extract: {
|
|
130
|
+
const extractKeys = extract.keys;
|
|
131
|
+
for (const e of Array.from(extractKeys)) {
|
|
127
132
|
tokens.push(e);
|
|
128
|
-
|
|
129
|
-
for (
|
|
130
|
-
|
|
133
|
+
const token = [];
|
|
134
|
+
for (const d in extract.data[e]) {
|
|
135
|
+
const key = Number.parseInt(d, 10);
|
|
131
136
|
token.push(key);
|
|
132
137
|
token.push(extract.data[e][d]);
|
|
133
138
|
}
|
|
134
139
|
tokens.push(token);
|
|
135
|
-
}
|
|
136
|
-
|
|
140
|
+
}
|
|
141
|
+
|
|
137
142
|
extract.reset();
|
|
138
143
|
queue(tokens, false);
|
|
144
|
+
}
|
|
139
145
|
}
|
|
140
146
|
}
|
package/src/data/envelope.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ApplicationPlatform, BooleanFlag, type Envelope, type Token, Upload } from "@clarity-types/data";
|
|
2
|
+
import * as scrub from "@src/core/scrub";
|
|
2
3
|
import { time } from "@src/core/time";
|
|
3
4
|
import version from "@src/core/version";
|
|
4
5
|
import * as metadata from "@src/data/metadata";
|
|
5
|
-
import * as scrub from "@src/core/scrub";
|
|
6
6
|
|
|
7
7
|
export let data: Envelope = null;
|
|
8
8
|
|
|
9
9
|
export function start(): void {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
10
|
+
const m = metadata.data;
|
|
11
|
+
data = {
|
|
12
|
+
version,
|
|
13
|
+
sequence: 0,
|
|
14
|
+
start: 0,
|
|
15
|
+
duration: 0,
|
|
16
|
+
projectId: m.projectId,
|
|
17
|
+
userId: m.userId,
|
|
18
|
+
sessionId: m.sessionId,
|
|
19
|
+
pageNum: m.pageNum,
|
|
20
|
+
upload: Upload.Async,
|
|
21
|
+
end: BooleanFlag.False,
|
|
22
|
+
applicationPlatform: ApplicationPlatform.WebApp,
|
|
23
|
+
url: "",
|
|
24
|
+
};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function stop(): void {
|
|
@@ -29,25 +29,25 @@ export function stop(): void {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function envelope(last: boolean): Token[] {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
32
|
+
data.start = data.start + data.duration;
|
|
33
|
+
data.duration = time() - data.start;
|
|
34
|
+
data.sequence++;
|
|
35
|
+
data.upload = last && "sendBeacon" in navigator ? Upload.Beacon : Upload.Async;
|
|
36
|
+
data.end = last ? BooleanFlag.True : BooleanFlag.False;
|
|
37
|
+
data.applicationPlatform = ApplicationPlatform.WebApp;
|
|
38
|
+
data.url = scrub.url(location.href, false, true);
|
|
39
|
+
return [
|
|
40
|
+
data.version,
|
|
41
|
+
data.sequence,
|
|
42
|
+
data.start,
|
|
43
|
+
data.duration,
|
|
44
|
+
data.projectId,
|
|
45
|
+
data.userId,
|
|
46
|
+
data.sessionId,
|
|
47
|
+
data.pageNum,
|
|
48
|
+
data.upload,
|
|
49
|
+
data.end,
|
|
50
|
+
data.applicationPlatform,
|
|
51
|
+
data.url,
|
|
52
|
+
];
|
|
53
53
|
}
|
package/src/data/extract.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { ExtractSource, Syntax, Type } from "@clarity-types/core";
|
|
2
|
-
import { Event,
|
|
3
|
-
import encode from "./encode";
|
|
4
|
-
import * as internal from "@src/diagnostic/internal";
|
|
1
|
+
import { ExtractSource, type Syntax, Type } from "@clarity-types/core";
|
|
2
|
+
import { Event, type ExtractData, Setting } from "@clarity-types/data";
|
|
5
3
|
import { Code, Constant, Severity } from "@clarity-types/data";
|
|
6
4
|
import { hashText } from "@src/clarity";
|
|
7
5
|
import hash from "@src/core/hash";
|
|
6
|
+
import * as internal from "@src/diagnostic/internal";
|
|
7
|
+
import encode from "./encode";
|
|
8
8
|
|
|
9
|
-
export
|
|
10
|
-
export
|
|
9
|
+
export const data: ExtractData = {};
|
|
10
|
+
export const keys: Set<number> = new Set();
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const variables: { [key: number]: { [key: number]: Syntax[] } } = {};
|
|
13
|
+
const selectors: { [key: number]: { [key: number]: string } } = {};
|
|
14
|
+
const hashes: { [key: number]: { [key: number]: string } } = {};
|
|
15
|
+
const validation: { [key: number]: string } = {};
|
|
16
16
|
|
|
17
17
|
export function start(): void {
|
|
18
18
|
reset();
|
|
@@ -23,44 +23,45 @@ export function start(): void {
|
|
|
23
23
|
// if element is present on the page it will set up event 101 to grab the contents of the class1 selector into component 1,
|
|
24
24
|
// the javascript evaluated contents of window.a.b into component 2,
|
|
25
25
|
// and the contents of Clarity's hash abc into component 3
|
|
26
|
-
export function trigger(input: string): void {
|
|
26
|
+
export function trigger(input: string): void {
|
|
27
27
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
const parts = input && input.length > 0 ? input.split(/ (.*)/) : [Constant.Empty];
|
|
29
|
+
const keyparts = parts[0].split(/\|(.*)/);
|
|
30
|
+
const key = Number.parseInt(keyparts[0]);
|
|
31
|
+
const element = keyparts.length > 1 ? keyparts[1] : Constant.Empty;
|
|
32
|
+
const values = parts.length > 1 ? JSON.parse(parts[1]) : {};
|
|
33
33
|
variables[key] = {};
|
|
34
34
|
selectors[key] = {};
|
|
35
35
|
hashes[key] = {};
|
|
36
36
|
validation[key] = element;
|
|
37
|
-
for (
|
|
38
|
-
// values is a set of strings for proper JSON parsing, but it's more efficient
|
|
37
|
+
for (const v in values) {
|
|
38
|
+
// values is a set of strings for proper JSON parsing, but it's more efficient
|
|
39
39
|
// to interact with them as numbers
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const id = Number.parseInt(v);
|
|
41
|
+
const value = values[v] as string;
|
|
42
42
|
let source = ExtractSource.Text;
|
|
43
43
|
if (value.startsWith(Constant.Tilde)) {
|
|
44
|
-
source = ExtractSource.Javascript
|
|
44
|
+
source = ExtractSource.Javascript;
|
|
45
45
|
} else if (value.startsWith(Constant.Bang)) {
|
|
46
|
-
source = ExtractSource.Hash
|
|
46
|
+
source = ExtractSource.Hash;
|
|
47
47
|
}
|
|
48
48
|
switch (source) {
|
|
49
|
-
case ExtractSource.Javascript:
|
|
50
|
-
|
|
49
|
+
case ExtractSource.Javascript: {
|
|
50
|
+
const variable = value.slice(1);
|
|
51
51
|
variables[key][id] = parse(variable);
|
|
52
52
|
break;
|
|
53
|
+
}
|
|
53
54
|
case ExtractSource.Text:
|
|
54
55
|
selectors[key][id] = value;
|
|
55
56
|
break;
|
|
56
|
-
case ExtractSource.Hash:
|
|
57
|
-
|
|
57
|
+
case ExtractSource.Hash: {
|
|
58
|
+
const hash = value.slice(1);
|
|
58
59
|
hashes[key][id] = hash;
|
|
59
60
|
break;
|
|
61
|
+
}
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
|
-
}
|
|
63
|
-
catch(e) {
|
|
64
|
+
} catch (e) {
|
|
64
65
|
internal.log(Code.Config, Severity.Warning, e ? e.name : null);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
@@ -71,39 +72,40 @@ export function clone(v: Syntax[]): Syntax[] {
|
|
|
71
72
|
|
|
72
73
|
export function compute(): void {
|
|
73
74
|
try {
|
|
74
|
-
for (
|
|
75
|
-
|
|
76
|
-
if (validation[key]
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (value) {
|
|
75
|
+
for (const v in variables) {
|
|
76
|
+
const key = Number.parseInt(v);
|
|
77
|
+
if (validation[key] === Constant.Empty || document.querySelector(validation[key])) {
|
|
78
|
+
const variableData = variables[key];
|
|
79
|
+
for (const v in variableData) {
|
|
80
|
+
const variableKey = Number.parseInt(v);
|
|
81
|
+
const value = str(evaluate(clone(variableData[variableKey])));
|
|
82
|
+
if (value) {
|
|
83
83
|
update(key, variableKey, value);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
for (
|
|
87
|
+
const selectorData = selectors[key];
|
|
88
|
+
for (const s in selectorData) {
|
|
89
89
|
let shouldMask = false;
|
|
90
|
-
|
|
90
|
+
const selectorKey = Number.parseInt(s);
|
|
91
91
|
let selector = selectorData[selectorKey];
|
|
92
|
-
if (selector.startsWith(Constant.At)){
|
|
92
|
+
if (selector.startsWith(Constant.At)) {
|
|
93
93
|
shouldMask = true;
|
|
94
94
|
selector = selector.slice(1);
|
|
95
95
|
}
|
|
96
|
-
|
|
96
|
+
const nodes = document.querySelectorAll(selector) as NodeListOf<HTMLElement>;
|
|
97
97
|
if (nodes) {
|
|
98
|
-
|
|
98
|
+
const text = Array.from(nodes)
|
|
99
|
+
.map((e) => e.textContent)
|
|
100
|
+
.join(Constant.Seperator);
|
|
99
101
|
update(key, selectorKey, (shouldMask ? hash(text).trim() : text).slice(0, Setting.ExtractLimit));
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
for (
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
const hashData = hashes[key];
|
|
106
|
+
for (const h in hashData) {
|
|
107
|
+
const hashKey = Number.parseInt(h);
|
|
108
|
+
const content = hashText(hashData[hashKey]).trim().slice(0, Setting.ExtractLimit);
|
|
107
109
|
update(key, hashKey, content);
|
|
108
110
|
}
|
|
109
111
|
}
|
|
@@ -112,8 +114,9 @@ export function compute(): void {
|
|
|
112
114
|
if (keys.size > 0) {
|
|
113
115
|
encode(Event.Extract);
|
|
114
116
|
}
|
|
117
|
+
} catch (e) {
|
|
118
|
+
internal.log(Code.Selector, Severity.Warning, e ? e.name : null);
|
|
115
119
|
}
|
|
116
|
-
catch (e) { internal.log(Code.Selector, Severity.Warning, e ? e.name : null); }
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
export function reset(): void {
|
|
@@ -121,15 +124,13 @@ export function reset(): void {
|
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
export function update(key: number, subkey: number, value: string): void {
|
|
124
|
-
|
|
127
|
+
let update = false;
|
|
125
128
|
if (!(key in data)) {
|
|
126
129
|
data[key] = {};
|
|
127
130
|
update = true;
|
|
128
131
|
}
|
|
129
|
-
|
|
130
|
-
if (!isEmpty(hashes[key])
|
|
131
|
-
&& (!(subkey in data[key]) || data[key][subkey] != value))
|
|
132
|
-
{
|
|
132
|
+
|
|
133
|
+
if (!isEmpty(hashes[key]) && (!(subkey in data[key]) || data[key][subkey] !== value)) {
|
|
133
134
|
update = true;
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -142,21 +143,21 @@ export function update(key: number, subkey: number, value: string): void {
|
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
export function stop(): void {
|
|
145
|
-
|
|
146
|
+
reset();
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
function parse(variable: string): Syntax[] {
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
const syntax: Syntax[] = [];
|
|
151
|
+
const parts = variable.split(Constant.Dot);
|
|
151
152
|
while (parts.length > 0) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
const part = parts.shift();
|
|
154
|
+
const arrayStart = part.indexOf(Constant.ArrayStart);
|
|
155
|
+
const conditionStart = part.indexOf(Constant.ConditionStart);
|
|
156
|
+
const conditionEnd = part.indexOf(Constant.ConditionEnd);
|
|
156
157
|
syntax.push({
|
|
157
|
-
name
|
|
158
|
-
type
|
|
159
|
-
condition
|
|
158
|
+
name: arrayStart > 0 ? part.slice(0, arrayStart) : conditionStart > 0 ? part.slice(0, conditionStart) : part,
|
|
159
|
+
type: arrayStart > 0 ? Type.Array : conditionStart > 0 ? Type.Object : Type.Simple,
|
|
160
|
+
condition: conditionStart > 0 ? part.slice(conditionStart + 1, conditionEnd) : null,
|
|
160
161
|
});
|
|
161
162
|
}
|
|
162
163
|
|
|
@@ -166,26 +167,32 @@ function parse(variable: string): Syntax[] {
|
|
|
166
167
|
// The function below takes in a variable name in following format: "a.b.c" and safely evaluates its value in javascript context
|
|
167
168
|
// For instance, for a.b.c, it will first check window["a"]. If it exists, it will recursively look at: window["a"]["b"] and finally,
|
|
168
169
|
// return the value for window["a"]["b"]["c"].
|
|
170
|
+
// biome-ignore lint/complexity/noBannedTypes: type of base is intentionally generic
|
|
171
|
+
// biome-ignore lint/suspicious/noExplicitAny: type of return value isn't known
|
|
169
172
|
function evaluate(variable: Syntax[], base: Object = window): any {
|
|
170
|
-
if (variable.length
|
|
171
|
-
|
|
173
|
+
if (variable.length === 0) {
|
|
174
|
+
return base;
|
|
175
|
+
}
|
|
176
|
+
const part = variable.shift();
|
|
177
|
+
// biome-ignore lint/suspicious/noImplicitAnyLet: type of return value isn't known
|
|
172
178
|
let output;
|
|
173
|
-
if (base
|
|
174
|
-
|
|
179
|
+
if (base?.[part.name]) {
|
|
180
|
+
const obj = base[part.name];
|
|
175
181
|
if (part.type !== Type.Array && match(obj, part.condition)) {
|
|
176
182
|
output = evaluate(variable, obj);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
for (var value of obj) {
|
|
183
|
+
} else if (Array.isArray(obj)) {
|
|
184
|
+
const filtered = [];
|
|
185
|
+
for (const value of obj) {
|
|
181
186
|
if (match(value, part.condition)) {
|
|
182
|
-
|
|
183
|
-
if (op) {
|
|
187
|
+
const op = evaluate(variable, value);
|
|
188
|
+
if (op) {
|
|
189
|
+
filtered.push(op);
|
|
190
|
+
}
|
|
184
191
|
}
|
|
185
192
|
}
|
|
186
193
|
output = filtered;
|
|
187
194
|
}
|
|
188
|
-
|
|
195
|
+
|
|
189
196
|
return output;
|
|
190
197
|
}
|
|
191
198
|
|
|
@@ -197,15 +204,17 @@ function str(input: string): string {
|
|
|
197
204
|
return input ? JSON.stringify(input).slice(0, Setting.ExtractLimit) : input;
|
|
198
205
|
}
|
|
199
206
|
|
|
207
|
+
// biome-ignore lint/complexity/noBannedTypes: type of base is intentionally generic
|
|
200
208
|
function match(base: Object, condition: string): boolean {
|
|
201
209
|
if (condition) {
|
|
202
|
-
|
|
203
|
-
return prop.length > 1 ? base[prop[0]]
|
|
210
|
+
const prop = condition.split(":");
|
|
211
|
+
return prop.length > 1 ? base[prop[0]] === prop[1] : base[prop[0]];
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
return true;
|
|
207
215
|
}
|
|
208
216
|
|
|
217
|
+
// biome-ignore lint/complexity/noBannedTypes: type of obj is intentionally generic
|
|
209
218
|
function isEmpty(obj: Object): boolean {
|
|
210
|
-
return Object.keys(obj).length
|
|
219
|
+
return Object.keys(obj).length === 0;
|
|
211
220
|
}
|
package/src/data/index.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
import type { Module } from "@clarity-types/core";
|
|
1
2
|
import measure from "@src/core/measure";
|
|
2
3
|
import * as baseline from "@src/data/baseline";
|
|
3
|
-
import * as envelope from "@src/data/envelope";
|
|
4
4
|
import * as dimension from "@src/data/dimension";
|
|
5
|
+
import * as envelope from "@src/data/envelope";
|
|
6
|
+
import * as extract from "@src/data/extract";
|
|
7
|
+
import * as limit from "@src/data/limit";
|
|
5
8
|
import * as metadata from "@src/data/metadata";
|
|
6
|
-
import { Module } from "@clarity-types/core";
|
|
7
9
|
import * as metric from "@src/data/metric";
|
|
8
10
|
import * as ping from "@src/data/ping";
|
|
9
|
-
import * as limit from "@src/data/limit";
|
|
10
11
|
import * as summary from "@src/data/summary";
|
|
11
12
|
import * as upgrade from "@src/data/upgrade";
|
|
12
13
|
import * as upload from "@src/data/upload";
|
|
13
14
|
import * as variable from "@src/data/variable";
|
|
14
|
-
import * as extract from "@src/data/extract";
|
|
15
15
|
export { event } from "@src/data/custom";
|
|
16
16
|
export { consent, metadata } from "@src/data/metadata";
|
|
17
17
|
export { upgrade } from "@src/data/upgrade";
|
|
@@ -23,7 +23,9 @@ const modules: Module[] = [baseline, dimension, variable, limit, summary, metada
|
|
|
23
23
|
export function start(): void {
|
|
24
24
|
// Metric needs to be initialized before we can start measuring. so metric is not wrapped in measure
|
|
25
25
|
metric.start();
|
|
26
|
-
|
|
26
|
+
for (const x of modules) {
|
|
27
|
+
measure(x.start)();
|
|
28
|
+
}
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export function stop(): void {
|
|
@@ -31,7 +33,9 @@ export function stop(): void {
|
|
|
31
33
|
// The ordering below should respect inter-module dependency.
|
|
32
34
|
// E.g. if upgrade depends on upload, then upgrade needs to end before upload.
|
|
33
35
|
// Similarly, if upload depends on metadata, upload needs to end before metadata.
|
|
34
|
-
modules.slice().reverse()
|
|
36
|
+
for (const x of modules.slice().reverse()) {
|
|
37
|
+
measure(x.stop)();
|
|
38
|
+
}
|
|
35
39
|
metric.stop();
|
|
36
40
|
}
|
|
37
41
|
|
package/src/data/limit.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Check, Event, LimitData, Setting } from "@clarity-types/data";
|
|
1
|
+
import { Check, Event, type LimitData, Setting } from "@clarity-types/data";
|
|
2
2
|
import * as clarity from "@src/clarity";
|
|
3
3
|
import { time } from "@src/core/time";
|
|
4
4
|
import * as envelope from "@src/data/envelope";
|