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