why-hydration 0.2.0 → 0.3.0
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 +66 -0
- package/README.md +87 -23
- package/dist/chunk-CER5NQRR.js +1333 -0
- package/dist/chunk-CER5NQRR.js.map +1 -0
- package/dist/{chunk-3OAI2ZHY.js → chunk-KP4S6CRL.js} +339 -181
- package/dist/chunk-KP4S6CRL.js.map +1 -0
- package/dist/{chunk-KX6G7I4Y.cjs → chunk-QFHUKJ5K.cjs} +339 -181
- package/dist/chunk-QFHUKJ5K.cjs.map +1 -0
- package/dist/chunk-RWMRFTQ4.cjs +1356 -0
- package/dist/chunk-RWMRFTQ4.cjs.map +1 -0
- package/dist/index.cjs +19 -19
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +1 -1
- package/dist/next/index.cjs +4 -4
- package/dist/next/index.js +2 -2
- package/dist/react.cjs +4 -4
- package/dist/react.d.cts +4 -3
- package/dist/react.d.ts +4 -3
- package/dist/react.js +2 -2
- package/package.json +22 -4
- package/dist/chunk-3OAI2ZHY.js.map +0 -1
- package/dist/chunk-KX6G7I4Y.cjs.map +0 -1
- package/dist/chunk-MK3TYHKM.js +0 -966
- package/dist/chunk-MK3TYHKM.js.map +0 -1
- package/dist/chunk-R7IWOK5M.cjs +0 -989
- package/dist/chunk-R7IWOK5M.cjs.map +0 -1
|
@@ -12,6 +12,230 @@ function readNodeEnv() {
|
|
|
12
12
|
}
|
|
13
13
|
var isDev = readNodeEnv() !== "production";
|
|
14
14
|
|
|
15
|
+
// src/core/classify/detectors.ts
|
|
16
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17
|
+
var REACT_ID_RE = /^:[rR][0-9a-z]*:$/;
|
|
18
|
+
var HEX_TOKEN_RE = /^[0-9a-f]{16,}$/i;
|
|
19
|
+
var RANDOM_DECIMAL_RE = /^0?\.\d{6,}$/;
|
|
20
|
+
var NANOID_RE = /^[A-Za-z0-9_-]{10,}$/;
|
|
21
|
+
var ARABIC_INDIC_DIGITS = /[٠-٩۰-۹]/;
|
|
22
|
+
var LATIN_DIGITS = /[0-9]/;
|
|
23
|
+
var BIDI_CONTROLS = /[\u200e\u200f\u061c\u2066-\u2069]/g;
|
|
24
|
+
function stripBidiControls(value2) {
|
|
25
|
+
return value2.replace(BIDI_CONTROLS, "");
|
|
26
|
+
}
|
|
27
|
+
function differsOnlyByBidiControls(a, b) {
|
|
28
|
+
const sa = stripBidiControls(a);
|
|
29
|
+
const sb = stripBidiControls(b);
|
|
30
|
+
return a !== b && sa === sb && sa.trim() !== "";
|
|
31
|
+
}
|
|
32
|
+
function normalizeNumerals(value2) {
|
|
33
|
+
return stripBidiControls(value2).replace(/[٠-٩۰-۹٫٬]/g, (ch) => {
|
|
34
|
+
if (ch === "\u066B") return ".";
|
|
35
|
+
if (ch === "\u066C") return ",";
|
|
36
|
+
const code2 = ch.charCodeAt(0);
|
|
37
|
+
const zero = code2 >= 1776 ? 1776 : 1632;
|
|
38
|
+
return String(code2 - zero);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function isRandomLike(value2) {
|
|
42
|
+
const v = value2.trim();
|
|
43
|
+
if (!v) return false;
|
|
44
|
+
if (UUID_RE.test(v)) return true;
|
|
45
|
+
if (REACT_ID_RE.test(v)) return true;
|
|
46
|
+
if (HEX_TOKEN_RE.test(v)) return true;
|
|
47
|
+
if (RANDOM_DECIMAL_RE.test(v)) return true;
|
|
48
|
+
if (NANOID_RE.test(v) && /[A-Za-z]/.test(v) && /[0-9]/.test(v)) return true;
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
function looksLikeTime(value2) {
|
|
52
|
+
return /\b\d{1,2}:\d{2}(?::\d{2})?(?:\s?[AaPp][Mm])?\b/.test(
|
|
53
|
+
normalizeNumerals(value2).trim()
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
var ISO_DATE = /^\d{4}-\d{1,2}(?:-\d{1,2})?(?:[T ]\d{1,2}:\d{2}(?::\d{2})?)?/;
|
|
57
|
+
var NUMERIC_DATE = /^\d{1,4}[/.-]\d{1,2}[/.-]\d{1,4}$/;
|
|
58
|
+
var TIME_OF_DAY = /^\d{1,2}:\d{2}(?::\d{2})?(?:\s?[AaPp]\.?[Mm]\.?)?$/;
|
|
59
|
+
var MONTH_NAME = /\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\b/i;
|
|
60
|
+
function looksLikeDate(v) {
|
|
61
|
+
return ISO_DATE.test(v) || NUMERIC_DATE.test(v) || TIME_OF_DAY.test(v) || MONTH_NAME.test(v) && /\d/.test(v);
|
|
62
|
+
}
|
|
63
|
+
function toTimestamp(value2) {
|
|
64
|
+
const v = value2.trim();
|
|
65
|
+
if (!v) return null;
|
|
66
|
+
if (/^\d{10,13}$/.test(v)) {
|
|
67
|
+
const n = Number(v);
|
|
68
|
+
return v.length === 10 ? n * 1e3 : n;
|
|
69
|
+
}
|
|
70
|
+
if (!looksLikeDate(v)) return null;
|
|
71
|
+
const parsed = Date.parse(v);
|
|
72
|
+
if (!Number.isNaN(parsed)) return parsed;
|
|
73
|
+
if (looksLikeTime(v)) {
|
|
74
|
+
const anchored = Date.parse(`1970-01-01 ${v}`);
|
|
75
|
+
if (!Number.isNaN(anchored)) return anchored;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
function hasArabicIndicDigits(value2) {
|
|
80
|
+
return ARABIC_INDIC_DIGITS.test(value2);
|
|
81
|
+
}
|
|
82
|
+
function hasLatinDigits(value2) {
|
|
83
|
+
return LATIN_DIGITS.test(value2);
|
|
84
|
+
}
|
|
85
|
+
var NUMERIC_LIKE = /^[+-]?[\d.,\s\u00a0\u2009]+$/;
|
|
86
|
+
function isSameNumberDifferentSeparators(a, b) {
|
|
87
|
+
const at = normalizeNumerals(a).trim();
|
|
88
|
+
const bt = normalizeNumerals(b).trim();
|
|
89
|
+
if (!NUMERIC_LIKE.test(at) || !NUMERIC_LIKE.test(bt)) return false;
|
|
90
|
+
const digitsOnly = (s) => s.replace(/\D/g, "");
|
|
91
|
+
const da = digitsOnly(at);
|
|
92
|
+
const db = digitsOnly(bt);
|
|
93
|
+
if (!da || da !== db) return false;
|
|
94
|
+
const hasSep = (s) => /[.,\s\u00a0\u2009]/.test(s);
|
|
95
|
+
return (hasSep(at) || hasSep(bt)) && a.trim() !== b.trim();
|
|
96
|
+
}
|
|
97
|
+
var CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
98
|
+
"value",
|
|
99
|
+
"placeholder",
|
|
100
|
+
"title",
|
|
101
|
+
"alt",
|
|
102
|
+
"label",
|
|
103
|
+
"aria-label",
|
|
104
|
+
"aria-valuetext",
|
|
105
|
+
"content",
|
|
106
|
+
"datetime"
|
|
107
|
+
]);
|
|
108
|
+
function isContentAttribute(name) {
|
|
109
|
+
return CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
110
|
+
}
|
|
111
|
+
var THIRD_PARTY_MARKERS = /googlefc|adsbygoogle|google_ads|googletag|__tcfapi|onetrust|optanon|cookiebot|usercentrics|iubenda|didomi|quantcast|grammarly|data-gramm|gtm-|_hjsettings|hotjar|fullstory|intercom|drift|zendesk|livechat|tawk|hubspot|turnstile|recaptcha/i;
|
|
112
|
+
function looksLikeThirdPartyNode(html, tagName) {
|
|
113
|
+
const tag = (tagName ?? "").toUpperCase();
|
|
114
|
+
if (tag === "IFRAME" || tag === "EMBED" || tag === "OBJECT") return true;
|
|
115
|
+
const h = (html ?? "").toLowerCase();
|
|
116
|
+
if (!h) return false;
|
|
117
|
+
return THIRD_PARTY_MARKERS.test(h) || h.includes("about:blank");
|
|
118
|
+
}
|
|
119
|
+
var DATE_PARTS_RE = /^(\d{1,4})[/.-](\d{1,2})[/.-](\d{1,4})$/;
|
|
120
|
+
function isSameDateDifferentOrder(a, b) {
|
|
121
|
+
const partsA = normalizeNumerals(a).trim().match(DATE_PARTS_RE);
|
|
122
|
+
const partsB = normalizeNumerals(b).trim().match(DATE_PARTS_RE);
|
|
123
|
+
if (!partsA || !partsB) return false;
|
|
124
|
+
const setA = [partsA[1], partsA[2], partsA[3]].sort().join("|");
|
|
125
|
+
const setB = [partsB[1], partsB[2], partsB[3]].sort().join("|");
|
|
126
|
+
return setA === setB && a.trim() !== b.trim();
|
|
127
|
+
}
|
|
128
|
+
var EXTENSION_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
129
|
+
"cz-shortcut-listen",
|
|
130
|
+
"data-gramm",
|
|
131
|
+
"data-gramm_editor",
|
|
132
|
+
"data-gramm_id",
|
|
133
|
+
"data-gr-c-s-loaded",
|
|
134
|
+
"data-lt-installed",
|
|
135
|
+
"data-new-gr-c-s-check-loaded",
|
|
136
|
+
"data-new-gr-c-s-loaded",
|
|
137
|
+
"spellcheck-extension",
|
|
138
|
+
"bis_register",
|
|
139
|
+
"__processed_by_react_dev_tools"
|
|
140
|
+
]);
|
|
141
|
+
function isExtensionAttribute(name) {
|
|
142
|
+
const n = name.toLowerCase();
|
|
143
|
+
if (EXTENSION_ATTRIBUTES.has(n)) return true;
|
|
144
|
+
return n.startsWith("data-gr-") || n.startsWith("data-gramm") || n.startsWith("__bis") || n.startsWith("bis_");
|
|
145
|
+
}
|
|
146
|
+
var CLOSES_P = [
|
|
147
|
+
"address",
|
|
148
|
+
"article",
|
|
149
|
+
"aside",
|
|
150
|
+
"blockquote",
|
|
151
|
+
"center",
|
|
152
|
+
"details",
|
|
153
|
+
"dialog",
|
|
154
|
+
"dir",
|
|
155
|
+
"div",
|
|
156
|
+
"dl",
|
|
157
|
+
"fieldset",
|
|
158
|
+
"figcaption",
|
|
159
|
+
"figure",
|
|
160
|
+
"footer",
|
|
161
|
+
"form",
|
|
162
|
+
"h1",
|
|
163
|
+
"h2",
|
|
164
|
+
"h3",
|
|
165
|
+
"h4",
|
|
166
|
+
"h5",
|
|
167
|
+
"h6",
|
|
168
|
+
"header",
|
|
169
|
+
"hgroup",
|
|
170
|
+
"hr",
|
|
171
|
+
"li",
|
|
172
|
+
"dd",
|
|
173
|
+
"dt",
|
|
174
|
+
"listing",
|
|
175
|
+
"main",
|
|
176
|
+
"menu",
|
|
177
|
+
"nav",
|
|
178
|
+
"ol",
|
|
179
|
+
"p",
|
|
180
|
+
"plaintext",
|
|
181
|
+
"pre",
|
|
182
|
+
"search",
|
|
183
|
+
"section",
|
|
184
|
+
"summary",
|
|
185
|
+
"table",
|
|
186
|
+
"ul",
|
|
187
|
+
"xmp"
|
|
188
|
+
];
|
|
189
|
+
var CLOSES_P_SET = new Set(CLOSES_P.map((t) => t.toUpperCase()));
|
|
190
|
+
var TABLE_CHILDREN = /* @__PURE__ */ new Set([
|
|
191
|
+
"CAPTION",
|
|
192
|
+
"COLGROUP",
|
|
193
|
+
"THEAD",
|
|
194
|
+
"TBODY",
|
|
195
|
+
"TFOOT"
|
|
196
|
+
]);
|
|
197
|
+
var TABLE_SCAFFOLD = ["script", "template", "style"];
|
|
198
|
+
var TABLE_LEVEL = ["caption", "colgroup", "thead", "tbody", "tfoot"];
|
|
199
|
+
var SECTION_LEVEL = ["tr"];
|
|
200
|
+
var ROW_LEVEL = ["td", "th"];
|
|
201
|
+
var notIn = (tags) => `:not(${[...tags, ...TABLE_SCAFFOLD].join(", ")})`;
|
|
202
|
+
var PARSER_REPAIRS = {
|
|
203
|
+
P: CLOSES_P.join(", "),
|
|
204
|
+
A: "a",
|
|
205
|
+
BUTTON: "button",
|
|
206
|
+
FORM: "form",
|
|
207
|
+
TABLE: [
|
|
208
|
+
`:scope > ${notIn([...TABLE_LEVEL, ...SECTION_LEVEL])}`,
|
|
209
|
+
...["thead", "tbody", "tfoot"].flatMap((section) => [
|
|
210
|
+
`:scope > ${section} > ${notIn(SECTION_LEVEL)}`,
|
|
211
|
+
`:scope > ${section} > tr > ${notIn(ROW_LEVEL)}`
|
|
212
|
+
]),
|
|
213
|
+
`:scope > tr > ${notIn(ROW_LEVEL)}`
|
|
214
|
+
].join(", ")
|
|
215
|
+
};
|
|
216
|
+
function isInvalidNesting(parentTag, childTag) {
|
|
217
|
+
if (!parentTag || !childTag) return false;
|
|
218
|
+
const p = parentTag.toUpperCase();
|
|
219
|
+
const c = childTag.toUpperCase();
|
|
220
|
+
if (p === "P") return CLOSES_P_SET.has(c);
|
|
221
|
+
if (p === "A") return c === "A";
|
|
222
|
+
if (p === "BUTTON") return c === "BUTTON" || c === "A";
|
|
223
|
+
if (p === "FORM") return c === "FORM";
|
|
224
|
+
if (p === "TABLE") return !TABLE_CHILDREN.has(c) && !isScaffold(c);
|
|
225
|
+
if (p === "THEAD" || p === "TBODY" || p === "TFOOT") {
|
|
226
|
+
return c !== "TR" && !isScaffold(c);
|
|
227
|
+
}
|
|
228
|
+
if (p === "TR") return c !== "TD" && c !== "TH" && !isScaffold(c);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
function isScaffold(tag) {
|
|
232
|
+
return TABLE_SCAFFOLD.includes(tag.toLowerCase());
|
|
233
|
+
}
|
|
234
|
+
function messageIndicatesInvalidNesting(message) {
|
|
235
|
+
if (!message) return false;
|
|
236
|
+
return /validateDOMNesting/i.test(message) || /cannot (?:be a|contain).*(?:descendant|child)/i.test(message) || /cannot appear as a (?:child|descendant)/i.test(message);
|
|
237
|
+
}
|
|
238
|
+
|
|
15
239
|
// src/core/diff.ts
|
|
16
240
|
var IGNORED_ATTRIBUTES = /* @__PURE__ */ new Set(["data-reactroot"]);
|
|
17
241
|
function parseServerHtml(html, rootTagName) {
|
|
@@ -38,9 +262,15 @@ function diffSnapshotAgainstDom(serverHtml, clientRoot) {
|
|
|
38
262
|
function collectChildren(serverParent, clientParent, parentPath, out, limit) {
|
|
39
263
|
if (out.length >= limit) return;
|
|
40
264
|
const serverChildren = meaningfulChildNodes(serverParent);
|
|
41
|
-
const clientChildren = meaningfulChildNodes(clientParent);
|
|
42
265
|
const parentPending = hasPendingSuspense(serverParent);
|
|
43
266
|
const parentTag = elementTag(clientParent);
|
|
267
|
+
const clientChildren = repairClientChildren(
|
|
268
|
+
meaningfulChildNodes(clientParent),
|
|
269
|
+
parentTag,
|
|
270
|
+
parentPath,
|
|
271
|
+
out,
|
|
272
|
+
limit
|
|
273
|
+
);
|
|
44
274
|
const pairs = alignChildren(serverChildren, clientChildren);
|
|
45
275
|
let index = 0;
|
|
46
276
|
for (let k = 0; k < pairs.length; k++) {
|
|
@@ -88,7 +318,10 @@ function collectChildren(serverParent, clientParent, parentPath, out, limit) {
|
|
|
88
318
|
parentTagName: parentTag,
|
|
89
319
|
server: null,
|
|
90
320
|
client: serialize(clientNode),
|
|
91
|
-
element
|
|
321
|
+
// An added text node has no element of its own, so point at its
|
|
322
|
+
// parent, as text changes do. With `null` the component lookup found
|
|
323
|
+
// nothing and fell back to whichever error was reported last.
|
|
324
|
+
element: asElement(clientNode) ?? asElement(clientParent)
|
|
92
325
|
});
|
|
93
326
|
} else if (serverNode && clientNode) {
|
|
94
327
|
collectNode(serverNode, clientNode, path, parentTag, out, limit);
|
|
@@ -134,7 +367,7 @@ function collectNode(serverNode, clientNode, path, parentTag, out, limit) {
|
|
|
134
367
|
parentTagName: parentTag,
|
|
135
368
|
server: serialize(serverEl),
|
|
136
369
|
client: serialize(clientEl),
|
|
137
|
-
element: clientEl
|
|
370
|
+
element: liveElement(clientEl)
|
|
138
371
|
});
|
|
139
372
|
return;
|
|
140
373
|
}
|
|
@@ -162,7 +395,7 @@ function diffAttributes(serverEl, clientEl, path, parentTag) {
|
|
|
162
395
|
attribute: name,
|
|
163
396
|
server: serverValue,
|
|
164
397
|
client: clientValue,
|
|
165
|
-
element: clientEl
|
|
398
|
+
element: liveElement(clientEl)
|
|
166
399
|
};
|
|
167
400
|
}
|
|
168
401
|
return null;
|
|
@@ -309,7 +542,8 @@ function meaningfulChildNodes(parent) {
|
|
|
309
542
|
for (const node of raw) {
|
|
310
543
|
if (node.nodeType === Node.COMMENT_NODE) {
|
|
311
544
|
const data = node.nodeValue ?? "";
|
|
312
|
-
if (data === "$?" || data === "$" || data === "$!")
|
|
545
|
+
if (data === "$?" || data === "$" || data === "$!")
|
|
546
|
+
boundaryStack.push(data);
|
|
313
547
|
else if (data === "/$") boundaryStack.pop();
|
|
314
548
|
continue;
|
|
315
549
|
}
|
|
@@ -332,7 +566,94 @@ function serialize(node) {
|
|
|
332
566
|
}
|
|
333
567
|
function asElement(node) {
|
|
334
568
|
if (!node) return null;
|
|
335
|
-
return node.nodeType === Node.ELEMENT_NODE ? node : null;
|
|
569
|
+
return node.nodeType === Node.ELEMENT_NODE ? liveElement(node) : null;
|
|
570
|
+
}
|
|
571
|
+
var LIVE = /* @__PURE__ */ new WeakMap();
|
|
572
|
+
function liveElement(el) {
|
|
573
|
+
return LIVE.get(el) ?? el;
|
|
574
|
+
}
|
|
575
|
+
function repairClientChildren(children, parentTag, parentPath, out, limit) {
|
|
576
|
+
let repaired = null;
|
|
577
|
+
children.forEach((child, i) => {
|
|
578
|
+
const expansion = repairedForm(child, parentTag);
|
|
579
|
+
if (!expansion) {
|
|
580
|
+
repaired?.push(child);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
repaired ??= children.slice(0, i);
|
|
584
|
+
repaired.push(...expansion.nodes);
|
|
585
|
+
if (out.length < limit) {
|
|
586
|
+
out.push({
|
|
587
|
+
kind: "structure",
|
|
588
|
+
path: childPath(parentPath, child, i),
|
|
589
|
+
tagName: expansion.offender.tagName,
|
|
590
|
+
parentTagName: invalidParent(expansion.offender, child),
|
|
591
|
+
// No values, on purpose: React reports the same nesting in its own
|
|
592
|
+
// warning with none, and matching it lets the two collapse into one.
|
|
593
|
+
server: null,
|
|
594
|
+
client: null,
|
|
595
|
+
element: expansion.offender
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
return repaired ?? children;
|
|
600
|
+
}
|
|
601
|
+
function invalidParent(offender, top) {
|
|
602
|
+
for (let el = offender.parentElement; el; el = el.parentElement) {
|
|
603
|
+
if (isInvalidNesting(el.tagName, offender.tagName)) return el.tagName;
|
|
604
|
+
if (el === top) break;
|
|
605
|
+
}
|
|
606
|
+
return top.tagName;
|
|
607
|
+
}
|
|
608
|
+
function repairedForm(node, parentTag) {
|
|
609
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return null;
|
|
610
|
+
const el = node;
|
|
611
|
+
const selector = PARSER_REPAIRS[el.tagName];
|
|
612
|
+
if (!selector) return null;
|
|
613
|
+
let offender = null;
|
|
614
|
+
try {
|
|
615
|
+
offender = el.querySelector(selector);
|
|
616
|
+
} catch {
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
if (!offender) return null;
|
|
620
|
+
const html = serializeKeepingTextBoundaries(el);
|
|
621
|
+
const container = parseServerHtml(html, parentTag ?? "div");
|
|
622
|
+
if (container.innerHTML === html) return null;
|
|
623
|
+
const nodes = meaningfulChildNodes(container);
|
|
624
|
+
mapToLive(el, nodes);
|
|
625
|
+
return { nodes, offender };
|
|
626
|
+
}
|
|
627
|
+
function serializeKeepingTextBoundaries(el) {
|
|
628
|
+
const copy = el.cloneNode(true);
|
|
629
|
+
const walker = copy.ownerDocument.createTreeWalker(
|
|
630
|
+
copy,
|
|
631
|
+
NodeFilter.SHOW_TEXT
|
|
632
|
+
);
|
|
633
|
+
const texts = [];
|
|
634
|
+
while (walker.nextNode()) texts.push(walker.currentNode);
|
|
635
|
+
for (const t of texts) {
|
|
636
|
+
if (t.previousSibling?.nodeType === Node.TEXT_NODE) {
|
|
637
|
+
t.parentNode.insertBefore(copy.ownerDocument.createComment(" "), t);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return copy.outerHTML;
|
|
641
|
+
}
|
|
642
|
+
function mapToLive(live, repaired) {
|
|
643
|
+
const liveEls = [live, ...Array.from(live.querySelectorAll("*"))];
|
|
644
|
+
let i = 0;
|
|
645
|
+
for (const root of repaired) {
|
|
646
|
+
if (root.nodeType !== Node.ELEMENT_NODE) continue;
|
|
647
|
+
const el = root;
|
|
648
|
+
for (const r of [el, ...Array.from(el.querySelectorAll("*"))]) {
|
|
649
|
+
let j = i;
|
|
650
|
+
while (j < liveEls.length && liveEls[j].tagName !== r.tagName) j++;
|
|
651
|
+
if (j < liveEls.length) {
|
|
652
|
+
LIVE.set(r, liveEls[j]);
|
|
653
|
+
i = j + 1;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
336
657
|
}
|
|
337
658
|
function elementTag(node) {
|
|
338
659
|
return node.nodeType === Node.ELEMENT_NODE ? node.tagName : void 0;
|
|
@@ -353,179 +674,6 @@ function childPath(parentPath, node, index) {
|
|
|
353
674
|
return `${parentPath} > #text[${index}]`;
|
|
354
675
|
}
|
|
355
676
|
|
|
356
|
-
// src/core/classify/detectors.ts
|
|
357
|
-
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
358
|
-
var REACT_ID_RE = /^:[rR][0-9a-z]*:$/;
|
|
359
|
-
var HEX_TOKEN_RE = /^[0-9a-f]{16,}$/i;
|
|
360
|
-
var RANDOM_DECIMAL_RE = /^0?\.\d{6,}$/;
|
|
361
|
-
var NANOID_RE = /^[A-Za-z0-9_-]{10,}$/;
|
|
362
|
-
var ARABIC_INDIC_DIGITS = /[٠-٩۰-۹]/;
|
|
363
|
-
var LATIN_DIGITS = /[0-9]/;
|
|
364
|
-
var BIDI_CONTROLS = /[\u200e\u200f\u061c\u2066-\u2069]/g;
|
|
365
|
-
function stripBidiControls(value2) {
|
|
366
|
-
return value2.replace(BIDI_CONTROLS, "");
|
|
367
|
-
}
|
|
368
|
-
function differsOnlyByBidiControls(a, b) {
|
|
369
|
-
const sa = stripBidiControls(a);
|
|
370
|
-
const sb = stripBidiControls(b);
|
|
371
|
-
return a !== b && sa === sb && sa.trim() !== "";
|
|
372
|
-
}
|
|
373
|
-
function normalizeNumerals(value2) {
|
|
374
|
-
return stripBidiControls(value2).replace(/[٠-٩۰-۹٫٬]/g, (ch) => {
|
|
375
|
-
if (ch === "\u066B") return ".";
|
|
376
|
-
if (ch === "\u066C") return ",";
|
|
377
|
-
const code2 = ch.charCodeAt(0);
|
|
378
|
-
const zero = code2 >= 1776 ? 1776 : 1632;
|
|
379
|
-
return String(code2 - zero);
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
function isRandomLike(value2) {
|
|
383
|
-
const v = value2.trim();
|
|
384
|
-
if (!v) return false;
|
|
385
|
-
if (UUID_RE.test(v)) return true;
|
|
386
|
-
if (REACT_ID_RE.test(v)) return true;
|
|
387
|
-
if (HEX_TOKEN_RE.test(v)) return true;
|
|
388
|
-
if (RANDOM_DECIMAL_RE.test(v)) return true;
|
|
389
|
-
if (NANOID_RE.test(v) && /[A-Za-z]/.test(v) && /[0-9]/.test(v)) return true;
|
|
390
|
-
return false;
|
|
391
|
-
}
|
|
392
|
-
function looksLikeTime(value2) {
|
|
393
|
-
return /\b\d{1,2}:\d{2}(?::\d{2})?(?:\s?[AaPp][Mm])?\b/.test(
|
|
394
|
-
normalizeNumerals(value2).trim()
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
var ISO_DATE = /^\d{4}-\d{1,2}(?:-\d{1,2})?(?:[T ]\d{1,2}:\d{2}(?::\d{2})?)?/;
|
|
398
|
-
var NUMERIC_DATE = /^\d{1,4}[/.-]\d{1,2}[/.-]\d{1,4}$/;
|
|
399
|
-
var TIME_OF_DAY = /^\d{1,2}:\d{2}(?::\d{2})?(?:\s?[AaPp]\.?[Mm]\.?)?$/;
|
|
400
|
-
var MONTH_NAME = /\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\b/i;
|
|
401
|
-
function looksLikeDate(v) {
|
|
402
|
-
return ISO_DATE.test(v) || NUMERIC_DATE.test(v) || TIME_OF_DAY.test(v) || MONTH_NAME.test(v) && /\d/.test(v);
|
|
403
|
-
}
|
|
404
|
-
function toTimestamp(value2) {
|
|
405
|
-
const v = value2.trim();
|
|
406
|
-
if (!v) return null;
|
|
407
|
-
if (/^\d{10,13}$/.test(v)) {
|
|
408
|
-
const n = Number(v);
|
|
409
|
-
return v.length === 10 ? n * 1e3 : n;
|
|
410
|
-
}
|
|
411
|
-
if (!looksLikeDate(v)) return null;
|
|
412
|
-
const parsed = Date.parse(v);
|
|
413
|
-
if (!Number.isNaN(parsed)) return parsed;
|
|
414
|
-
if (looksLikeTime(v)) {
|
|
415
|
-
const anchored = Date.parse(`1970-01-01 ${v}`);
|
|
416
|
-
if (!Number.isNaN(anchored)) return anchored;
|
|
417
|
-
}
|
|
418
|
-
return null;
|
|
419
|
-
}
|
|
420
|
-
function hasArabicIndicDigits(value2) {
|
|
421
|
-
return ARABIC_INDIC_DIGITS.test(value2);
|
|
422
|
-
}
|
|
423
|
-
function hasLatinDigits(value2) {
|
|
424
|
-
return LATIN_DIGITS.test(value2);
|
|
425
|
-
}
|
|
426
|
-
var NUMERIC_LIKE = /^[+-]?[\d.,\s\u00a0\u2009]+$/;
|
|
427
|
-
function isSameNumberDifferentSeparators(a, b) {
|
|
428
|
-
const at = normalizeNumerals(a).trim();
|
|
429
|
-
const bt = normalizeNumerals(b).trim();
|
|
430
|
-
if (!NUMERIC_LIKE.test(at) || !NUMERIC_LIKE.test(bt)) return false;
|
|
431
|
-
const digitsOnly = (s) => s.replace(/\D/g, "");
|
|
432
|
-
const da = digitsOnly(at);
|
|
433
|
-
const db = digitsOnly(bt);
|
|
434
|
-
if (!da || da !== db) return false;
|
|
435
|
-
const hasSep = (s) => /[.,\s\u00a0\u2009]/.test(s);
|
|
436
|
-
return (hasSep(at) || hasSep(bt)) && a.trim() !== b.trim();
|
|
437
|
-
}
|
|
438
|
-
var CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
439
|
-
"value",
|
|
440
|
-
"placeholder",
|
|
441
|
-
"title",
|
|
442
|
-
"alt",
|
|
443
|
-
"label",
|
|
444
|
-
"aria-label",
|
|
445
|
-
"aria-valuetext",
|
|
446
|
-
"content",
|
|
447
|
-
"datetime"
|
|
448
|
-
]);
|
|
449
|
-
function isContentAttribute(name) {
|
|
450
|
-
return CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
451
|
-
}
|
|
452
|
-
var THIRD_PARTY_MARKERS = /googlefc|adsbygoogle|google_ads|googletag|__tcfapi|onetrust|optanon|cookiebot|usercentrics|iubenda|didomi|quantcast|grammarly|data-gramm|gtm-|_hjsettings|hotjar|fullstory|intercom|drift|zendesk|livechat|tawk|hubspot|turnstile|recaptcha/i;
|
|
453
|
-
function looksLikeThirdPartyNode(html, tagName) {
|
|
454
|
-
const tag = (tagName ?? "").toUpperCase();
|
|
455
|
-
if (tag === "IFRAME" || tag === "EMBED" || tag === "OBJECT") return true;
|
|
456
|
-
const h = (html ?? "").toLowerCase();
|
|
457
|
-
if (!h) return false;
|
|
458
|
-
return THIRD_PARTY_MARKERS.test(h) || h.includes("about:blank");
|
|
459
|
-
}
|
|
460
|
-
var DATE_PARTS_RE = /^(\d{1,4})[/.-](\d{1,2})[/.-](\d{1,4})$/;
|
|
461
|
-
function isSameDateDifferentOrder(a, b) {
|
|
462
|
-
const partsA = normalizeNumerals(a).trim().match(DATE_PARTS_RE);
|
|
463
|
-
const partsB = normalizeNumerals(b).trim().match(DATE_PARTS_RE);
|
|
464
|
-
if (!partsA || !partsB) return false;
|
|
465
|
-
const setA = [partsA[1], partsA[2], partsA[3]].sort().join("|");
|
|
466
|
-
const setB = [partsB[1], partsB[2], partsB[3]].sort().join("|");
|
|
467
|
-
return setA === setB && a.trim() !== b.trim();
|
|
468
|
-
}
|
|
469
|
-
var EXTENSION_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
470
|
-
"cz-shortcut-listen",
|
|
471
|
-
"data-gramm",
|
|
472
|
-
"data-gramm_editor",
|
|
473
|
-
"data-gramm_id",
|
|
474
|
-
"data-gr-c-s-loaded",
|
|
475
|
-
"data-lt-installed",
|
|
476
|
-
"data-new-gr-c-s-check-loaded",
|
|
477
|
-
"data-new-gr-c-s-loaded",
|
|
478
|
-
"spellcheck-extension",
|
|
479
|
-
"bis_register",
|
|
480
|
-
"__processed_by_react_dev_tools"
|
|
481
|
-
]);
|
|
482
|
-
function isExtensionAttribute(name) {
|
|
483
|
-
const n = name.toLowerCase();
|
|
484
|
-
if (EXTENSION_ATTRIBUTES.has(n)) return true;
|
|
485
|
-
return n.startsWith("data-gr-") || n.startsWith("data-gramm") || n.startsWith("__bis") || n.startsWith("bis_");
|
|
486
|
-
}
|
|
487
|
-
var BLOCK_TAGS = /* @__PURE__ */ new Set([
|
|
488
|
-
"DIV",
|
|
489
|
-
"P",
|
|
490
|
-
"SECTION",
|
|
491
|
-
"ARTICLE",
|
|
492
|
-
"UL",
|
|
493
|
-
"OL",
|
|
494
|
-
"LI",
|
|
495
|
-
"TABLE",
|
|
496
|
-
"HEADER",
|
|
497
|
-
"FOOTER",
|
|
498
|
-
"MAIN",
|
|
499
|
-
"ASIDE",
|
|
500
|
-
"NAV",
|
|
501
|
-
"H1",
|
|
502
|
-
"H2",
|
|
503
|
-
"H3",
|
|
504
|
-
"H4",
|
|
505
|
-
"H5",
|
|
506
|
-
"H6",
|
|
507
|
-
"FORM",
|
|
508
|
-
"BLOCKQUOTE",
|
|
509
|
-
"PRE",
|
|
510
|
-
"HR"
|
|
511
|
-
]);
|
|
512
|
-
function isInvalidNesting(parentTag, childTag) {
|
|
513
|
-
if (!parentTag || !childTag) return false;
|
|
514
|
-
const p = parentTag.toUpperCase();
|
|
515
|
-
const c = childTag.toUpperCase();
|
|
516
|
-
if (p === "P" && BLOCK_TAGS.has(c)) return true;
|
|
517
|
-
if (p === "A" && c === "A") return true;
|
|
518
|
-
if (p === "BUTTON" && (c === "BUTTON" || c === "A")) return true;
|
|
519
|
-
if ((p === "TABLE" || p === "THEAD" || p === "TBODY") && c === "DIV") {
|
|
520
|
-
return true;
|
|
521
|
-
}
|
|
522
|
-
return false;
|
|
523
|
-
}
|
|
524
|
-
function messageIndicatesInvalidNesting(message) {
|
|
525
|
-
if (!message) return false;
|
|
526
|
-
return /validateDOMNesting/i.test(message) || /cannot (?:be a|contain).*(?:descendant|child)/i.test(message) || /cannot appear as a (?:child|descendant)/i.test(message);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
677
|
// src/core/classify/messages.ts
|
|
530
678
|
var code = (text) => ({ code: text });
|
|
531
679
|
var value = (text) => ({ value: text });
|
|
@@ -992,6 +1140,16 @@ var ReportCollector = class {
|
|
|
992
1140
|
this.options = options;
|
|
993
1141
|
this.maxReports = options.maxReports ?? 25;
|
|
994
1142
|
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Swap the rules, threshold, ignore list and cap for everything reported
|
|
1145
|
+
* from now on. Reports already collected are kept as they are: they were
|
|
1146
|
+
* correct under the options in force when they were made, and re-deciding
|
|
1147
|
+
* them would re-fire `onReport` for mismatches the caller already saw.
|
|
1148
|
+
*/
|
|
1149
|
+
configure(options) {
|
|
1150
|
+
this.options = options;
|
|
1151
|
+
this.maxReports = options.maxReports ?? 25;
|
|
1152
|
+
}
|
|
995
1153
|
/**
|
|
996
1154
|
* Register a sink. Pass `replay` for sinks that render *state* (the overlay)
|
|
997
1155
|
* rather than react to *events* (`onReport`, the console): they need the
|
|
@@ -1350,5 +1508,5 @@ exports.plainText = plainText;
|
|
|
1350
1508
|
exports.renderMessage = renderMessage;
|
|
1351
1509
|
exports.reportFromMessage = reportFromMessage;
|
|
1352
1510
|
exports.signatureOf = signatureOf;
|
|
1353
|
-
//# sourceMappingURL=chunk-
|
|
1354
|
-
//# sourceMappingURL=chunk-
|
|
1511
|
+
//# sourceMappingURL=chunk-QFHUKJ5K.cjs.map
|
|
1512
|
+
//# sourceMappingURL=chunk-QFHUKJ5K.cjs.map
|