Skip to content

Commit

Permalink
Simplify selector logic in clarity-js (microsoft#174)
Browse files Browse the repository at this point in the history
* Simplify selector logic in clarity-js

* Addressing PR feedback

* Bumping version to 0.6.26

* Reset counter after a successful history operation

* Bug fixes related to shadow dom

* Bug fix to enable standalone calls to merge function

* Handling empty selectors

* Ability to lookup value by hash and extension bug fixes
  • Loading branch information
sarveshnagpal committed Oct 28, 2021
1 parent 0494b75 commit 4868c6b
Show file tree
Hide file tree
Showing 41 changed files with 447 additions and 341 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"packages": [
"packages/*"
],
"version": "0.6.25",
"version": "0.6.26",
"npmClient": "yarn",
"useWorkspaces": true
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "clarity",
"private": true,
"version": "0.6.25",
"version": "0.6.26",
"repository": "https://github.com/microsoft/clarity.git",
"author": "Sarvesh Nagpal <sarveshn@microsoft.com>",
"license": "MIT",
Expand Down
4 changes: 2 additions & 2 deletions packages/clarity-decode/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clarity-decode",
"version": "0.6.25",
"version": "0.6.26",
"description": "An analytics library that uses web page interactions to generate aggregated insights",
"author": "Microsoft Corp.",
"license": "MIT",
Expand All @@ -26,7 +26,7 @@
"url": "https://github.com/Microsoft/clarity/issues"
},
"dependencies": {
"clarity-js": "^0.6.25"
"clarity-js": "^0.6.26"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^19.0.1",
Expand Down
3 changes: 0 additions & 3 deletions packages/clarity-decode/src/clarity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ export function decode(input: string): DecodedPayload {
throw new Error(`Invalid version. Actual: ${payload.envelope.version} | Expected: ${version} (+/- 1) | ${input.substr(0, 250)}`);
}

/* Reset components before decoding to keep them stateless */
layout.reset();

for (let entry of encoded) {
switch (entry[1]) {
case Data.Event.Baseline:
Expand Down
18 changes: 11 additions & 7 deletions packages/clarity-decode/src/interaction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Data, Interaction } from "clarity-js";
import { InteractionEvent } from "../types/interaction";
import { Data, Interaction, Layout } from "clarity-js";
import { InteractionEvent, ClickData, TimelineData } from "../types/interaction";

export function decode(tokens: Data.Token[]): InteractionEvent {
let time = tokens[0] as number;
Expand All @@ -21,7 +21,8 @@ export function decode(tokens: Data.Token[]): InteractionEvent {
};
return { time, event, data: pointerData };
case Data.Event.Click:
let clickData: Interaction.ClickData = {
let clickHashes = (tokens[12] as string).split(Data.Constant.Dot);
let clickData: ClickData = {
target: tokens[2] as number,
x: tokens[3] as number,
y: tokens[4] as number,
Expand All @@ -32,7 +33,8 @@ export function decode(tokens: Data.Token[]): InteractionEvent {
context: tokens[9] as number,
text: tokens[10] as string,
link: tokens[11] as string,
hash: tokens[12] as string
hash: clickHashes[0],
hashBeta: clickHashes.length > 0 ? clickHashes[1] : null
};
return { time, event, data: clickData };
case Data.Event.Resize:
Expand Down Expand Up @@ -60,13 +62,15 @@ export function decode(tokens: Data.Token[]): InteractionEvent {
};
return { time, event, data: scrollData };
case Data.Event.Timeline:
let timelineData: Interaction.TimelineData = {
let timelineHashes = (tokens[3] as string).split(Data.Constant.Dot);
let timelineData: TimelineData = {
type: tokens[2] as number,
hash: tokens[3] as string,
hash: timelineHashes[Layout.Selector.Stable],
x: tokens[4] as number,
y: tokens[5] as number,
reaction: tokens[6] as number,
context: tokens[7] as number
context: tokens[7] as number,
hashBeta: timelineHashes.length > 0 ? timelineHashes[Layout.Selector.Beta] : null
};
return { time, event, data: timelineData };
case Data.Event.Visibility:
Expand Down
28 changes: 8 additions & 20 deletions packages/clarity-decode/src/layout.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { Constant } from "@clarity-types/data";
import { helper, Data, Layout } from "clarity-js";
import { Data, Layout } from "clarity-js";
import { DomData, LayoutEvent, Interaction, RegionVisibility } from "../types/layout";

const AverageWordLength = 6;
const Space = " ";
let hashes: { [key: number]: string } = {};

export function reset(): void {
hashes = {};
}

export function decode(tokens: Data.Token[]): LayoutEvent {
let time = tokens[0] as number;
Expand Down Expand Up @@ -104,21 +99,19 @@ export function decode(tokens: Data.Token[]): LayoutEvent {
}

function process(node: any[] | number[], tagIndex: number): DomData {
let [tag, position]: string[] = node[tagIndex] ? node[tagIndex].split("~") : [node[tagIndex]];
// For backward compatibility, only extract the tag even if position is available as part of the tag name
// And, continue computing position in the visualization library from decoded payload.
let tag = node[tagIndex] ? node[tagIndex].split("~")[0] : node[tagIndex];
let output: DomData = {
id: Math.abs(node[0]),
parent: tagIndex > 1 ? node[1] : null,
previous: tagIndex > 2 ? node[2] : null,
tag,
position: position ? parseInt(position, 10) : null,
selector: null,
hash: null
tag
};
let masked = node[0] < 0;
let hasAttribute = false;
let attributes: Layout.Attributes = {};
let value = null;
let prefix = output.parent in hashes ? `${hashes[output.parent]}>` : (output.parent ? Layout.Constant.Empty : null);

for (let i = tagIndex + 1; i < node.length; i++) {
// Explicitly convert the token into a string value
Expand All @@ -129,7 +122,9 @@ function process(node: any[] | number[], tagIndex: number): DomData {
if (i === (node.length - 1) && output.tag === "STYLE") {
value = token;
} else if (output.tag !== Layout.Constant.TextTag && lastChar === ">" && keyIndex === -1) {
prefix = token;
// Backward compatibility - since v0.6.25
// Ignore this conditional block since we no longer compute selectors at decode time to save on uploaded bytes
// Instead, we now compute selector and hash at visualization layer where we have access to all payloads together
} else if (output.tag !== Layout.Constant.TextTag && firstChar === Layout.Constant.Box && keyIndex === -1) {
let parts = token.substr(1).split(Layout.Constant.Period);
if (parts.length === 2) {
Expand All @@ -146,13 +141,6 @@ function process(node: any[] | number[], tagIndex: number): DomData {
}
}

let selector = helper.selector(output.tag, prefix, attributes, output.position);
if (selector.length > 0) {
output.selector = selector;
output.hash = helper.hash(selector);
hashes[output.id] = selector;
}

if (hasAttribute) { output.attributes = attributes; }
if (value) { output.value = value; }

Expand Down
16 changes: 12 additions & 4 deletions packages/clarity-decode/types/interaction.d.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
import { Interaction } from "clarity-js";
import { PartialEvent } from "./core";

export interface ClickData extends Interaction.ClickData {
hashBeta: string;
}

export interface TimelineData extends Interaction.TimelineData {
hashBeta: string;
}

export interface InputEvent extends PartialEvent { data: Interaction.InputData; }
export interface ClickEvent extends PartialEvent { data: Interaction.ClickData; }
export interface ClickEvent extends PartialEvent { data: ClickData; }
export interface PointerEvent extends PartialEvent { data: Interaction.PointerData; }
export interface ResizeEvent extends PartialEvent { data: Interaction.ResizeData; }
export interface ScrollEvent extends PartialEvent { data: Interaction.ScrollData; }
export interface SelectionEvent extends PartialEvent { data: Interaction.SelectionData; }
export interface TimelineEvent extends PartialEvent { data: Interaction.TimelineData; }
export interface TimelineEvent extends PartialEvent { data: TimelineData; }
export interface UnloadEvent extends PartialEvent { data: Interaction.UnloadData; }
export interface VisibilityEvent extends PartialEvent { data: Interaction.VisibilityData; }
export interface InteractionEvent extends PartialEvent {
data: Interaction.ClickData |
data: ClickData |
Interaction.InputData |
Interaction.PointerData |
Interaction.ResizeData |
Interaction.ScrollData |
Interaction.SelectionData |
Interaction.TimelineData |
TimelineData |
Interaction.UnloadData |
Interaction.VisibilityData;
}
8 changes: 5 additions & 3 deletions packages/clarity-decode/types/layout.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ export interface LayoutEvent extends PartialEvent {
export import Constant = Layout.Constant;
export import Interaction = Layout.InteractionState;
export import RegionVisibility = Layout.RegionVisibility;
export import SelectorInput = Layout.SelectorInput;

/* Event Data */
export interface DomData {
id: number;
parent: number;
previous: number;
tag: string;
position: number;
selector: string;
hash: string;
attributes?: Layout.Attributes;
value?: string;
width?: number;
height?: number;
selector?: string;
hash?: string;
selectorBeta?: string;
hashBeta?: string;
}
9 changes: 5 additions & 4 deletions packages/clarity-devtools/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clarity-devtools",
"version": "0.6.25",
"version": "0.6.26",
"private": true,
"description": "Adds Clarity debugging support to browser devtools",
"author": "Microsoft Corp.",
Expand All @@ -24,9 +24,9 @@
"url": "https://github.com/Microsoft/clarity/issues"
},
"dependencies": {
"clarity-decode": "^0.6.25",
"clarity-js": "^0.6.25",
"clarity-visualize": "^0.6.25"
"clarity-decode": "^0.6.26",
"clarity-js": "^0.6.26",
"clarity-visualize": "^0.6.26"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^13.0.2",
Expand All @@ -39,6 +39,7 @@
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.30.0",
"source-map-loader": "^3.0.0",
"tslib": "^2.3.0",
"ts-node": "^10.1.0",
"tslint": "^6.1.3",
"typescript": "^4.3.5"
Expand Down
5 changes: 5 additions & 0 deletions packages/clarity-devtools/rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export default [
output: [{ file: "extension/content.js", format: "iife", exports: "named" }],
plugins: [resolve(), typescript({ rollupCommonJSResolveHack: true, clean: true })]
},
{
input: "src/clarity.ts",
output: [{ file: "extension/clarity.js", format: "iife", exports: "named" }],
plugins: [resolve(), typescript({ rollupCommonJSResolveHack: true, clean: true })]
},
{
input: "src/popup.ts",
output: [{ file: "extension/popup.js", format: "iife", exports: "named" }],
Expand Down
4 changes: 3 additions & 1 deletion packages/clarity-devtools/src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ chrome.runtime.onMessage.addListener(
case "payload":
if (sender.tab) {
let tabId = sender.tab.id;
if (tabId in connections) {
let success = tabId in connections;
if (success) {
connections[tabId].postMessage(message);
}
sendResponse({ success });
}
break;
}
Expand Down
20 changes: 20 additions & 0 deletions packages/clarity-devtools/src/clarity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { clarity, version, helper } from "clarity-js";

// Execute clarity-js in context of the webpage
(function(): void {
if (typeof window !== "undefined") {
const w = window as any;
const c = 'clarity';

// Stop any existing instance of clarity-js
if (w[c]) { w[c]("stop"); }

// Re-wire clarity-js for developer tools and expose helper methods as part of the global object
w[c] = function(method: string, ...args: any[]): void { return clarity[method](...args); }
w[c].h = function(method: string, ...args: any[]): void { return helper[method](...args); }
w[c].v = version;

// Notify developer tools that clarity-js is wired up
window.postMessage({ action: "wireup" }, "*");
}
})();
4 changes: 2 additions & 2 deletions packages/clarity-devtools/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Core, Data, Layout } from "clarity-js";
import { Core, Data } from "clarity-js";

const enum Region {
Header = 1,
Expand All @@ -9,7 +9,7 @@ const enum Region {
export default function(): Core.Config {
return {
regions: [
[Region.Header, "header", 1, Layout.Constant.DevHook], /* 1: Javascript Filter */
[Region.Header, "header", 1, Data.Constant.Clarity], /* 1: Javascript Filter */
[Region.Footer, "footer", 0, "product"], /* 0: Url */
[Region.Navigation, "nav"]
],
Expand Down
Loading

0 comments on commit 4868c6b

Please sign in to comment.