@cms-lab/reporter 1.2.1 → 1.2.3
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/README.md +10 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +30 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,6 +9,16 @@ import { renderHtmlReport } from "@cms-lab/reporter";
|
|
|
9
9
|
The CLI uses this package for `cms-lab scan --report`. The generated report is a
|
|
10
10
|
self-contained HTML file with grouped diagnostics and client-side filters.
|
|
11
11
|
|
|
12
|
+
Use the share privacy mode when rendering a report that may be attached to a
|
|
13
|
+
public issue:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
renderHtmlReport(result, { privacy: "share" });
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Share-safe reports keep diagnostic codes, severity, route paths, and field paths
|
|
20
|
+
visible, but redact CMS source IDs and local project paths.
|
|
21
|
+
|
|
12
22
|
## Release History
|
|
13
23
|
|
|
14
24
|
See the repository [changelog](https://github.com/i-afaqrashid/cms-lab/blob/main/CHANGELOG.md)
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ type ReporterStatus = {
|
|
|
5
5
|
format: "html";
|
|
6
6
|
};
|
|
7
7
|
declare function getReporterStatus(): ReporterStatus;
|
|
8
|
-
|
|
8
|
+
type HtmlReportPrivacy = "full" | "share";
|
|
9
|
+
type HtmlReportOptions = {
|
|
10
|
+
privacy?: HtmlReportPrivacy;
|
|
11
|
+
};
|
|
12
|
+
declare function renderHtmlReport(result: ScanResult, options?: HtmlReportOptions): string;
|
|
9
13
|
|
|
10
|
-
export { type ReporterStatus, getReporterStatus, renderHtmlReport };
|
|
14
|
+
export { type HtmlReportOptions, type HtmlReportPrivacy, type ReporterStatus, getReporterStatus, renderHtmlReport };
|
package/dist/index.js
CHANGED
|
@@ -18,9 +18,10 @@ function getReporterStatus() {
|
|
|
18
18
|
format: "html"
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
function renderHtmlReport(result) {
|
|
21
|
+
function renderHtmlReport(result, options = {}) {
|
|
22
22
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23
23
|
const diagnostics = result.diagnostics;
|
|
24
|
+
const privacy = options.privacy ?? "full";
|
|
24
25
|
const status = result.summary.errors > 0 ? "failed" : "passed";
|
|
25
26
|
const statusClass = result.summary.errors > 0 ? "fail" : result.summary.warnings > 0 ? "warn" : "ok";
|
|
26
27
|
const grouped = groupDiagnostics(diagnostics);
|
|
@@ -411,6 +412,7 @@ function renderHtmlReport(result) {
|
|
|
411
412
|
<span class="badge ${statusClass}">${escapeHtml(statusLabel(result))}</span>
|
|
412
413
|
${result.summary.warnings > 0 ? `<span class="badge warn">${result.summary.warnings} ${escapeHtml(plural(result.summary.warnings, "warning"))}</span>` : ""}
|
|
413
414
|
${result.summary.info > 0 ? `<span class="badge info">${result.summary.info} ${escapeHtml(plural(result.summary.info, "info item"))}</span>` : ""}
|
|
415
|
+
${privacy === "share" ? `<span class="badge">Share-safe report</span>` : ""}
|
|
414
416
|
</div>
|
|
415
417
|
<div class="subtitle">
|
|
416
418
|
${escapeHtml(projectLabel(result))} \xB7 ${result.documents.length} ${escapeHtml(plural(result.documents.length, "document"))}
|
|
@@ -436,7 +438,7 @@ function renderHtmlReport(result) {
|
|
|
436
438
|
${grouped.map((group) => `<button class="chip" type="button" data-filter-kind="group" data-filter-value="${escapeHtml(group.label)}">${escapeHtml(group.label)} <span class="n">${group.diagnostics.length}</span></button>`).join("")}
|
|
437
439
|
</div>
|
|
438
440
|
|
|
439
|
-
${diagnostics.length === 0 ? `<div class="empty-state">No diagnostics found.</div>` : grouped.map((group) => diagnosticsGroup(group)).join("")}
|
|
441
|
+
${diagnostics.length === 0 ? `<div class="empty-state">No diagnostics found.</div>` : grouped.map((group) => diagnosticsGroup(group, result, privacy)).join("")}
|
|
440
442
|
|
|
441
443
|
<div class="report-foot">
|
|
442
444
|
<span>project: <span class="path-code">${escapeHtml(result.project.framework)} ${escapeHtml(result.project.router)}</span></span>
|
|
@@ -542,24 +544,45 @@ function groupForDiagnostic(diagnostic) {
|
|
|
542
544
|
}
|
|
543
545
|
return "other";
|
|
544
546
|
}
|
|
545
|
-
function diagnosticsGroup(group) {
|
|
547
|
+
function diagnosticsGroup(group, result, privacy) {
|
|
546
548
|
return `<section class="diagnostic-group" data-diagnostic-group="${escapeHtml(group.label)}">
|
|
547
549
|
<div class="group-header">
|
|
548
550
|
<span>${escapeHtml(group.label)}</span> \xB7 <span class="count" data-visible-count>${group.diagnostics.length} ${escapeHtml(plural(group.diagnostics.length, "diagnostic"))}</span>
|
|
549
551
|
</div>
|
|
550
|
-
${group.diagnostics.map((diagnostic, index) => diagnosticRow(diagnostic, group.label, index + 1)).join("")}
|
|
552
|
+
${group.diagnostics.map((diagnostic, index) => diagnosticRow(diagnostic, group.label, index + 1, result, privacy)).join("")}
|
|
551
553
|
</section>`;
|
|
552
554
|
}
|
|
553
|
-
function diagnosticRow(diagnostic, group, index) {
|
|
555
|
+
function diagnosticRow(diagnostic, group, index, result, privacy) {
|
|
556
|
+
const path = diagnostic.path ? redactReportValue(diagnostic.path, result, privacy) : void 0;
|
|
557
|
+
const message = redactReportValue(diagnostic.message, result, privacy);
|
|
558
|
+
const source = privacy === "share" ? diagnostic.source ? "[redacted CMS source]" : void 0 : diagnostic.source;
|
|
554
559
|
return `<div class="diag ${escapeHtml(diagnostic.severity)}" data-diagnostic data-group="${escapeHtml(group)}" data-severity="${escapeHtml(diagnostic.severity)}">
|
|
555
560
|
<div class="col-num">${index}</div>
|
|
556
561
|
<div class="sev"><span class="marker"></span>${escapeHtml(diagnostic.severity)}</div>
|
|
557
562
|
<div class="msg">
|
|
558
|
-
${
|
|
559
|
-
<span class="ctx"><span class="diag-code">${escapeHtml(diagnostic.code)}</span>${
|
|
563
|
+
${path ? `<strong>${escapeHtml(path)}</strong> ` : ""}${escapeHtml(message)}
|
|
564
|
+
<span class="ctx"><span class="diag-code">${escapeHtml(diagnostic.code)}</span>${source ? ` <span aria-hidden="true">\xB7</span> <span>${escapeHtml(source)}</span>` : ""}</span>
|
|
560
565
|
</div>
|
|
561
566
|
</div>`;
|
|
562
567
|
}
|
|
568
|
+
function redactReportValue(value, result, privacy) {
|
|
569
|
+
if (privacy !== "share") {
|
|
570
|
+
return value;
|
|
571
|
+
}
|
|
572
|
+
let redacted = value;
|
|
573
|
+
const projectPaths = [
|
|
574
|
+
result.project.appDir,
|
|
575
|
+
result.project.pagesDir,
|
|
576
|
+
result.project.rootDir
|
|
577
|
+
].filter((path) => Boolean(path)).sort((a, b) => b.length - a.length);
|
|
578
|
+
for (const projectPath of projectPaths) {
|
|
579
|
+
redacted = redacted.replaceAll(projectPath, "[redacted project path]");
|
|
580
|
+
}
|
|
581
|
+
return redacted.replaceAll(
|
|
582
|
+
/(?:\/Users|\/private\/var|\/var\/folders)\/[^\s<>"')]+/g,
|
|
583
|
+
"[redacted project path]"
|
|
584
|
+
).replaceAll(/[A-Z]:\\Users\\[^\s<>"')]+/gi, "[redacted project path]");
|
|
585
|
+
}
|
|
563
586
|
function capitalize(value) {
|
|
564
587
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
565
588
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cms-lab/reporter",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "HTML report rendering for cms-lab.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"access": "public"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@cms-lab/core": "1.2.
|
|
38
|
+
"@cms-lab/core": "1.2.3"
|
|
39
39
|
},
|
|
40
40
|
"author": "Afaq Rashid",
|
|
41
41
|
"scripts": {
|