@hublo/sentinel 1.5.0-alpha.10 → 1.5.0-alpha.11

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.
@@ -15,7 +15,7 @@ import {
15
15
  palette,
16
16
  registerAdapters,
17
17
  resolve
18
- } from "../chunk-FWGU7QLH.js";
18
+ } from "../chunk-SXIZBKVJ.js";
19
19
  import {
20
20
  resolveContext
21
21
  } from "../chunk-KLEXJFJ6.js";
@@ -4864,6 +4864,8 @@ function helpFor(key) {
4864
4864
  }
4865
4865
 
4866
4866
  // src/roles/static-analysis/report.ts
4867
+ var SCRIPTS = { json: "static-analysis:json", html: "static-analysis:html" };
4868
+ var HTML_GROUP_LIMIT = 50;
4867
4869
  function shown(row) {
4868
4870
  return row.unit === "%" && typeof row.value === "number" ? row.value.toFixed(2) : String(row.value);
4869
4871
  }
@@ -4900,6 +4902,12 @@ function renderConsole(report) {
4900
4902
  }
4901
4903
  lines.push(" a language is absent when no file of it was long enough to scan");
4902
4904
  }
4905
+ if (report.findings.length > 0) {
4906
+ lines.push(
4907
+ "",
4908
+ ` ${report.findings.length} place(s) to look, listed by \`${SCRIPTS.json}\` and \`${SCRIPTS.html}\``
4909
+ );
4910
+ }
4903
4911
  const caveats = report.rows.map((row) => ({ row, help: helpFor(row.metric) })).filter(
4904
4912
  (entry) => Boolean(entry.help)
4905
4913
  );
@@ -4937,6 +4945,36 @@ function renderHtml(report) {
4937
4945
  <td>${setting.moved ? '<span class="moved">overridden in this module</span>' : ""}</td>
4938
4946
  </tr>`
4939
4947
  ).join("\n");
4948
+ const groups = /* @__PURE__ */ new Map();
4949
+ for (const finding of report.findings) {
4950
+ const bucket = groups.get(finding.metric) ?? [];
4951
+ bucket.push(finding);
4952
+ groups.set(finding.metric, bucket);
4953
+ }
4954
+ const findings = [...groups.entries()].map(([metric, all2]) => {
4955
+ const label = helpFor(metric)?.label ?? metric;
4956
+ const sorted = [...all2].sort((a, b) => (b.lines ?? 0) - (a.lines ?? 0));
4957
+ const shown2 = sorted.slice(0, HTML_GROUP_LIMIT);
4958
+ const rest = sorted.length - shown2.length;
4959
+ const rows2 = shown2.map(
4960
+ (finding) => ` <tr>
4961
+ <td><code>${escape(finding.path)}</code>${finding.other ? ` <span class="unit">and</span> <code>${escape(finding.other)}</code>` : ""}</td>
4962
+ <td>${finding.name ? `<code>${escape(finding.name)}</code>` : ""}</td>
4963
+ <td class="num">${finding.lines ?? ""}</td>
4964
+ <td class="num">${finding.confidence ?? ""}</td>
4965
+ </tr>`
4966
+ ).join("\n");
4967
+ return ` <h2>${escape(label)}: where to look</h2>
4968
+ <table>
4969
+ <thead>
4970
+ <tr><th scope="col">File</th><th scope="col">Name</th><th scope="col">Lines</th><th scope="col">Confidence</th></tr>
4971
+ </thead>
4972
+ <tbody>
4973
+ ${rows2}
4974
+ </tbody>
4975
+ </table>
4976
+ ${rest > 0 ? ` <p class="sub">The ${HTML_GROUP_LIMIT} longest are listed; ${rest} more are in <code>${SCRIPTS.json}</code>.</p>` : ""}`;
4977
+ }).join("\n");
4940
4978
  return `<!doctype html>
4941
4979
  <html lang="en">
4942
4980
  <head>
@@ -4985,6 +5023,7 @@ ${rows}
4985
5023
  ${settings}
4986
5024
  </tbody>
4987
5025
  </table>
5026
+ ${findings}
4988
5027
  </main>
4989
5028
  </body>
4990
5029
  </html>
@@ -5403,7 +5442,7 @@ ${result.stderr ?? ""}`
5403
5442
  const category = finding.category ?? "unknown";
5404
5443
  byCategory[category] = (byCategory[category] ?? 0) + 1;
5405
5444
  }
5406
- return { kind: "figures", statistics, byCategory };
5445
+ return { kind: "figures", statistics, byCategory, findings: parsed.findings ?? [] };
5407
5446
  } finally {
5408
5447
  dispose();
5409
5448
  }
@@ -5437,7 +5476,12 @@ ${result.stderr ?? ""}`
5437
5476
  );
