@openreplay/tracker 7.0.2 → 8.0.0-beta.1
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/CHANGELOG.md +8 -0
- package/cjs/app/index.d.ts +8 -0
- package/cjs/app/index.js +53 -5
- package/cjs/app/messages.gen.d.ts +2 -0
- package/cjs/app/messages.gen.js +15 -1
- package/cjs/app/sanitizer.d.ts +1 -0
- package/cjs/app/sanitizer.js +6 -4
- package/cjs/app/session.d.ts +4 -0
- package/cjs/app/session.js +18 -0
- package/cjs/common/interaction.d.ts +1 -0
- package/cjs/common/messages.gen.d.ts +12 -2
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +9 -1
- package/cjs/modules/network.js +1 -1
- package/cjs/modules/tabs.d.ts +2 -0
- package/cjs/modules/tabs.js +13 -0
- package/cjs/utils.d.ts +1 -1
- package/cjs/utils.js +13 -11
- package/coverage/clover.xml +2461 -0
- package/coverage/coverage-final.json +38 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +176 -0
- package/coverage/lcov-report/main/app/guards.ts.html +229 -0
- package/coverage/lcov-report/main/app/index.html +206 -0
- package/coverage/lcov-report/main/app/index.ts.html +2053 -0
- package/coverage/lcov-report/main/app/logger.ts.html +277 -0
- package/coverage/lcov-report/main/app/messages.gen.ts.html +2752 -0
- package/coverage/lcov-report/main/app/nodes.ts.html +367 -0
- package/coverage/lcov-report/main/app/observer/iframe_observer.ts.html +148 -0
- package/coverage/lcov-report/main/app/observer/iframe_offsets.ts.html +289 -0
- package/coverage/lcov-report/main/app/observer/index.html +161 -0
- package/coverage/lcov-report/main/app/observer/observer.ts.html +1282 -0
- package/coverage/lcov-report/main/app/observer/shadow_root_observer.ts.html +142 -0
- package/coverage/lcov-report/main/app/observer/top_observer.ts.html +535 -0
- package/coverage/lcov-report/main/app/sanitizer.ts.html +394 -0
- package/coverage/lcov-report/main/app/session.ts.html +559 -0
- package/coverage/lcov-report/main/app/ticker.ts.html +250 -0
- package/coverage/lcov-report/main/index.html +131 -0
- package/coverage/lcov-report/main/index.ts.html +1012 -0
- package/coverage/lcov-report/main/modules/axiosSpy.ts.html +700 -0
- package/coverage/lcov-report/main/modules/connection.ts.html +160 -0
- package/coverage/lcov-report/main/modules/console.ts.html +508 -0
- package/coverage/lcov-report/main/modules/constructedStyleSheets.ts.html +559 -0
- package/coverage/lcov-report/main/modules/cssrules.ts.html +418 -0
- package/coverage/lcov-report/main/modules/exception.ts.html +385 -0
- package/coverage/lcov-report/main/modules/focus.ts.html +220 -0
- package/coverage/lcov-report/main/modules/fonts.ts.html +289 -0
- package/coverage/lcov-report/main/modules/img.ts.html +433 -0
- package/coverage/lcov-report/main/modules/index.html +371 -0
- package/coverage/lcov-report/main/modules/input.ts.html +811 -0
- package/coverage/lcov-report/main/modules/mouse.ts.html +826 -0
- package/coverage/lcov-report/main/modules/network.ts.html +1129 -0
- package/coverage/lcov-report/main/modules/performance.ts.html +367 -0
- package/coverage/lcov-report/main/modules/scroll.ts.html +364 -0
- package/coverage/lcov-report/main/modules/selection.ts.html +202 -0
- package/coverage/lcov-report/main/modules/tabs.ts.html +124 -0
- package/coverage/lcov-report/main/modules/timing.ts.html +841 -0
- package/coverage/lcov-report/main/modules/viewport.ts.html +250 -0
- package/coverage/lcov-report/main/utils.ts.html +406 -0
- package/coverage/lcov-report/main/vendors/finder/finder.ts.html +1381 -0
- package/coverage/lcov-report/main/vendors/finder/index.html +116 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/webworker/BatchWriter.ts.html +532 -0
- package/coverage/lcov-report/webworker/MessageEncoder.gen.ts.html +949 -0
- package/coverage/lcov-report/webworker/PrimitiveEncoder.ts.html +436 -0
- package/coverage/lcov-report/webworker/QueueSender.ts.html +475 -0
- package/coverage/lcov-report/webworker/StringDictionary.ts.html +124 -0
- package/coverage/lcov-report/webworker/index.html +191 -0
- package/coverage/lcov-report/webworker/index.ts.html +592 -0
- package/coverage/lcov.info +4882 -0
- package/jest.config.js +2 -0
- package/lib/app/index.d.ts +8 -0
- package/lib/app/index.js +54 -6
- package/lib/app/messages.gen.d.ts +2 -0
- package/lib/app/messages.gen.js +12 -0
- package/lib/app/sanitizer.d.ts +1 -0
- package/lib/app/sanitizer.js +4 -3
- package/lib/app/session.d.ts +4 -0
- package/lib/app/session.js +18 -0
- package/lib/common/interaction.d.ts +1 -0
- package/lib/common/messages.gen.d.ts +12 -2
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +9 -1
- package/lib/modules/network.js +1 -1
- package/lib/modules/tabs.d.ts +2 -0
- package/lib/modules/tabs.js +10 -0
- package/lib/utils.d.ts +1 -1
- package/lib/utils.js +11 -9
- package/package.json +4 -2
- package/cjs/vendors/finder/finder.d.ts +0 -12
- package/cjs/vendors/finder/finder.js +0 -352
- package/lib/vendors/finder/finder.d.ts +0 -12
- package/lib/vendors/finder/finder.js +0 -348
package/lib/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import Fonts from './modules/fonts.js';
|
|
|
20
20
|
import Network from './modules/network.js';
|
|
21
21
|
import ConstructedStyleSheets from './modules/constructedStyleSheets.js';
|
|
22
22
|
import Selection from './modules/selection.js';
|
|
23
|
+
import Tabs from './modules/tabs.js';
|
|
23
24
|
import { IN_BROWSER, deprecationWarn, DOCS_HOST } from './utils.js';
|
|
24
25
|
const DOCS_SETUP = '/installation/javascript-sdk';
|
|
25
26
|
function processOptions(obj) {
|
|
@@ -113,6 +114,7 @@ export default class API {
|
|
|
113
114
|
Fonts(app);
|
|
114
115
|
Network(app, options.network);
|
|
115
116
|
Selection(app);
|
|
117
|
+
Tabs(app);
|
|
116
118
|
window.__OPENREPLAY__ = this;
|
|
117
119
|
if (options.autoResetOnWindowOpen) {
|
|
118
120
|
const wOpen = window.open;
|
|
@@ -137,7 +139,7 @@ export default class API {
|
|
|
137
139
|
// no-cors issue only with text/plain or not-set Content-Type
|
|
138
140
|
// req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
139
141
|
req.send(JSON.stringify({
|
|
140
|
-
trackerVersion: '
|
|
142
|
+
trackerVersion: '8.0.0-beta.1',
|
|
141
143
|
projectKey: options.projectKey,
|
|
142
144
|
doNotTrack,
|
|
143
145
|
// TODO: add precise reason (an exact API missing)
|
|
@@ -183,6 +185,12 @@ export default class API {
|
|
|
183
185
|
}
|
|
184
186
|
return this.app.getSessionID();
|
|
185
187
|
}
|
|
188
|
+
getTabId() {
|
|
189
|
+
if (this.app === null) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
return this.app.getTabId();
|
|
193
|
+
}
|
|
186
194
|
sessionID() {
|
|
187
195
|
deprecationWarn("'sessionID' method", "'getSessionID' method", '/');
|
|
188
196
|
return this.getSessionID();
|
package/lib/modules/network.js
CHANGED
|
@@ -158,7 +158,7 @@ export default function (app, opts = {}) {
|
|
|
158
158
|
xhr.addEventListener('load', app.safe((e) => {
|
|
159
159
|
const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
|
|
160
160
|
const duration = startTime > 0 ? e.timeStamp - startTime : 0;
|
|
161
|
-
const hString = xhr.getAllResponseHeaders() || ''; // might be null (
|
|
161
|
+
const hString = xhr.getAllResponseHeaders() || ''; // might be null (only if no response received though)
|
|
162
162
|
const headersArr = hString.trim().split(/[\r\n]+/);
|
|
163
163
|
const headerMap = {};
|
|
164
164
|
headersArr.forEach(function (line) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TabChange } from '../app/messages.gen.js';
|
|
2
|
+
export default function (app) {
|
|
3
|
+
function changeTab() {
|
|
4
|
+
if (!document.hidden) {
|
|
5
|
+
app.debug.log('Openreplay: tab change to' + app.session.getTabId());
|
|
6
|
+
app.send(TabChange(app.session.getTabId()));
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
app.attachEventListener(window, 'focus', changeTab, false, false);
|
|
10
|
+
}
|
package/lib/utils.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ export declare const DOCS_HOST = "https://docs.openreplay.com";
|
|
|
11
11
|
export declare function deprecationWarn(nameOfFeature: string, useInstead: string, docsPath?: string): void;
|
|
12
12
|
export declare function getLabelAttribute(e: Element): string | null;
|
|
13
13
|
export declare function hasOpenreplayAttribute(e: Element, attr: string): boolean;
|
|
14
|
-
export declare function isIframeCrossdomain(e: HTMLIFrameElement): boolean;
|
|
15
14
|
/**
|
|
16
15
|
* checks if iframe is accessible
|
|
17
16
|
**/
|
|
18
17
|
export declare function canAccessIframe(iframe: HTMLIFrameElement): boolean;
|
|
18
|
+
export declare function generateRandomId(len?: number): string;
|
package/lib/utils.js
CHANGED
|
@@ -59,15 +59,6 @@ export function hasOpenreplayAttribute(e, attr) {
|
|
|
59
59
|
}
|
|
60
60
|
return false;
|
|
61
61
|
}
|
|
62
|
-
export function isIframeCrossdomain(e) {
|
|
63
|
-
var _a;
|
|
64
|
-
try {
|
|
65
|
-
return ((_a = e.contentWindow) === null || _a === void 0 ? void 0 : _a.location.href) !== window.location.href;
|
|
66
|
-
}
|
|
67
|
-
catch (e) {
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
62
|
/**
|
|
72
63
|
* checks if iframe is accessible
|
|
73
64
|
**/
|
|
@@ -79,3 +70,14 @@ export function canAccessIframe(iframe) {
|
|
|
79
70
|
return false;
|
|
80
71
|
}
|
|
81
72
|
}
|
|
73
|
+
function dec2hex(dec) {
|
|
74
|
+
return dec.toString(16).padStart(2, '0');
|
|
75
|
+
}
|
|
76
|
+
export function generateRandomId(len) {
|
|
77
|
+
const arr = new Uint8Array((len || 40) / 2);
|
|
78
|
+
// msCrypto = IE11
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
const safeCrypto = window.crypto || window.msCrypto;
|
|
81
|
+
safeCrypto.getRandomValues(arr);
|
|
82
|
+
return Array.from(arr, dec2hex).join('');
|
|
83
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openreplay/tracker",
|
|
3
3
|
"description": "The OpenReplay tracker main package",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "8.0.0-beta.1",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"logging",
|
|
7
7
|
"replay"
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
"build": "npm run clean && npm run tscRun && npm run rollup && npm run compile",
|
|
23
23
|
"prepare": "cd ../../ && husky install tracker/.husky/",
|
|
24
24
|
"lint-front": "lint-staged",
|
|
25
|
-
"test": "jest"
|
|
25
|
+
"test": "jest --coverage=false",
|
|
26
|
+
"test:ci": "jest --coverage=true",
|
|
27
|
+
"postversion": "npm run build"
|
|
26
28
|
},
|
|
27
29
|
"devDependencies": {
|
|
28
30
|
"@babel/core": "^7.10.2",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export type Options = {
|
|
2
|
-
root: Element;
|
|
3
|
-
idName: (name: string) => boolean;
|
|
4
|
-
className: (name: string) => boolean;
|
|
5
|
-
tagName: (name: string) => boolean;
|
|
6
|
-
attr: (name: string, value: string) => boolean;
|
|
7
|
-
seedMinLength: number;
|
|
8
|
-
optimizedMinLength: number;
|
|
9
|
-
threshold: number;
|
|
10
|
-
maxNumberOfTries: number;
|
|
11
|
-
};
|
|
12
|
-
export declare function finder(input: Element, options?: Partial<Options>): string;
|
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.finder = void 0;
|
|
4
|
-
var Limit;
|
|
5
|
-
(function (Limit) {
|
|
6
|
-
Limit[Limit["All"] = 0] = "All";
|
|
7
|
-
Limit[Limit["Two"] = 1] = "Two";
|
|
8
|
-
Limit[Limit["One"] = 2] = "One";
|
|
9
|
-
})(Limit || (Limit = {}));
|
|
10
|
-
let config;
|
|
11
|
-
let rootDocument;
|
|
12
|
-
function finder(input, options) {
|
|
13
|
-
if (input.nodeType !== Node.ELEMENT_NODE) {
|
|
14
|
-
throw new Error("Can't generate CSS selector for non-element node type.");
|
|
15
|
-
}
|
|
16
|
-
if ('html' === input.tagName.toLowerCase()) {
|
|
17
|
-
return 'html';
|
|
18
|
-
}
|
|
19
|
-
const defaults = {
|
|
20
|
-
root: document.body,
|
|
21
|
-
idName: (name) => true,
|
|
22
|
-
className: (name) => true,
|
|
23
|
-
tagName: (name) => true,
|
|
24
|
-
attr: (name, value) => false,
|
|
25
|
-
seedMinLength: 1,
|
|
26
|
-
optimizedMinLength: 2,
|
|
27
|
-
threshold: 1000,
|
|
28
|
-
maxNumberOfTries: 10000,
|
|
29
|
-
};
|
|
30
|
-
config = Object.assign(Object.assign({}, defaults), options);
|
|
31
|
-
rootDocument = findRootDocument(config.root, defaults);
|
|
32
|
-
let path = bottomUpSearch(input, Limit.All, () => bottomUpSearch(input, Limit.Two, () => bottomUpSearch(input, Limit.One)));
|
|
33
|
-
if (path) {
|
|
34
|
-
const optimized = sort(optimize(path, input));
|
|
35
|
-
if (optimized.length > 0) {
|
|
36
|
-
path = optimized[0];
|
|
37
|
-
}
|
|
38
|
-
return selector(path);
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
throw new Error('Selector was not found.');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
exports.finder = finder;
|
|
45
|
-
function findRootDocument(rootNode, defaults) {
|
|
46
|
-
if (rootNode.nodeType === Node.DOCUMENT_NODE) {
|
|
47
|
-
return rootNode;
|
|
48
|
-
}
|
|
49
|
-
if (rootNode === defaults.root) {
|
|
50
|
-
return rootNode.ownerDocument;
|
|
51
|
-
}
|
|
52
|
-
return rootNode;
|
|
53
|
-
}
|
|
54
|
-
function bottomUpSearch(input, limit, fallback) {
|
|
55
|
-
let path = null;
|
|
56
|
-
const stack = [];
|
|
57
|
-
let current = input;
|
|
58
|
-
let i = 0;
|
|
59
|
-
while (current && current !== config.root.parentElement) {
|
|
60
|
-
let level = maybe(id(current)) ||
|
|
61
|
-
maybe(...attr(current)) ||
|
|
62
|
-
maybe(...classNames(current)) ||
|
|
63
|
-
maybe(tagName(current)) || [any()];
|
|
64
|
-
const nth = index(current);
|
|
65
|
-
if (limit === Limit.All) {
|
|
66
|
-
if (nth) {
|
|
67
|
-
level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
else if (limit === Limit.Two) {
|
|
71
|
-
level = level.slice(0, 1);
|
|
72
|
-
if (nth) {
|
|
73
|
-
level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
else if (limit === Limit.One) {
|
|
77
|
-
const [node] = (level = level.slice(0, 1));
|
|
78
|
-
if (nth && dispensableNth(node)) {
|
|
79
|
-
level = [nthChild(node, nth)];
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
for (const node of level) {
|
|
83
|
-
node.level = i;
|
|
84
|
-
}
|
|
85
|
-
stack.push(level);
|
|
86
|
-
if (stack.length >= config.seedMinLength) {
|
|
87
|
-
path = findUniquePath(stack, fallback);
|
|
88
|
-
if (path) {
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
current = current.parentElement;
|
|
93
|
-
i++;
|
|
94
|
-
}
|
|
95
|
-
if (!path) {
|
|
96
|
-
path = findUniquePath(stack, fallback);
|
|
97
|
-
}
|
|
98
|
-
return path;
|
|
99
|
-
}
|
|
100
|
-
function findUniquePath(stack, fallback) {
|
|
101
|
-
const paths = sort(combinations(stack));
|
|
102
|
-
if (paths.length > config.threshold) {
|
|
103
|
-
return fallback ? fallback() : null;
|
|
104
|
-
}
|
|
105
|
-
for (const candidate of paths) {
|
|
106
|
-
if (unique(candidate)) {
|
|
107
|
-
return candidate;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
function selector(path) {
|
|
113
|
-
let node = path[0];
|
|
114
|
-
let query = node.name;
|
|
115
|
-
for (let i = 1; i < path.length; i++) {
|
|
116
|
-
const level = path[i].level || 0;
|
|
117
|
-
if (node.level === level - 1) {
|
|
118
|
-
query = `${path[i].name} > ${query}`;
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
query = `${path[i].name} ${query}`;
|
|
122
|
-
}
|
|
123
|
-
node = path[i];
|
|
124
|
-
}
|
|
125
|
-
return query;
|
|
126
|
-
}
|
|
127
|
-
function penalty(path) {
|
|
128
|
-
return path.map((node) => node.penalty).reduce((acc, i) => acc + i, 0);
|
|
129
|
-
}
|
|
130
|
-
function unique(path) {
|
|
131
|
-
switch (rootDocument.querySelectorAll(selector(path)).length) {
|
|
132
|
-
case 0:
|
|
133
|
-
throw new Error(`Can't select any node with this selector: ${selector(path)}`);
|
|
134
|
-
case 1:
|
|
135
|
-
return true;
|
|
136
|
-
default:
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
function id(input) {
|
|
141
|
-
const elementId = input.getAttribute('id');
|
|
142
|
-
if (elementId && config.idName(elementId)) {
|
|
143
|
-
return {
|
|
144
|
-
name: '#' + cssesc(elementId, { isIdentifier: true }),
|
|
145
|
-
penalty: 0,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
function attr(input) {
|
|
151
|
-
const attrs = Array.from(input.attributes).filter((attr) => config.attr(attr.name, attr.value));
|
|
152
|
-
return attrs.map((attr) => ({
|
|
153
|
-
name: '[' + cssesc(attr.name, { isIdentifier: true }) + '="' + cssesc(attr.value) + '"]',
|
|
154
|
-
penalty: 0.5,
|
|
155
|
-
}));
|
|
156
|
-
}
|
|
157
|
-
function classNames(input) {
|
|
158
|
-
const names = Array.from(input.classList).filter(config.className);
|
|
159
|
-
return names.map((name) => ({
|
|
160
|
-
name: '.' + cssesc(name, { isIdentifier: true }),
|
|
161
|
-
penalty: 1,
|
|
162
|
-
}));
|
|
163
|
-
}
|
|
164
|
-
function tagName(input) {
|
|
165
|
-
const name = input.tagName.toLowerCase();
|
|
166
|
-
if (config.tagName(name)) {
|
|
167
|
-
return {
|
|
168
|
-
name,
|
|
169
|
-
penalty: 2,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
function any() {
|
|
175
|
-
return {
|
|
176
|
-
name: '*',
|
|
177
|
-
penalty: 3,
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
function index(input) {
|
|
181
|
-
const parent = input.parentNode;
|
|
182
|
-
if (!parent) {
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
let child = parent.firstChild;
|
|
186
|
-
if (!child) {
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
let i = 0;
|
|
190
|
-
while (child) {
|
|
191
|
-
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
192
|
-
i++;
|
|
193
|
-
}
|
|
194
|
-
if (child === input) {
|
|
195
|
-
break;
|
|
196
|
-
}
|
|
197
|
-
child = child.nextSibling;
|
|
198
|
-
}
|
|
199
|
-
return i;
|
|
200
|
-
}
|
|
201
|
-
function nthChild(node, i) {
|
|
202
|
-
return {
|
|
203
|
-
name: node.name + `:nth-child(${i})`,
|
|
204
|
-
penalty: node.penalty + 1,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
function dispensableNth(node) {
|
|
208
|
-
return node.name !== 'html' && !node.name.startsWith('#');
|
|
209
|
-
}
|
|
210
|
-
function maybe(...level) {
|
|
211
|
-
const list = level.filter(notEmpty);
|
|
212
|
-
if (list.length > 0) {
|
|
213
|
-
return list;
|
|
214
|
-
}
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
function notEmpty(value) {
|
|
218
|
-
return value !== null && value !== undefined;
|
|
219
|
-
}
|
|
220
|
-
function combinations(stack, path = []) {
|
|
221
|
-
const paths = [];
|
|
222
|
-
if (stack.length > 0) {
|
|
223
|
-
for (const node of stack[0]) {
|
|
224
|
-
paths.push(...combinations(stack.slice(1, stack.length), path.concat(node)));
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
paths.push(path);
|
|
229
|
-
}
|
|
230
|
-
return paths;
|
|
231
|
-
}
|
|
232
|
-
function sort(paths) {
|
|
233
|
-
return Array.from(paths).sort((a, b) => penalty(a) - penalty(b));
|
|
234
|
-
}
|
|
235
|
-
function optimize(path, input, scope = {
|
|
236
|
-
counter: 0,
|
|
237
|
-
visited: new Map(),
|
|
238
|
-
}) {
|
|
239
|
-
const paths = [];
|
|
240
|
-
if (path.length > 2 && path.length > config.optimizedMinLength) {
|
|
241
|
-
for (let i = 1; i < path.length - 1; i++) {
|
|
242
|
-
if (scope.counter > config.maxNumberOfTries) {
|
|
243
|
-
return paths; // Okay At least I tried!
|
|
244
|
-
}
|
|
245
|
-
scope.counter += 1;
|
|
246
|
-
const newPath = [...path];
|
|
247
|
-
newPath.splice(i, 1);
|
|
248
|
-
const newPathKey = selector(newPath);
|
|
249
|
-
if (scope.visited.has(newPathKey)) {
|
|
250
|
-
return paths;
|
|
251
|
-
}
|
|
252
|
-
if (unique(newPath) && same(newPath, input)) {
|
|
253
|
-
paths.push(newPath);
|
|
254
|
-
scope.visited.set(newPathKey, true);
|
|
255
|
-
paths.push(...optimize(newPath, input, scope));
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return paths;
|
|
260
|
-
}
|
|
261
|
-
function same(path, input) {
|
|
262
|
-
return rootDocument.querySelector(selector(path)) === input;
|
|
263
|
-
}
|
|
264
|
-
const regexAnySingleEscape = /[ -,\.\/:-@\[-\^`\{-~]/;
|
|
265
|
-
const regexSingleEscape = /[ -,\.\/:-@\[\]\^`\{-~]/;
|
|
266
|
-
const regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
|
|
267
|
-
const defaultOptions = {
|
|
268
|
-
escapeEverything: false,
|
|
269
|
-
isIdentifier: false,
|
|
270
|
-
quotes: 'single',
|
|
271
|
-
wrap: false,
|
|
272
|
-
};
|
|
273
|
-
function cssesc(string, opt = {}) {
|
|
274
|
-
const options = Object.assign(Object.assign({}, defaultOptions), opt);
|
|
275
|
-
if (options.quotes != 'single' && options.quotes != 'double') {
|
|
276
|
-
options.quotes = 'single';
|
|
277
|
-
}
|
|
278
|
-
const quote = options.quotes == 'double' ? '"' : "'";
|
|
279
|
-
const isIdentifier = options.isIdentifier;
|
|
280
|
-
const firstChar = string.charAt(0);
|
|
281
|
-
let output = '';
|
|
282
|
-
let counter = 0;
|
|
283
|
-
const length = string.length;
|
|
284
|
-
while (counter < length) {
|
|
285
|
-
const character = string.charAt(counter++);
|
|
286
|
-
let codePoint = character.charCodeAt(0);
|
|
287
|
-
let value = void 0;
|
|
288
|
-
// If it’s not a printable ASCII character…
|
|
289
|
-
if (codePoint < 0x20 || codePoint > 0x7e) {
|
|
290
|
-
if (codePoint >= 0xd800 && codePoint <= 0xdbff && counter < length) {
|
|
291
|
-
// It’s a high surrogate, and there is a next character.
|
|
292
|
-
const extra = string.charCodeAt(counter++);
|
|
293
|
-
if ((extra & 0xfc00) == 0xdc00) {
|
|
294
|
-
// next character is low surrogate
|
|
295
|
-
codePoint = ((codePoint & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
// It’s an unmatched surrogate; only append this code unit, in case
|
|
299
|
-
// the next code unit is the high surrogate of a surrogate pair.
|
|
300
|
-
counter--;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
if (options.escapeEverything) {
|
|
307
|
-
if (regexAnySingleEscape.test(character)) {
|
|
308
|
-
value = '\\' + character;
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
else if (/[\t\n\f\r\x0B]/.test(character)) {
|
|
315
|
-
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
|
|
316
|
-
}
|
|
317
|
-
else if (character == '\\' ||
|
|
318
|
-
(!isIdentifier &&
|
|
319
|
-
((character == '"' && quote == character) || (character == "'" && quote == character))) ||
|
|
320
|
-
(isIdentifier && regexSingleEscape.test(character))) {
|
|
321
|
-
value = '\\' + character;
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
value = character;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
output += value;
|
|
328
|
-
}
|
|
329
|
-
if (isIdentifier) {
|
|
330
|
-
if (/^-[-\d]/.test(output)) {
|
|
331
|
-
output = '\\-' + output.slice(1);
|
|
332
|
-
}
|
|
333
|
-
else if (/\d/.test(firstChar)) {
|
|
334
|
-
output = '\\3' + firstChar + ' ' + output.slice(1);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// Remove spaces after `\HEX` escapes that are not followed by a hex digit,
|
|
338
|
-
// since they’re redundant. Note that this is only possible if the escape
|
|
339
|
-
// sequence isn’t preceded by an odd number of backslashes.
|
|
340
|
-
output = output.replace(regexExcessiveSpaces, function ($0, $1, $2) {
|
|
341
|
-
if ($1 && $1.length % 2) {
|
|
342
|
-
// It’s not safe to remove the space, so don’t.
|
|
343
|
-
return $0;
|
|
344
|
-
}
|
|
345
|
-
// Strip the space.
|
|
346
|
-
return ($1 || '') + $2;
|
|
347
|
-
});
|
|
348
|
-
if (!isIdentifier && options.wrap) {
|
|
349
|
-
return quote + output + quote;
|
|
350
|
-
}
|
|
351
|
-
return output;
|
|
352
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export type Options = {
|
|
2
|
-
root: Element;
|
|
3
|
-
idName: (name: string) => boolean;
|
|
4
|
-
className: (name: string) => boolean;
|
|
5
|
-
tagName: (name: string) => boolean;
|
|
6
|
-
attr: (name: string, value: string) => boolean;
|
|
7
|
-
seedMinLength: number;
|
|
8
|
-
optimizedMinLength: number;
|
|
9
|
-
threshold: number;
|
|
10
|
-
maxNumberOfTries: number;
|
|
11
|
-
};
|
|
12
|
-
export declare function finder(input: Element, options?: Partial<Options>): string;
|