Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | 1x 1x 6x 8x 2x 1x 4x 1x 1x 27x 8x 8x 6x 5x | /**
* Display copy + pure formatters for the compliance components.
*
* Lives separate from `CompliancePanel.tsx` / `ComplianceRow.tsx` so
* non-React consumers (Storybook manager bundle, MDX `<code>` chips,
* sandbox status strings) can import the strings and tiny helpers
* without pulling React into their bundle. The two component files
* here re-import these so there is exactly one source of truth.
*/
import type { ComplianceStatus, ComplianceVerdict } from '../types.js';
/** Counts of rows by status, keyed by status name. */
export type ComplianceStatusCounts = Record<ComplianceStatus, number>;
/**
* Headline + glyph for each verdict. Rendered as `<glyph> <title> — <subtitle>`
* so screen readers and visual users get the same one-glance summary.
*/
export const VERDICT_COPY: Record<ComplianceVerdict, { glyph: string; title: string }> = {
conformant: { glyph: '✓', title: 'Theme-layer conformant' },
'conformant-pending-review': { glyph: '!', title: 'Conformant, pending review' },
'not-conformant': { glyph: '✗', title: 'Not theme-layer conformant' },
'not-evaluated': { glyph: '–', title: 'Not yet evaluated' },
};
/** Display order for summary pills and the row list, severity-ranked. */
export const SUMMARY_ORDER: readonly ComplianceStatus[] = ['fail', 'review', 'pass', 'info'];
/** Pluralization helper local to verdict subtitles. */
function pluralize(n: number, singular: string, plural = `${singular}s`): string {
return n === 1 ? singular : plural;
}
/**
* Build the per-verdict subtitle from the row counts. Returns the
* same string regardless of host so the panel reads identically in
* Storybook, sandbox, and MDX surfaces.
*/
export function verdictSubtitle(verdict: ComplianceVerdict, counts: ComplianceStatusCounts): string {
switch (verdict) {
case 'conformant':
return `All ${counts.pass} ${pluralize(counts.pass, 'check')} ${pluralize(counts.pass, 'passes', 'pass')}.`;
case 'conformant-pending-review':
return `${counts.review} ${pluralize(counts.review, 'check')} need a human look; ${counts.pass} pass.`;
case 'not-conformant':
return `${counts.fail} fail, ${counts.review} review, ${counts.pass} pass.`;
case 'not-evaluated':
Iif (counts.info === 0) return 'No checks have run yet.';
return `${counts.info} ${pluralize(counts.info, 'check')} have no data source loaded yet.`;
}
}
/** Single-character glyph rendered alongside the row's status pill. */
export function statusGlyph(status: ComplianceStatus): string {
switch (status) {
case 'pass':
return '✓';
case 'fail':
return '✕';
case 'review':
return '!';
case 'info':
default:
return 'i';
}
}
/**
* Trim location strings down to the meaningful suffix authors care about.
* The audit threads absolute filesystem paths through `decl.source`, which
* blows out the location chip's grid column and squeezes the hook column
* to one character per line. Anchor the displayed path to the SLDS2
* component root (`slds2/<name>/...`) so the offender name has room to
* breathe; the full path stays in the host's `title` tooltip.
*/
export function formatOffenderLocation(location: string): string {
const slds2Idx = location.lastIndexOf('/slds2/');
if (slds2Idx !== -1) return location.slice(slds2Idx + 1);
const srcIdx = location.lastIndexOf('/src/');
if (srcIdx !== -1) return location.slice(srcIdx + 1);
return location;
}
|