5438
5477
  return { kind: "failed", code: 1 };
5439
5478
  }
5440
- return { kind: "figures", total, formats: parsed?.statistics?.formats ?? {} };
5479
+ return {
5480
+ kind: "figures",
5481
+ total,
5482
+ formats: parsed?.statistics?.formats ?? {},
5483
+ duplicates: parsed?.duplicates ?? []
5484
+ };
5441
5485
  } finally {
5442
5486
  dispose();
5443
5487
  }
@@ -5449,6 +5493,31 @@ function safeParse(text) {
5449
5493
  return void 0;
5450
5494
  }
5451
5495
  }
5496
+ function placesToLook(product, tests, dead) {
5497
+ const clones = (outcome, metric) => outcome.kind === "figures" ? outcome.duplicates.map((entry) => ({
5498
+ metric,
5499
+ path: entry.firstFile?.name ?? "(unknown)",
5500
+ other: entry.secondFile?.name,
5501
+ lines: entry.lines
5502
+ })) : [];
5503
+ const deadMetric = {
5504
+ "unused-file": "unusedFiles",
5505
+ "unused-export": "unusedExports",
5506
+ "unused-symbol": "unusedSymbols",
5507
+ "unused-import": "unusedImports"
5508
+ };
5509
+ return [
5510
+ ...clones(product, "clones"),
5511
+ ...clones(tests, "clonesTests"),
5512
+ ...dead.kind === "figures" ? dead.findings.map((finding) => ({
5513
+ metric: deadMetric[finding.category ?? ""] ?? "deadLinesPercent",
5514
+ path: finding.path ?? "(unknown)",
5515
+ ...finding.name ? { name: finding.name } : {},
5516
+ ...finding.lines === void 0 ? {} : { lines: finding.lines },
5517
+ ...finding.confidence === void 0 ? {} : { confidence: finding.confidence }
5518
+ })) : []
5519
+ ];
5520
+ }
5452
5521
  function assemble(ctx, config, product, tests, dead) {
5453
5522
  const share = (total) => Number((total.percentage ?? 0).toFixed(2));
5454
5523
  const rows = [
@@ -5508,6 +5577,7 @@ function assemble(ctx, config, product, tests, dead) {
5508
5577
  rows,
5509
5578
  notes,
5510
5579
  settings: duplicationSettings(config),
5580
+ findings: placesToLook(product, tests, dead),
5511
5581
  byLanguage
5512
5582
  };
5513
5583
  }
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  registerAdapters,
7
7
  resolve,
8
8
  setDefaultRunner
9
- } from "./chunk-FWGU7QLH.js";
9
+ } from "./chunk-SXIZBKVJ.js";
10
10
  import {
11
11
  BaseAdapter
12
12
  } from "./chunk-KLEXJFJ6.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hublo/sentinel",
3
- "version": "1.5.0-alpha.10",
3
+ "version": "1.5.0-alpha.11",
4
4
  "description": "One CLI that guards code health across Hublo repos: shared lint/typescript/build/test presets, static & dynamic analysis, and architecture checks.",
5
5
  "type": "module",
6
6
  "license": "MIT",