vue3-migration 1.4.3 → 1.4.4
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
|
@@ -184,9 +184,33 @@ def write_diff_report(plan: MigrationPlan, project_root: Path) -> Path:
|
|
|
184
184
|
except ValueError:
|
|
185
185
|
return str(path)
|
|
186
186
|
|
|
187
|
+
# Count totals for header
|
|
188
|
+
all_changes = [c for c in (plan.composable_changes + plan.component_changes) if c.has_changes]
|
|
189
|
+
_header_parts = [f"{len(all_changes)} file{'s' if len(all_changes) != 1 else ''}"]
|
|
190
|
+
if plan.entries_by_component:
|
|
191
|
+
_seen: set[str] = set()
|
|
192
|
+
_all_w = []
|
|
193
|
+
for _cp2, _el2 in plan.entries_by_component:
|
|
194
|
+
for _e2 in _el2:
|
|
195
|
+
if _e2.mixin_stem not in _seen:
|
|
196
|
+
_seen.add(_e2.mixin_stem)
|
|
197
|
+
_all_w.extend(_e2.warnings)
|
|
198
|
+
_ec = sum(1 for w in _all_w if w.severity == "error")
|
|
199
|
+
_wc = sum(1 for w in _all_w if w.severity == "warning")
|
|
200
|
+
_ic = sum(1 for w in _all_w if w.severity == "info")
|
|
201
|
+
if _ec:
|
|
202
|
+
_header_parts.append(f"{_ec} error{'s' if _ec != 1 else ''}")
|
|
203
|
+
if _wc:
|
|
204
|
+
_header_parts.append(f"{_wc} warning{'s' if _wc != 1 else ''}")
|
|
205
|
+
if _ic:
|
|
206
|
+
_header_parts.append(f"{_ic} info")
|
|
207
|
+
|
|
187
208
|
sections: list[str] = [
|
|
188
209
|
"# Migration Diff Report",
|
|
189
|
-
|
|
210
|
+
"",
|
|
211
|
+
f"`{now.strftime('%Y-%m-%d %H:%M:%S')}` \u2014 {' \u00b7 '.join(_header_parts)}",
|
|
212
|
+
"",
|
|
213
|
+
"---",
|
|
190
214
|
"",
|
|
191
215
|
]
|
|
192
216
|
|
|
@@ -221,7 +245,7 @@ def write_diff_report(plan: MigrationPlan, project_root: Path) -> Path:
|
|
|
221
245
|
else:
|
|
222
246
|
confidence_map[entry.mixin_stem] = ConfidenceLevel.HIGH
|
|
223
247
|
|
|
224
|
-
summary = build_warning_summary(plan.entries_by_component, plan.composable_changes)
|
|
248
|
+
summary = build_warning_summary(plan.entries_by_component, plan.composable_changes, project_root)
|
|
225
249
|
if summary:
|
|
226
250
|
sections.append(summary)
|
|
227
251
|
sections.append("")
|
|
@@ -235,8 +259,6 @@ def write_diff_report(plan: MigrationPlan, project_root: Path) -> Path:
|
|
|
235
259
|
sections.append("")
|
|
236
260
|
|
|
237
261
|
# Diffs
|
|
238
|
-
all_changes = [c for c in (plan.composable_changes + plan.component_changes) if c.has_changes]
|
|
239
|
-
|
|
240
262
|
for change in all_changes:
|
|
241
263
|
rel = _rel(change.file_path)
|
|
242
264
|
sections.append(f"## `{rel}`")
|
|
@@ -13,6 +13,23 @@ _SKIPPED_CATEGORIES = frozenset({
|
|
|
13
13
|
"skipped-no-usage",
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
+
_CONF_DOT = {
|
|
17
|
+
ConfidenceLevel.LOW: "\U0001f534", # red dot
|
|
18
|
+
ConfidenceLevel.MEDIUM: "\U0001f7e1", # yellow dot
|
|
19
|
+
ConfidenceLevel.HIGH: "\U0001f7e2", # green dot
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _rel_link(path: "Path | str", project_root: Path, label: str | None = None) -> str:
|
|
24
|
+
"""Return a markdown hyperlink with a relative path."""
|
|
25
|
+
p = Path(path) if not isinstance(path, Path) else path
|
|
26
|
+
try:
|
|
27
|
+
rel = p.relative_to(project_root)
|
|
28
|
+
except ValueError:
|
|
29
|
+
rel = p
|
|
30
|
+
display = label or rel.name
|
|
31
|
+
return f"[`{display}`]({str(rel).replace(chr(92), '/')})"
|
|
32
|
+
|
|
16
33
|
|
|
17
34
|
def build_component_report(
|
|
18
35
|
component_path: Path,
|
|
@@ -20,23 +37,30 @@ def build_component_report(
|
|
|
20
37
|
project_root: Path,
|
|
21
38
|
) -> str:
|
|
22
39
|
"""Build a markdown migration report for a single component."""
|
|
40
|
+
from datetime import datetime
|
|
41
|
+
|
|
23
42
|
lines: list[str] = []
|
|
24
43
|
w = lines.append
|
|
25
44
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
45
|
+
ready_count = sum(
|
|
46
|
+
1 for e in mixin_entries
|
|
47
|
+
if not e.used_members or (e.classification and e.classification.is_ready)
|
|
48
|
+
)
|
|
49
|
+
blocked_count = len(mixin_entries) - ready_count
|
|
30
50
|
|
|
31
|
-
w(f"# Migration Report: {
|
|
51
|
+
w(f"# Migration Report: {_rel_link(component_path, project_root)}\n")
|
|
52
|
+
parts = [f"{len(mixin_entries)} mixin{'s' if len(mixin_entries) != 1 else ''}"]
|
|
53
|
+
parts.append(f"{ready_count} ready")
|
|
54
|
+
parts.append(f"{blocked_count} blocked")
|
|
55
|
+
w(f"`{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}` \u2014 {' \u00b7 '.join(parts)}\n")
|
|
56
|
+
w("---\n")
|
|
32
57
|
|
|
33
58
|
ready_entries = []
|
|
34
59
|
blocked_entries = []
|
|
35
60
|
|
|
36
61
|
for entry in mixin_entries:
|
|
37
62
|
mixin_name = entry.mixin_stem
|
|
38
|
-
w(f"## Mixin: {mixin_name}\n")
|
|
39
|
-
w(f"**File:** {md_green(str(entry.mixin_path))}\n")
|
|
63
|
+
w(f"## Mixin: {_rel_link(entry.mixin_path, project_root, mixin_name)}\n")
|
|
40
64
|
|
|
41
65
|
# Members breakdown
|
|
42
66
|
for section in ("data", "computed", "methods"):
|
|
@@ -64,7 +88,7 @@ def build_component_report(
|
|
|
64
88
|
w(f"**Composable:** {md_yellow('NOT FOUND')}\n")
|
|
65
89
|
blocked_entries.append(entry)
|
|
66
90
|
else:
|
|
67
|
-
w(f"**Composable:** {
|
|
91
|
+
w(f"**Composable:** {_rel_link(comp.file_path, project_root)}")
|
|
68
92
|
w(f"**Function:** `{comp.fn_name}`")
|
|
69
93
|
w(f"**Import path:** `{comp.import_path}`")
|
|
70
94
|
w(f"> {md_yellow('Verify the above path and function name are correct.')}\n")
|
|
@@ -125,7 +149,7 @@ def build_component_report(
|
|
|
125
149
|
w(f"- Add to composable: {', '.join(cls.missing)}")
|
|
126
150
|
if cls and cls.not_returned:
|
|
127
151
|
w(f"- Add to return statement: {', '.join(cls.not_returned)}")
|
|
128
|
-
w(f"- File: {
|
|
152
|
+
w(f"- File: {_rel_link(comp.file_path, project_root)}\n")
|
|
129
153
|
|
|
130
154
|
if ready_entries:
|
|
131
155
|
w("### Ready for injection")
|
|
@@ -233,19 +257,18 @@ def generate_status_report(project_root: Path, config) -> str:
|
|
|
233
257
|
needs_manual_count = sum(1 for c in components_info if c["has_manual"])
|
|
234
258
|
blocked = len(components_info) - ready - needs_manual_count
|
|
235
259
|
|
|
260
|
+
header_parts = [f"{len(components_info)} component{'s' if len(components_info) != 1 else ''}"]
|
|
261
|
+
header_parts.append(f"{ready} ready")
|
|
262
|
+
if needs_manual_count:
|
|
263
|
+
header_parts.append(f"{needs_manual_count} manual")
|
|
264
|
+
header_parts.append(f"{blocked} blocked")
|
|
265
|
+
|
|
236
266
|
lines: list[str] = [
|
|
237
267
|
"# Vue Migration Status Report",
|
|
238
|
-
f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
|
|
239
268
|
"",
|
|
240
|
-
"
|
|
269
|
+
f"`{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}` \u2014 {' \u00b7 '.join(header_parts)}",
|
|
241
270
|
"",
|
|
242
|
-
|
|
243
|
-
f"- Ready to migrate now: **{ready}**",
|
|
244
|
-
]
|
|
245
|
-
if needs_manual_count:
|
|
246
|
-
lines.append(f"- Needs manual migration: **{needs_manual_count}**")
|
|
247
|
-
lines.extend([
|
|
248
|
-
f"- Blocked (composable missing or incomplete): **{blocked}**",
|
|
271
|
+
"---",
|
|
249
272
|
"",
|
|
250
273
|
"> Run `vue3-migration auto` to generate a detailed diff report with warnings, per-component guide, and checklist.",
|
|
251
274
|
"",
|
|
@@ -253,7 +276,7 @@ def generate_status_report(project_root: Path, config) -> str:
|
|
|
253
276
|
"",
|
|
254
277
|
"| Mixin | Used in | Composable |",
|
|
255
278
|
"|-------|---------|------------|",
|
|
256
|
-
]
|
|
279
|
+
]
|
|
257
280
|
|
|
258
281
|
for stem, count in mixin_counter.most_common():
|
|
259
282
|
has_comp = mixin_has_composable(stem, composable_stems)
|
|
@@ -283,7 +306,7 @@ def generate_status_report(project_root: Path, config) -> str:
|
|
|
283
306
|
missing = comp["total"] - comp["covered"] - comp["needs_manual"]
|
|
284
307
|
status_str = f"**Blocked** -- {missing} composable(s) missing or incomplete"
|
|
285
308
|
|
|
286
|
-
lines.append(f"### `{comp['rel_path']}`")
|
|
309
|
+
lines.append(f"### [`{comp['rel_path']}`]({str(comp['rel_path']).replace(chr(92), '/')})")
|
|
287
310
|
lines.append(f"- Mixins: {', '.join(f'`{s}`' for s in comp['stems'])}")
|
|
288
311
|
lines.append(f"- Status: {status_str}")
|
|
289
312
|
lines.append("")
|
|
@@ -305,10 +328,19 @@ def build_audit_report(
|
|
|
305
328
|
warnings: list[MigrationWarning] | None = None,
|
|
306
329
|
) -> str:
|
|
307
330
|
"""Build a markdown audit report for a single mixin."""
|
|
331
|
+
from datetime import datetime
|
|
332
|
+
|
|
308
333
|
lines: list[str] = []
|
|
309
334
|
w = lines.append
|
|
310
335
|
|
|
311
|
-
|
|
336
|
+
total_members = len(all_member_names)
|
|
337
|
+
header_parts = [f"{total_members} member{'s' if total_members != 1 else ''}"]
|
|
338
|
+
header_parts.append(f"{len(lifecycle_hooks)} hook{'s' if len(lifecycle_hooks) != 1 else ''}")
|
|
339
|
+
header_parts.append(f"{len(importing_files)} file{'s' if len(importing_files) != 1 else ''}")
|
|
340
|
+
|
|
341
|
+
w(f"# Mixin Audit: {_rel_link(mixin_path, project_root, mixin_path.name)}\n")
|
|
342
|
+
w(f"`{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}` \u2014 {' \u00b7 '.join(header_parts)}\n")
|
|
343
|
+
w("---\n")
|
|
312
344
|
|
|
313
345
|
w("## Mixin Members\n")
|
|
314
346
|
for section in ("data", "computed", "methods"):
|
|
@@ -328,7 +360,7 @@ def build_audit_report(
|
|
|
328
360
|
for file_path in sorted(importing_files):
|
|
329
361
|
relative_path = file_path.relative_to(project_root)
|
|
330
362
|
used = usage_map.get(str(relative_path), [])
|
|
331
|
-
w(f"### {relative_path}\n")
|
|
363
|
+
w(f"### {_rel_link(file_path, project_root, str(relative_path))}\n")
|
|
332
364
|
if used:
|
|
333
365
|
w(f"Uses: {', '.join(used)}\n")
|
|
334
366
|
else:
|
|
@@ -379,18 +411,12 @@ def build_per_component_index(
|
|
|
379
411
|
if not entries_by_component:
|
|
380
412
|
return ""
|
|
381
413
|
|
|
382
|
-
_CONF_ICON = {ConfidenceLevel.LOW: "\u274c", ConfidenceLevel.MEDIUM: "\u26a0\ufe0f", ConfidenceLevel.HIGH: "\u2705"}
|
|
383
|
-
|
|
384
414
|
lines: list[str] = []
|
|
385
415
|
a = lines.append
|
|
386
416
|
a("## Per-Component Guide\n")
|
|
387
417
|
|
|
388
418
|
for comp_path, entry_list in entries_by_component:
|
|
389
|
-
|
|
390
|
-
comp_rel = comp_path.relative_to(project_root)
|
|
391
|
-
except ValueError:
|
|
392
|
-
comp_rel = comp_path
|
|
393
|
-
a(f"### {comp_rel.name}\n")
|
|
419
|
+
a(f"### {_rel_link(comp_path, project_root)}\n")
|
|
394
420
|
|
|
395
421
|
for entry in entry_list:
|
|
396
422
|
entry_cats = {w.category for w in entry.warnings}
|
|
@@ -401,9 +427,10 @@ def build_per_component_index(
|
|
|
401
427
|
a(f"- \u2139\ufe0f **{entry.mixin_stem}** skipped \u2014 {reason}")
|
|
402
428
|
elif entry.composable:
|
|
403
429
|
conf = confidence_map.get(entry.mixin_stem, ConfidenceLevel.HIGH)
|
|
404
|
-
|
|
430
|
+
dot = _CONF_DOT.get(conf, "\u2753")
|
|
405
431
|
error_count = sum(1 for w in entry.warnings if w.severity == "error")
|
|
406
432
|
warn_count = sum(1 for w in entry.warnings if w.severity == "warning")
|
|
433
|
+
comp_link = _rel_link(entry.composable.file_path, project_root, entry.composable.fn_name)
|
|
407
434
|
if error_count or warn_count:
|
|
408
435
|
parts = []
|
|
409
436
|
if error_count:
|
|
@@ -411,11 +438,11 @@ def build_per_component_index(
|
|
|
411
438
|
if warn_count:
|
|
412
439
|
parts.append(f"{warn_count} warning{'s' if warn_count != 1 else ''}")
|
|
413
440
|
detail = ", ".join(parts)
|
|
414
|
-
a(f"- {
|
|
441
|
+
a(f"- {dot} {comp_link} \u2014 {detail} \u2192 [See warnings](#{entry.mixin_stem})")
|
|
415
442
|
else:
|
|
416
|
-
a(f"- {
|
|
443
|
+
a(f"- {dot} {comp_link} \u2014 No issues")
|
|
417
444
|
else:
|
|
418
|
-
a(f"- \
|
|
445
|
+
a(f"- \U0001f534 **{entry.mixin_stem}** \u2014 composable not found")
|
|
419
446
|
|
|
420
447
|
a("")
|
|
421
448
|
|
|
@@ -508,6 +535,7 @@ def build_checklist(
|
|
|
508
535
|
def build_warning_summary(
|
|
509
536
|
entries_by_component: "list[tuple[Path, list[MixinEntry]]]",
|
|
510
537
|
composable_changes: "list[FileChange] | None" = None,
|
|
538
|
+
project_root: "Path | None" = None,
|
|
511
539
|
) -> str:
|
|
512
540
|
"""Build a markdown Migration Summary checklist for the diff report.
|
|
513
541
|
|
|
@@ -517,34 +545,51 @@ def build_warning_summary(
|
|
|
517
545
|
"""
|
|
518
546
|
from ..core.warning_collector import compute_confidence
|
|
519
547
|
|
|
520
|
-
#
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
548
|
+
# Group entries by mixin_stem, tracking component paths and warnings
|
|
549
|
+
from collections import OrderedDict
|
|
550
|
+
|
|
551
|
+
# Collect per-mixin: representative entry + all (comp_path, warning) pairs
|
|
552
|
+
_MixinGroup = tuple[MixinEntry, list[tuple[Path, MigrationWarning]]]
|
|
553
|
+
mixin_groups: OrderedDict[str, _MixinGroup] = OrderedDict()
|
|
554
|
+
|
|
555
|
+
for comp_path, entry_list in entries_by_component:
|
|
524
556
|
for entry in entry_list:
|
|
525
|
-
if entry.mixin_stem not in
|
|
526
|
-
|
|
527
|
-
|
|
557
|
+
if entry.mixin_stem not in mixin_groups:
|
|
558
|
+
mixin_groups[entry.mixin_stem] = (entry, [])
|
|
559
|
+
group_entry, group_warnings = mixin_groups[entry.mixin_stem]
|
|
560
|
+
for w in entry.warnings:
|
|
561
|
+
group_warnings.append((comp_path, w))
|
|
528
562
|
|
|
529
|
-
if not
|
|
563
|
+
if not mixin_groups:
|
|
530
564
|
return ""
|
|
531
565
|
|
|
532
566
|
# Separate skipped entries from active entries
|
|
533
567
|
skipped_rows: list[tuple[str, str, str]] = [] # (component, mixin, reason)
|
|
534
568
|
active_entries: list[MixinEntry] = []
|
|
569
|
+
# Map mixin_stem -> de-duped (comp_path, warning) pairs
|
|
570
|
+
active_warnings: dict[str, list[tuple[Path, MigrationWarning]]] = {}
|
|
535
571
|
|
|
536
|
-
for entry in
|
|
572
|
+
for stem, (entry, comp_warnings) in mixin_groups.items():
|
|
537
573
|
entry_cats = {w.category for w in entry.warnings}
|
|
538
574
|
if entry_cats and entry_cats <= _SKIPPED_CATEGORIES:
|
|
539
|
-
# Find which component(s) this mixin was used in
|
|
540
575
|
for comp_path, entry_list in entries_by_component:
|
|
541
576
|
for e in entry_list:
|
|
542
|
-
if e.mixin_stem ==
|
|
577
|
+
if e.mixin_stem == stem:
|
|
543
578
|
reason = entry.warnings[0].message.split(":", 1)[-1].strip() if entry.warnings else "unknown"
|
|
544
|
-
|
|
545
|
-
skipped_rows.append((comp_name, entry.mixin_stem, reason))
|
|
579
|
+
skipped_rows.append((comp_path.name, stem, reason))
|
|
546
580
|
else:
|
|
547
581
|
active_entries.append(entry)
|
|
582
|
+
# De-dup warnings by (category, message, severity) but keep component paths
|
|
583
|
+
seen_w: dict[tuple[str, str, str], list[Path]] = {}
|
|
584
|
+
deduped: list[tuple[Path, MigrationWarning]] = []
|
|
585
|
+
for cp, w in comp_warnings:
|
|
586
|
+
key = (w.category, w.message, w.severity)
|
|
587
|
+
if key not in seen_w:
|
|
588
|
+
seen_w[key] = []
|
|
589
|
+
deduped.append((cp, w))
|
|
590
|
+
if cp not in seen_w[key]:
|
|
591
|
+
seen_w[key].append(cp)
|
|
592
|
+
active_warnings[stem] = deduped
|
|
548
593
|
|
|
549
594
|
# Build a lookup of composable content by file path
|
|
550
595
|
composable_content_map: dict[Path, str] = {}
|
|
@@ -575,8 +620,8 @@ def build_warning_summary(
|
|
|
575
620
|
if not active_entries and not skipped_rows:
|
|
576
621
|
return ""
|
|
577
622
|
|
|
578
|
-
# Count totals
|
|
579
|
-
all_warnings = [w for
|
|
623
|
+
# Count totals (from de-duped warnings)
|
|
624
|
+
all_warnings = [w for stem in active_warnings for _cp, w in active_warnings[stem]]
|
|
580
625
|
error_count = sum(1 for w in all_warnings if w.severity == "error")
|
|
581
626
|
warning_count = sum(1 for w in all_warnings if w.severity == "warning")
|
|
582
627
|
info_count = sum(1 for w in all_warnings if w.severity == "info")
|
|
@@ -588,28 +633,42 @@ def build_warning_summary(
|
|
|
588
633
|
|
|
589
634
|
# Overview line
|
|
590
635
|
total_count = len(active_entries) + len(skipped_rows)
|
|
591
|
-
parts = [f"
|
|
636
|
+
parts = [f"{total_count} composable{'s' if total_count != 1 else ''}"]
|
|
592
637
|
if error_count:
|
|
593
638
|
parts.append(f"{error_count} error{'s' if error_count != 1 else ''}")
|
|
594
639
|
if warning_count:
|
|
595
640
|
parts.append(f"{warning_count} warning{'s' if warning_count != 1 else ''}")
|
|
596
641
|
if info_count:
|
|
597
642
|
parts.append(f"{info_count} info")
|
|
598
|
-
a("
|
|
643
|
+
a(" \u00b7 ".join(parts))
|
|
599
644
|
a("")
|
|
600
645
|
a("---\n")
|
|
601
646
|
|
|
602
647
|
# Per-mixin sections
|
|
603
|
-
_SEVERITY_ICON = {"error": "\u274c", "warning": "\u26a0\ufe0f", "info": "\u2139\ufe0f"}
|
|
604
|
-
_CONF_ICON = {ConfidenceLevel.LOW: "\u274c", ConfidenceLevel.MEDIUM: "\u26a0\ufe0f", ConfidenceLevel.HIGH: "\u2705"}
|
|
605
|
-
|
|
606
648
|
for entry in active_entries:
|
|
607
649
|
conf = confidence_map[entry.mixin_stem]
|
|
608
|
-
|
|
650
|
+
dot = _CONF_DOT.get(conf, "\u2753")
|
|
609
651
|
|
|
610
|
-
|
|
652
|
+
# Build heading: dot mixin_link → composable_link · (CONFIDENCE)
|
|
653
|
+
if project_root:
|
|
654
|
+
mixin_link = _rel_link(entry.mixin_path, project_root, entry.mixin_stem)
|
|
655
|
+
else:
|
|
656
|
+
mixin_link = f"`{entry.mixin_stem}`"
|
|
657
|
+
|
|
658
|
+
if entry.composable:
|
|
659
|
+
if project_root:
|
|
660
|
+
comp_link = _rel_link(entry.composable.file_path, project_root, entry.composable.fn_name)
|
|
661
|
+
else:
|
|
662
|
+
comp_link = f"`{entry.composable.fn_name}`"
|
|
663
|
+
heading = f"{dot} {mixin_link} \u2192 {comp_link} \u00b7 ({conf.value})"
|
|
664
|
+
else:
|
|
665
|
+
heading = f"{dot} {mixin_link} \u00b7 ({conf.value})"
|
|
611
666
|
|
|
612
|
-
|
|
667
|
+
a(f"<a id=\"{entry.mixin_stem}\"></a>\n")
|
|
668
|
+
a(f"### {heading}\n")
|
|
669
|
+
|
|
670
|
+
entry_w = active_warnings.get(entry.mixin_stem, [])
|
|
671
|
+
if not entry_w:
|
|
613
672
|
# Only say "No manual changes needed" if the composable is truly clean
|
|
614
673
|
comp_source = ""
|
|
615
674
|
if entry.composable and entry.composable.file_path in composable_content_map:
|
|
@@ -625,14 +684,23 @@ def build_warning_summary(
|
|
|
625
684
|
a("Review generated composable for any remaining migration markers.\n")
|
|
626
685
|
continue
|
|
627
686
|
|
|
628
|
-
|
|
629
|
-
|
|
687
|
+
# Determine how many unique components use this mixin
|
|
688
|
+
all_comps_for_mixin = set()
|
|
689
|
+
for cp, el in entries_by_component:
|
|
690
|
+
for e in el:
|
|
691
|
+
if e.mixin_stem == entry.mixin_stem:
|
|
692
|
+
all_comps_for_mixin.add(cp)
|
|
630
693
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
694
|
+
a("| Severity | Issue | Fix |")
|
|
695
|
+
a("|---|---|---|")
|
|
696
|
+
for comp_path, warning in entry_w:
|
|
697
|
+
# Show component name when there are multiple components or when it adds context
|
|
698
|
+
if project_root and len(all_comps_for_mixin) >= 1:
|
|
699
|
+
comp_name = _rel_link(comp_path, project_root)
|
|
700
|
+
a(f"| {warning.severity} | {comp_name}: {warning.message} | {warning.action_required} |")
|
|
701
|
+
else:
|
|
702
|
+
a(f"| {warning.severity} | {warning.message} | {warning.action_required} |")
|
|
703
|
+
a("")
|
|
636
704
|
|
|
637
705
|
# Skipped mixins table
|
|
638
706
|
if skipped_rows:
|