bee-ladybug 0.6.0 → 0.6.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/package.json
CHANGED
|
@@ -219,9 +219,9 @@ export class CSSAdapter {
|
|
|
219
219
|
const findings = [];
|
|
220
220
|
pushNegativeMargins(el, findings);
|
|
221
221
|
pushInvisible(el, findings);
|
|
222
|
-
pushBlockers(el, findings);
|
|
222
|
+
pushBlockers(el, findings, true);
|
|
223
223
|
pushImage(el, findings);
|
|
224
|
-
pushStacking(el, findings);
|
|
224
|
+
pushStacking(el, findings, true);
|
|
225
225
|
pushImportant(el, built.rules, findings);
|
|
226
226
|
for (let j = 0; j < findings.length; j++) {
|
|
227
227
|
rows.push({ el, selector: cssPath(el), ...findings[j] });
|
|
@@ -755,7 +755,7 @@ function pushInvisible(el, findings) {
|
|
|
755
755
|
}
|
|
756
756
|
}
|
|
757
757
|
|
|
758
|
-
function pushBlockers(el, findings) {
|
|
758
|
+
function pushBlockers(el, findings, skipNoise = false) {
|
|
759
759
|
if (!el.getBoundingClientRect || typeof document.elementFromPoint !== 'function') return;
|
|
760
760
|
const rect = el.getBoundingClientRect();
|
|
761
761
|
const x = rect.left + rect.width / 2;
|
|
@@ -768,6 +768,7 @@ function pushBlockers(el, findings) {
|
|
|
768
768
|
const hit = document.elementFromPoint(x, y);
|
|
769
769
|
if (!hit || isBeeChrome(hit) || hit === el || el.contains(hit)) return;
|
|
770
770
|
if (pseudo && (hit === document.documentElement || hit === document.body)) return;
|
|
771
|
+
if (skipNoise && isReportNoise(hit)) return;
|
|
771
772
|
findings.push(issue(`click blocked by ${cssPath(hit)}`, ISSUE_RANK.blocker, 40));
|
|
772
773
|
}
|
|
773
774
|
|
|
@@ -950,7 +951,7 @@ function willChangeHint(value) {
|
|
|
950
951
|
return hit.join(', ');
|
|
951
952
|
}
|
|
952
953
|
|
|
953
|
-
function pushStacking(el, findings) {
|
|
954
|
+
function pushStacking(el, findings, skipNoise = false) {
|
|
954
955
|
if (!el || typeof getComputedStyle !== 'function' || !el.parentElement) return;
|
|
955
956
|
const own = getComputedStyle(el);
|
|
956
957
|
const ownZ = own.zIndex || own.getPropertyValue?.('z-index') || 'auto';
|
|
@@ -958,6 +959,7 @@ function pushStacking(el, findings) {
|
|
|
958
959
|
let node = el.parentElement;
|
|
959
960
|
while (node && node.nodeType === 1) {
|
|
960
961
|
if (isBeeChrome(node)) return;
|
|
962
|
+
if (skipNoise && isReportNoise(node)) return;
|
|
961
963
|
const found = stackingReasons(getComputedStyle(node));
|
|
962
964
|
const ancestor = cssPath(node);
|
|
963
965
|
if (found.bugs.length) {
|
|
@@ -190,7 +190,7 @@ export class CanvasAdapter {
|
|
|
190
190
|
severity: box.hit ? 'warn' : 'ok',
|
|
191
191
|
selector: box.name,
|
|
192
192
|
rule: 'hitbox',
|
|
193
|
-
value: `${box.x},${box.y} ${box.w}x${box.h}${box.hit ? ' colliding' : ''}`,
|
|
193
|
+
value: `${round1(box.x)},${round1(box.y)} ${round1(box.w)}x${round1(box.h)}${box.hit ? ' colliding' : ''}`,
|
|
194
194
|
source: this.source
|
|
195
195
|
}));
|
|
196
196
|
const fps = this.#fpsItem();
|
|
@@ -10,7 +10,7 @@ import { UIOverlay } from './UIOverlay.js';
|
|
|
10
10
|
import { buildAssistantSnapshot, normalizeAssistant } from './AiAssistant.js';
|
|
11
11
|
import { exportReport as writeReport } from './ReportExporter.js';
|
|
12
12
|
|
|
13
|
-
export const BEE_LADYBUG_VERSION = '0.6.
|
|
13
|
+
export const BEE_LADYBUG_VERSION = '0.6.1';
|
|
14
14
|
|
|
15
15
|
export const CORE_DEFAULTS = Object.freeze({
|
|
16
16
|
toggleKey: 'F2',
|
|
@@ -74,11 +74,19 @@ export function isReportNoise(node) {
|
|
|
74
74
|
while (current && typeof current === 'object') {
|
|
75
75
|
if (seen.has(current)) break;
|
|
76
76
|
seen.add(current);
|
|
77
|
-
if (current.id === 'wpadminbar') return true;
|
|
78
|
-
if (hasAbClass(current
|
|
77
|
+
if (current.id === 'wpadminbar' || elementId(current) === 'wpadminbar') return true;
|
|
78
|
+
if (hasAbClass(classText(current))) return true;
|
|
79
79
|
if (current.tagName === 'BEE-LADYBUG-OVERLAY') return true;
|
|
80
80
|
if (hasBeeAttribute(current)) return true;
|
|
81
|
-
|
|
81
|
+
if (typeof current.closest === 'function') {
|
|
82
|
+
try {
|
|
83
|
+
const bar = current.closest('#wpadminbar');
|
|
84
|
+
if (bar) return true;
|
|
85
|
+
} catch {
|
|
86
|
+
/* closest is optional */
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
current = current.parentElement || (current.parentNode && current.parentNode.nodeType === 1 ? current.parentNode : null);
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
const style = readStyle(el);
|
|
@@ -103,7 +111,7 @@ function buildReport(core) {
|
|
|
103
111
|
const series = readSeries(core);
|
|
104
112
|
const latest = readLatest(core);
|
|
105
113
|
const adapters = readAdapters(core);
|
|
106
|
-
const summary = countFindings(adapters);
|
|
114
|
+
const summary = countFindings(adapters, logs);
|
|
107
115
|
|
|
108
116
|
return {
|
|
109
117
|
version: state.version,
|
|
@@ -219,7 +227,7 @@ function readAdapters(core) {
|
|
|
219
227
|
const list = result && Array.isArray(result.items) ? result.items : [];
|
|
220
228
|
sections.push({
|
|
221
229
|
name,
|
|
222
|
-
items: list.filter((row) => row && typeof row === 'object').map((row) => makeItem(row, name))
|
|
230
|
+
items: groupIdentical(list.filter((row) => row && typeof row === 'object').map((row) => makeItem(row, name)))
|
|
223
231
|
});
|
|
224
232
|
}
|
|
225
233
|
return sections;
|
|
@@ -240,14 +248,45 @@ function makeItem(row, fallbackSource = '') {
|
|
|
240
248
|
};
|
|
241
249
|
}
|
|
242
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Identical selector + rule + value collapse to one row. The count is part of the value.
|
|
253
|
+
* @param {ReportItem[]} items
|
|
254
|
+
* @returns {ReportItem[]}
|
|
255
|
+
*/
|
|
256
|
+
function groupIdentical(items) {
|
|
257
|
+
const order = [];
|
|
258
|
+
const map = new Map();
|
|
259
|
+
for (let i = 0; i < items.length; i++) {
|
|
260
|
+
const item = items[i];
|
|
261
|
+
const key = `${item.selector}\0${item.rule}\0${item.value}`;
|
|
262
|
+
const prev = map.get(key);
|
|
263
|
+
if (!prev) {
|
|
264
|
+
const row = { ...item, count: 1 };
|
|
265
|
+
map.set(key, row);
|
|
266
|
+
order.push(row);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
prev.count += 1;
|
|
270
|
+
}
|
|
271
|
+
return order.map((row) => ({
|
|
272
|
+
severity: row.severity,
|
|
273
|
+
selector: row.selector,
|
|
274
|
+
rule: row.rule,
|
|
275
|
+
value: row.count > 1 ? `${row.value} ×${row.count}` : row.value,
|
|
276
|
+
source: row.source
|
|
277
|
+
}));
|
|
278
|
+
}
|
|
279
|
+
|
|
243
280
|
/**
|
|
244
281
|
* @param {Array<{ items: ReportItem[] }>} adapters
|
|
282
|
+
* @param {Array<{ type: string, level: string | null }>} logs
|
|
245
283
|
*/
|
|
246
|
-
function countFindings(adapters) {
|
|
284
|
+
function countFindings(adapters, logs) {
|
|
247
285
|
const summary = { error: 0, warn: 0, ok: 0 };
|
|
248
286
|
for (const section of adapters) {
|
|
249
287
|
for (const item of section.items) summary[item.severity] += 1;
|
|
250
288
|
}
|
|
289
|
+
for (let i = 0; i < logs.length; i++) summary[logSeverity(logs[i])] += 1;
|
|
251
290
|
return summary;
|
|
252
291
|
}
|
|
253
292
|
|
|
@@ -267,7 +306,7 @@ function normalizeFormat(format) {
|
|
|
267
306
|
function normalizeSeverity(value) {
|
|
268
307
|
const text = String(value || '').toLowerCase();
|
|
269
308
|
if (text === 'error') return 'error';
|
|
270
|
-
if (text === 'warn' || text === 'warning') return 'warn';
|
|
309
|
+
if (text === 'warn' || text === 'warning' || text === 'warm') return 'warn';
|
|
271
310
|
return 'ok';
|
|
272
311
|
}
|
|
273
312
|
|
|
@@ -332,8 +371,10 @@ function csvCell(value) {
|
|
|
332
371
|
* @returns {ReportSeverity}
|
|
333
372
|
*/
|
|
334
373
|
function logSeverity(log) {
|
|
335
|
-
|
|
336
|
-
if (
|
|
374
|
+
const level = String(log.level || '').toLowerCase();
|
|
375
|
+
if (level === 'warn' || level === 'warning' || level === 'warm') return 'warn';
|
|
376
|
+
if (level === 'error' || log.type === 'error') return 'error';
|
|
377
|
+
if (log.type === 'warn') return 'warn';
|
|
337
378
|
return 'ok';
|
|
338
379
|
}
|
|
339
380
|
|
|
@@ -490,11 +531,22 @@ function saveIfMounted(core, report, ext, mime, text) {
|
|
|
490
531
|
if (typeof document === 'undefined' || !document.body) return;
|
|
491
532
|
if (typeof URL === 'undefined' || typeof URL.createObjectURL !== 'function' || typeof Blob === 'undefined') return;
|
|
492
533
|
|
|
493
|
-
const
|
|
534
|
+
const filename = `report-${report.fileStamp}.${ext}`;
|
|
535
|
+
const type = `${mime};charset=utf-8`;
|
|
536
|
+
let blob;
|
|
537
|
+
try {
|
|
538
|
+
blob = typeof File === 'function'
|
|
539
|
+
? new File([text], filename, { type })
|
|
540
|
+
: new Blob([text], { type });
|
|
541
|
+
} catch {
|
|
542
|
+
if (typeof Blob !== 'function') return;
|
|
543
|
+
blob = new Blob([text], { type });
|
|
544
|
+
}
|
|
494
545
|
const url = URL.createObjectURL(blob);
|
|
495
546
|
const link = document.createElement('a');
|
|
496
547
|
link.href = url;
|
|
497
|
-
link.download =
|
|
548
|
+
link.download = filename;
|
|
549
|
+
link.setAttribute('download', filename);
|
|
498
550
|
link.rel = 'noopener';
|
|
499
551
|
document.body.appendChild(link);
|
|
500
552
|
link.click();
|
|
@@ -580,6 +632,34 @@ function escapeHtml(value) {
|
|
|
580
632
|
.replace(/"/g, '"');
|
|
581
633
|
}
|
|
582
634
|
|
|
635
|
+
function classText(node) {
|
|
636
|
+
if (!node || typeof node !== 'object') return '';
|
|
637
|
+
const parts = [];
|
|
638
|
+
if (typeof node.className === 'string' && node.className) parts.push(node.className);
|
|
639
|
+
else if (node.className && typeof node.className === 'object' && 'baseVal' in node.className && node.className.baseVal) {
|
|
640
|
+
parts.push(String(node.className.baseVal));
|
|
641
|
+
}
|
|
642
|
+
if (node.classList && typeof node.classList.length === 'number') {
|
|
643
|
+
try {
|
|
644
|
+
parts.push([...node.classList].join(' '));
|
|
645
|
+
} catch {
|
|
646
|
+
/* classList may not be iterable */
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if (typeof node.getAttribute === 'function') {
|
|
650
|
+
const attr = node.getAttribute('class');
|
|
651
|
+
if (attr) parts.push(attr);
|
|
652
|
+
}
|
|
653
|
+
return parts.join(' ');
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function elementId(node) {
|
|
657
|
+
if (!node || typeof node !== 'object') return '';
|
|
658
|
+
if (typeof node.id === 'string' && node.id) return node.id;
|
|
659
|
+
if (typeof node.getAttribute === 'function') return node.getAttribute('id') || '';
|
|
660
|
+
return '';
|
|
661
|
+
}
|
|
662
|
+
|
|
583
663
|
/**
|
|
584
664
|
* @param {unknown} className
|
|
585
665
|
*/
|