fix: improve accuracy and add manual review gate across SLDS skills

Correct hook families, badge modifiers, and severity levels; add a
manual review gate to validating-slds so automated grades alone cannot
declare production readiness; make analyze-quality.cjs portable with
explicit --hooks-index flag; remove dead parseYaml code; add version
field to all three skill frontmatters.

Made-with: Cursor
This commit is contained in:
showerbee 2026-04-09 10:31:55 -04:00
parent 43258a7b9c
commit ad41147b30
12 changed files with 294 additions and 247 deletions

View File

@ -1,5 +1,6 @@
---
name: applying-slds
version: "1.0.0"
description: Apply SLDS-compliant UI using the correct blueprints, styling hooks, utility classes, and icons. Use when building any UI that needs SLDS, choosing between Lightning Base Components and SLDS Blueprints, applying styling hooks for theming, using utility classes for layout and spacing, or selecting icons. Triggers include "build a modal", "create a form", "data table", "SLDS styling", "style with hooks", "add an icon".
---
@ -8,6 +9,8 @@ description: Apply SLDS-compliant UI using the correct blueprints, styling hooks
The **Salesforce Lightning Design System (SLDS)** is a CSS framework with thousands of artifacts. This skill teaches agents how to find and correctly use them.
> **Version:** This skill targets **SLDS v2**. Legacy `--lwc-*` tokens and `slds-*--modifier` syntax are deprecated.
>
> **Audit scope:** The companion `validating-slds` skill analyzer only scans `.css`, `.html`, and `.js` files. Use it directly for LWC and similar HTML/CSS/JS components; treat it as a partial signal for JSX/TSX or other framework-specific template formats and supplement with manual review.
## What is SLDS?
@ -30,10 +33,12 @@ The **Salesforce Lightning Design System (SLDS)** is a CSS framework with thousa
- Which icon to use and from which category
- SLDS naming conventions, class structure, hook syntax
**This skill includes basic accessibility reminders** (icon alt text, focus outlines, color-not-sole-indicator) in the validation checklists. Full WCAG compliance requires a dedicated accessibility review.
**This skill does NOT cover (use companion skills):**
- **Design decisions** -- visual hierarchy, composition, interaction patterns (design skill)
- **LWC mechanics** -- component structure, @wire, @api, lifecycle, events (LWC skill)
- **Accessibility** -- WCAG, ARIA patterns, keyboard navigation, focus management (a11y skill)
- **Design decisions** -- visual hierarchy, composition, interaction patterns
- **LWC mechanics** -- component structure, @wire, @api, lifecycle, events (not yet available)
- **Full accessibility** -- WCAG conformance, ARIA patterns, keyboard navigation, focus management, contrast ratios (not yet available)
---
@ -79,7 +84,7 @@ If no LBC exists (or not using LWC), select an SLDS Blueprint. See [references/c
## Hook Naming Traps
SLDS hook families do NOT all follow the same naming pattern. Agents frequently invent hooks that don't exist by assuming `{prefix}-{number}` works universally. **Always verify a hook exists** via `node scripts/search-hooks.cjs` or `metadata/hooks-index.json` before using it.
SLDS hook families do NOT all follow the same naming pattern. Agents frequently invent hooks that don't exist by assuming `{prefix}-{number}` works universally. **Always verify a hook exists** via the bundled `search-hooks.cjs` script or `metadata/hooks-index.json` before using it.
### Trap 1: Font size hooks are NOT numbered
@ -148,7 +153,7 @@ Use a consistent prefix for custom classes to avoid collision with SLDS:
Custom hook namespacing:
```css
:root {
--my-app-primary: var(--slds-g-color-brand-1);
--my-app-primary: var(--slds-g-color-accent-1);
--my-app-card-padding: var(--slds-g-spacing-4);
}
```
@ -253,13 +258,7 @@ The linter catches hardcoded values, class overrides, and deprecated tokens. **F
- All icons have accessibility text (A004)
- Custom classes use `my-*` or `c-*` prefix (Q010)
**Step 4 (optional): Run the full quality audit** for a scored report before code review or deployment:
```bash
node <validating-slds>/scripts/analyze-quality.cjs <component-path>
```
Or invoke the [validating-slds](../validating-slds/) skill. Target a B grade (≥80) or higher before marking work complete.
**Step 4 (optional): Run the full quality audit** using the `validating-slds` skill for a scored report before code review or deployment. Use it directly for LWC / HTML-CSS-JS components; for JSX/TSX outputs, treat the result as partial coverage only. Target a B grade (≥80) or higher before marking work complete.
---
@ -310,7 +309,7 @@ See [examples.md](examples.md) for worked examples demonstrating the full workfl
## Validation
See [checklists.md](checklists.md) for validation checklists aligned with the [validating-slds](../validating-slds/) skill.
See [checklists.md](checklists.md) for validation checklists aligned with the validating-slds skill.
## Resources

View File

@ -1,8 +1,7 @@
# Validation Checklists
Run through these checks before finalizing any SLDS-authored component. Check IDs align with the [validating-slds](../validating-slds/) skill's quality-checks.md.
Run through these checks before finalizing any SLDS-authored component. Check IDs align with the validating-slds skill's quality-checks.md.
---
## Theming & Styling (T-series)
@ -37,7 +36,7 @@ Code produced by this skill should score high on T-series checks.
| **No !important** | No `!important` declarations | Q001 |
| **No inline styles** | No `style="..."` in HTML | Q002 |
| **Custom class prefix** | Custom classes use `my-*`, `c-*`, or namespace prefix | Q010 |
| **No SLDS naming** | Custom classes don't start with `slds-` | Q012 |
| **No dynamic SLDS class manipulation** | Avoid `.classList.add/remove/toggle('slds-*')` patterns in JS | Q012 |
| **No magic numbers** | All numeric values have clear purpose | Q020 |
---

View File

@ -4,7 +4,6 @@ Worked examples showing the SLDS authoring workflow: from intent to artifact sel
Each example follows the 5-phase workflow from SKILL.md and shows which files were consulted and why.
---
## Example 1: Build a Confirmation Dialog
@ -37,7 +36,7 @@ The destructive action button needs error color to signal danger:
```bash
node scripts/search-hooks.cjs --prefix "--slds-g-color-error-"
# Found: --slds-g-color-error-1 (#ea001e), --slds-g-color-on-error (#ffffff)
# Found: --slds-g-color-error-1 (#ea001e), --slds-g-color-on-error-1 (#ffffff)
```
**Result:** Use `variant="destructive"` on `lightning-button` inside the modal footer. The LBC handles the correct SLDS color hooks internally.
@ -101,23 +100,23 @@ node scripts/search-blueprints.cjs --search "badge"
**Read YAMLs:**
- `metadata/blueprints/components/cards.yaml` -- classes: `slds-card`, `slds-card__header`, `slds-card__body`, `slds-card__footer`
- `metadata/blueprints/components/badges.yaml` -- classes: `slds-badge`, modifiers: `slds-badge_success`, `slds-badge_warning`, `slds-badge_error`
- `metadata/blueprints/components/badges.yaml` -- classes: `slds-badge`, modifiers: `slds-badge_lightest`, `slds-badge_inverse`
### Phase 3: Apply Styling
**Read:** `references/styling-decision-guide.md`
Card background and text use surface hooks. The status badge uses semantic SLDS modifier classes (no custom color needed).
Card background and text use surface hooks. The status is conveyed by badge text plus a custom status accent on the card, rather than invented badge modifiers.
```html
<article class="slds-card">
<article class="slds-card my-status-card">
<div class="slds-card__header slds-grid">
<header class="slds-media slds-media_center slds-has-flexi-truncate">
<div class="slds-media__body">
<h2 class="slds-card__header-title slds-truncate">Account Name</h2>
</div>
<div class="slds-no-flex">
<span class="slds-badge slds-badge_success">Active</span>
<span class="slds-badge slds-badge_lightest">Active</span>
</div>
</header>
</div>
@ -160,7 +159,7 @@ In React (non-LWC), use the SVG blueprint pattern:
### Phase 5: Validate
- Card uses exact blueprint classes (`slds-card`, `slds-card__header`, etc.)
- Badge uses SLDS modifier (`slds-badge_success`) not custom color
- Badge uses a real blueprint modifier (`slds-badge_lightest`), not an invented status variant
- Custom border uses `my-*` prefix and hook with fallback
- Icon uses `slds-assistive-text` for accessibility
- No hardcoded colors
@ -188,6 +187,19 @@ node scripts/search-blueprints.cjs --search "illustration"
### Phase 3: Apply Styling
**Verify grid and spacing utilities** before using them:
```bash
node scripts/search-utilities.cjs --search "slds-grid"
# Found: slds-grid (category: grid, css: display: flex)
node scripts/search-utilities.cjs --search "slds-text-heading_large"
# Found: slds-text-heading_large (category: typography)
node scripts/search-utilities.cjs --search "slds-text-body_small"
# Found: slds-text-body_small (category: typography)
```
**Grid layout** uses utility classes (see `references/utilities-quick-ref.md`):
```html

View File

@ -70,10 +70,11 @@ Before picking a hook, classify what the color is for:
| Role | Hook prefix | Examples |
|------|-------------|----------|
| Surface (backgrounds) | `--slds-g-color-surface-*` | Page bg, card bg, modal bg |
| Surface (backgrounds) | `--slds-g-color-surface-*` | Page bg, modal bg, top-level panels |
| Surface container (nested surfaces) | `--slds-g-color-surface-container-*` | Card bg, embedded panels, list items |
| On-surface (text on surfaces) | `--slds-g-color-on-surface-*` | Body text, headings, icons |
| Container (interactive bg) | `--slds-g-color-container-*` | Button bg, input bg, tab bg |
| Accent (emphasis) | `--slds-g-color-accent-*` | Primary button, selected tab |
| Accent (emphasis) | `--slds-g-color-accent-*` | Primary emphasis, selected state text/icons |
| Accent container (accent backgrounds) | `--slds-g-color-accent-container-*` | Buttons, selected tabs, emphasized controls |
| Border | `--slds-g-color-border-*` | Dividers, card borders |
| Error | `--slds-g-color-error-*` | Validation errors |
| Success | `--slds-g-color-success-*` | Confirmation states |

View File

@ -88,9 +88,11 @@ Responsive: `slds-small-size_*`, `slds-medium-size_*`, `slds-large-size_*`
- `slds-hide` -- hide element (`display: none`)
- `slds-show` -- show element (`display: block`)
- `slds-show_inline` -- show inline
- `slds-hidden` -- visually hidden but accessible
- `slds-hidden` -- hidden via `visibility: hidden`; occupies space and is not a screen-reader helper
- `slds-assistive-text` -- screen-reader only text
Use `slds-assistive-text`, not `slds-hidden`, when content should remain available to assistive technology.
### Truncation
- `slds-truncate` -- single-line truncation with ellipsis

View File

@ -12,50 +12,9 @@
const fs = require('fs');
const path = require('path');
const yaml = require !== undefined ? null : null; // yaml parsing below
const BLUEPRINTS_DIR = path.join(__dirname, '..', 'metadata', 'blueprints', 'components');
function parseYaml(text) {
const lines = text.split('\n');
const result = {};
let currentKey = null;
let currentArray = null;
let currentObj = null;
let indent = 0;
for (const line of lines) {
const trimmed = line.trimEnd();
if (!trimmed || trimmed.startsWith('#')) continue;
const match = trimmed.match(/^(\s*)([\w_]+):\s*(.*)$/);
if (match) {
const spaces = match[1].length;
const key = match[2];
let value = match[3].replace(/^["']|["']$/g, '').trim();
if (spaces === 0) {
currentKey = key;
currentArray = null;
currentObj = null;
if (value) {
result[key] = value;
} else {
result[key] = {};
}
} else if (currentKey && spaces > 0) {
if (typeof result[currentKey] === 'object' && !Array.isArray(result[currentKey])) {
if (value) {
result[currentKey][key] = value;
}
}
}
}
}
return result;
}
function loadBlueprints() {
const blueprints = [];
if (!fs.existsSync(BLUEPRINTS_DIR)) {

View File

@ -1,5 +1,6 @@
---
name: uplifting-components-to-slds2
version: "1.0.0"
description: Migrate Lightning Web Components from SLDS 1 to SLDS 2 by running the SLDS linter and fixing violations. Use this skill whenever users mention SLDS 2, SLDS uplift, linter violations, LWC token migration, class overrides, hardcoded CSS values that need SLDS hook replacement, or styling hook selection. Covers all styling hook categories — color, spacing, sizing, typography, borders, radius, and shadows. Also use when users mention no-hardcoded-values, no-slds-class-overrides, lwc-to-slds-hooks, no-deprecated-tokens-slds1, or ask about SLDS component migration — even if they don't explicitly say "uplift" or "migration".
---
@ -32,7 +33,7 @@ Color hooks require the most judgment (context-dependent selection). Non-color h
# Workflow
```
1. Run SLDS linter with auto-fix -> Handles simple violations automatically
1. **REQUIRED — ALWAYS run first:** npx @salesforce-ux/slds-linter@latest lint --fix . — NEVER skip this step. This handles simple violations automatically.
2. Review linter output -> Identify remaining manual fixes needed
3. Fix by violation type -> Use per-rule reference guides
4. Choose the right hook -> Context-first, inspect HTML before deciding
@ -40,6 +41,7 @@ Color hooks require the most judgment (context-dependent selection). Non-color h
```
## Step 1: Run SLDS Linter
MANDATORY: This step is NOT optional.
```bash
npx @salesforce-ux/slds-linter@latest lint --fix .

View File

@ -30,12 +30,12 @@ dataTable.css
**Before:**
```css
.slds-table {
border-collapse: separate;
border-spacing: 0;
border-width: var(--slds-g-sizing-border-1, 1px);
border-radius: var(--slds-g-radius-border-2, 0.25rem);
}
.slds-table .slds-button {
padding: 0.5rem 1rem;
padding: var(--slds-g-spacing-2, 0.5rem) var(--slds-g-spacing-2, 1rem);
}
```
@ -48,12 +48,12 @@ dataTable.css
**After:**
```css
.dataTable-table {
border-collapse: separate;
border-spacing: 0;
border-width: var(--slds-g-sizing-border-1, 1px);
border-radius: var(--slds-g-radius-border-2, 0.25rem);
}
.dataTable-table .dataTable-button {
padding: 0.5rem 1rem;
padding: var(--slds-g-spacing-2, 0.5rem) var(--slds-g-spacing-2, 1rem);
}
```

View File

@ -1,42 +1,33 @@
---
name: validating-slds
description: >-
Audit Lightning Web Components for SLDS compliance and produce a scored quality
report. Runs the SLDS linter, analyzes CSS for theming hook usage and pairing,
checks HTML for accessibility attributes, and scores findings across categories
into an overall grade. Use when asked to "score my component", "SLDS scorecard",
"quality report", "audit SLDS compliance", "how good is my SLDS", "check
component quality", "rate my component", "evaluate my component", "is this
component ready to ship?", "look at my LWC for issues", "audit this before I
submit", "review my component before code review", or any time a user wants a
quality assessment or production-readiness check on an LWC or SLDS component.
Not for fixing violations (use slds-uplift) or building new components (use
slds-authoring).
version: "1.0.0"
description: Audit Lightning Web Components for SLDS compliance and produce a scored quality report. Runs the SLDS linter, analyzes CSS for theming hook usage and pairing, checks HTML for accessibility attributes, and scores findings across categories into an overall grade. Use when asked to "score my component", "SLDS scorecard", "quality report", "audit SLDS compliance", "how good is my SLDS", "check component quality", "rate my component", "evaluate my component", "is this component ready to ship?", "look at my LWC for issues", "audit this before I submit", "review my component before code review", or any time a user wants a quality assessment or production-readiness check on an LWC or SLDS component. Not for fixing violations (use uplifting-components-to-slds2) or building new components (use applying-slds).
---
# SLDS Quality Audit
Audit Lightning Web Components for SLDS compliance and produce a scored quality scorecard. Combines SLDS linter output with supplementary static analysis to catch what the linter misses.
Audit Lightning Web Components for SLDS compliance and produce an automated scorecard plus a required manual review gate. Combines SLDS linter output with supplementary static analysis to catch what the linter misses.
## Scope
Also valid for: auditing SLDS compliance across a project or component set, and before/after quality comparison after making changes.
Not for:
- **Fixing** linter violations — use `slds-uplift` instead
- **Building** new components — use `slds-authoring` instead
- **Fixing** linter violations — use `uplifting-components-to-slds2` instead
- **Building** new components — use `applying-slds` instead
- **Just running the linter** — run `npx @salesforce-ux/slds-linter@latest lint .` directly
- **Full WCAG accessibility audit** — this skill checks attribute presence only (labels, alt text, focus indicators), not contrast ratios, keyboard flows, or screen reader behavior
- **Framework-specific template auditing** beyond `.css`, `.html`, and `.js` files — JSX/TSX/Vue/Svelte outputs need additional manual review
---
## Quality Validation Process
```
1. Run SLDS Linter → Collect violation counts (linter's job)
1. Run SLDS Linter → Collect violation counts (linter's job)
2. Run Analyze Script → Check what linter doesn't cover (supplementary)
3. Agent Review → Manual review prompts (not automatable)
4. Score & Grade → Combine linter + script + review findings
3. Agent Review → Required manual review gate
4. Score & Grade → Compute automated score + final recommendation
5. Generate Report → Produce formatted scorecard
```
@ -67,7 +58,7 @@ Overall (linter unavailable) = (Theming × 0.29) + (Accessibility × 0.29)
## Step 2: Run Supplementary Analysis
Run the analyze script to catch issues the linter doesn't cover:
Run the analyze script to catch issues the linter doesn't cover. The bundled analyzer scans `.css`, `.html`, and `.js` files only:
```bash
node scripts/analyze-quality.cjs <component-path>
@ -80,10 +71,10 @@ The script outputs JSON with findings organized by severity. It checks:
| Check | What It Catches | Severity |
|-------|----------------|----------|
| Missing fallbacks | `var(--slds-g-*)` without a fallback value | Critical |
| Invented hooks (T051) | `--slds-g-*` tokens not found in `hooks-index.json` | Critical |
| Invented hooks (T051) | `--slds-g-*` tokens not found in `hooks-index.json` (requires `--hooks-index`) | Critical |
| Hook pairing | Background hooks without matching foreground hooks | Warning |
| `!important` | Specificity overrides | Warning |
| Magic pixel values | Hardcoded `px` not using spacing hooks | Info |
| Magic pixel values | Hardcoded `px` not using spacing hooks | Warning |
| High z-index | z-index values > 99 | Warning |
| Outline removal | `outline: none` without alternative focus style | Warning |
@ -92,7 +83,7 @@ The script outputs JSON with findings organized by severity. It checks:
| Check | What It Catches | Severity |
|-------|----------------|----------|
| Inline style assignment | `.style.*=` direct property assignment | Warning |
| SLDS class manipulation | Dynamic `.classList.add('slds-*')` manipulation | Info |
| SLDS class manipulation | Dynamic `.classList.add('slds-*')` manipulation | Warning |
### HTML Checks
@ -105,7 +96,7 @@ The script outputs JSON with findings organized by severity. It checks:
| Positive tabindex | `tabindex` values other than 0 or -1 | Warning |
| Clickable divs | `<div onclick>` instead of `<button>` | Warning |
| Inline styles | `style="..."` attributes | Warning |
| Native elements | `<input>`, `<button>`, `<select>` where LBC alternatives exist | Info |
| Native elements | `<input>`, `<button>`, `<select>` where LBC alternatives exist | Warning |
### Hook Pairing Validation
@ -115,7 +106,7 @@ The script checks that background/foreground hooks are semantically paired:
surface-* backgrounds → on-surface-* text
surface-container-* bg → on-surface-* text
accent-* backgrounds → on-accent-* text
accent-container-* bg → on-accent-container-* text
accent-container-* bg → on-accent-* text
```
> **Limitation:** Hook pairing is checked at the file level, not per-selector. A file with `surface-1` in `.classA` and `on-accent-1` in `.classB` would pass because both surface and accent families are present. Review pairing correctness per-selector during manual review (Step 3).
@ -126,7 +117,10 @@ The script cross-references every `--slds-g-*` token in CSS against `hooks-index
## Step 3: Agent Manual Review
These checks require understanding the component's purpose and cannot be automated reliably. Review each and note findings as additional context in the report.
These checks require understanding the component's purpose and cannot be automated reliably. Review each and classify findings as either:
- **Blocking** — incorrect blueprint structure, missing required states, or semantic/interaction issues that make the component not production-ready
- **Advisory** — worthwhile improvements that do not block shipping on their own
| Review Area | What to Look For |
|-------------|-----------------|
@ -137,9 +131,9 @@ These checks require understanding the component's purpose and cannot be automat
| Semantic HTML | Are `<nav>`, `<article>`, `<section>` used where appropriate? |
| SLDS blueprint compliance | Do cards, modals, forms follow SLDS blueprint structure? |
> These are not scored. Note relevant findings in the "Recommendations" section of the report.
> Manual review findings are not automated, but they do affect the final recommendation. Do not report an automated grade as the only verdict.
## Step 4: Calculate Quality Scores
## Step 4: Calculate Automated Scores and Final Recommendation
### Component Complexity
@ -153,7 +147,7 @@ Before scoring, classify the component to give the score context:
Include the complexity classification in the report header. This prevents misreading a "B" on a 1000-line component vs. a "B" on a 20-line component.
### Scoring Formula
### Automated Scoring Formula
```
Category Score = 100 - (critical_issues × 10) - (warnings × 3) - (info × 1)
@ -168,31 +162,53 @@ Minimum score: 0
| Theming | 20% | Script: fallbacks, hook pairing (Step 2) |
| Accessibility | 20% | Script: labels, alt text, focus (Step 2) |
| Code Quality | 15% | Script: !important, inline styles, z-index (Step 2) |
| Component Usage | 15% | Script: native elements, semantic HTML (Step 2) |
| Component Usage | 15% | Script: native elements (Step 2) plus manual semantic/blueprint review (Step 3) |
### Overall Score
### Automated Overall Score
```
Overall = (Linter × 0.30) + (Theming × 0.20) + (Accessibility × 0.20)
+ (CodeQuality × 0.15) + (ComponentUsage × 0.15)
```
### Grade Thresholds
### Automated Grade Thresholds
| Score | Grade | Status |
|-------|-------|--------|
| 90-100 | A | Excellent - Ready for production |
| 80-89 | B | Good - Minor improvements suggested |
| 70-79 | C | Acceptable - Address issues before deployment |
| 60-69 | D | Needs Work - Significant issues to resolve |
| 0-59 | F | Failing - Critical issues blocking deployment |
| Score | Grade | Meaning |
|-------|-------|---------|
| 90-100 | A | Excellent automated score |
| 80-89 | B | Good automated score |
| 70-79 | C | Acceptable automated score |
| 60-69 | D | Weak automated score |
| 0-59 | F | Failing automated score |
### Manual Review Gate
After computing the automated score, apply the manual review outcome:
| Gate | When to use it | Effect on final recommendation |
|------|----------------|-------------------------------|
| Pass | No manual findings | Final recommendation can follow the automated score |
| Advisory | Only non-blocking manual findings | Final recommendation can be "Ready with follow-ups" at best |
| Blocking | One or more blocking manual findings | Final recommendation is **not ready for production**, regardless of automated grade |
### Final Recommendation Rules
Use both the automated score and the manual review gate:
| Final Recommendation | Conditions |
|----------------------|------------|
| Ready for production | Automated grade A/B, no critical findings, manual gate = Pass |
| Ready with follow-ups | Automated grade A/B, no critical findings, manual gate = Advisory |
| Needs work | Any critical findings, automated grade C/D, or manual gate = Blocking |
| Failing | Automated grade F |
## Step 5: Generate Quality Report
Use the template in **[report-format.md](references/report-format.md)** to produce the final report. Default to the **compact format** for initial output and expand sections on request.
The report includes:
- Executive summary with overall grade
- Executive summary with automated grade and final recommendation
- Manual review gate outcome (`Pass`, `Advisory`, or `Blocking`)
- Scores by category with visual indicators
- Detailed findings organized by severity
- Specific code locations and recommendations
@ -216,7 +232,7 @@ Linter Violations:
• Deprecated Tokens: 3
• Hardcoded Values: 5
Quick Grade: C (estimated)
Quick Automated Grade: C (estimated)
Run full validation for detailed report.
```
@ -241,5 +257,5 @@ If a check produces a false positive, note it in the report as "suppressed" with
- **[Quality Checks](references/quality-checks.md)** - Complete list of all quality checks with detection patterns
- **[Report Format](references/report-format.md)** - Quality report template and formatting guide
- **[Analyze Script](scripts/analyze-quality.cjs)** - Automated analysis for linter-complementary checks
- **[SLDS Uplift Skill](../slds-uplift/SKILL.md)** - How to fix linter violations
- **[SLDS Applying Skill](../applying-slds/SKILL.md)** - Guide for building new components with correct patterns
- **uplifting-components-to-slds2 skill** - How to fix linter violations
- **applying-slds skill** - Guide for building new components with correct patterns

View File

@ -4,6 +4,14 @@ Complete catalog of quality checks performed during SLDS component validation.
> **Scope note:** The SLDS linter already catches class overrides (`slds/class-override`), deprecated tokens (`slds/lwc-token-to-slds-hook`), and hardcoded values (`slds/no-hardcoded-values`). The checks below cover what the linter does **not** catch. Linter violation counts are incorporated into the final score separately — see Step 1 in SKILL.md.
### Detection Legend
| Symbol | Meaning |
|--------|---------|
| **Script** | Automated by `analyze-quality.cjs` |
| **Linter** | Caught by the SLDS linter |
| **Manual** | Requires agent review (Step 3) |
---
## Table of Contents
@ -20,50 +28,50 @@ Complete catalog of quality checks performed during SLDS component validation.
### Hook Fallbacks (not caught by linter)
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| T002 | Fallback values present | Critical | All `var(--slds-g-*)` include a fallback value |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| T002 | Fallback values present | Critical | Script | All `var(--slds-g-*)` include a fallback value |
### Hook Family Pairing
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| T010 | Surface pairing | Warning | `surface-*` bg paired with `on-surface-*` text |
| T011 | Container pairing | Warning | `surface-container-*` bg paired with `on-surface-*` text |
| T012 | Accent pairing | Warning | `accent-*` bg paired with `on-accent-*` text |
| T013 | Feedback pairing | Warning | Feedback colors paired with correct text hooks |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| T010 | File-level hook family pairing | Warning | Script | Each background hook family present in a file has a matching `on-*` family present somewhere in the same file |
| T011 | Surface/container pairing correctness | Warning | Manual | `surface-*` and `surface-container-*` backgrounds are paired with appropriate `on-surface-*` text in the same selector/context |
| T012 | Accent pairing correctness | Warning | Manual | `accent-*` and `accent-container-*` backgrounds are paired with appropriate `on-accent-*` text in the same selector/context |
| T013 | Feedback pairing correctness | Warning | Manual | Feedback colors are paired with the correct `on-error-*`, `on-warning-*`, `on-success-*`, or `on-info-*` text hooks in the same selector/context |
### Spacing Hook Usage
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| T020 | Spacing uses hooks | Warning | Spacing uses `var(--slds-g-spacing-*)` or utilities |
| T021 | No magic pixel values | Warning | No arbitrary `px` values for spacing |
| T022 | Base-8 alignment | Info | Spacing values align to 4, 8, 12, 16, 24, 32, 48px |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| T020 | Spacing uses hooks | Warning | Manual | Spacing uses `var(--slds-g-spacing-*)` or utilities |
| T021 | No magic pixel values | Warning | Script | No arbitrary `px` values for spacing |
| T022 | Base-8 alignment | Info | Manual | Spacing values align to 4, 8, 12, 16, 24, 32, 48px |
### Typography Hook Usage
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| T030 | Font family hooks | Warning | `font-family` uses `var(--slds-g-font-family-*)` |
| T031 | Font size hooks | Warning | `font-size` uses `var(--slds-g-font-scale-*)` or `var(--slds-g-font-size-base)` — NOT `var(--slds-g-font-size-N)` |
| T032 | Font weight hooks | Warning | `font-weight` uses `var(--slds-g-font-weight-*)` |
| T033 | Line height hooks | Info | `line-height` uses `var(--slds-g-font-line-height-*)` |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| T030 | Font family hooks | Warning | Manual | `font-family` uses `var(--slds-g-font-family-*)` |
| T031 | Font size hooks | Warning | Manual | `font-size` uses `var(--slds-g-font-scale-*)` or `var(--slds-g-font-size-base)` — NOT `var(--slds-g-font-size-N)` |
| T032 | Font weight hooks | Warning | Manual | `font-weight` uses `var(--slds-g-font-weight-*)` |
| T033 | Line height hooks | Info | Manual | `line-height` uses `var(--slds-g-font-line-height-*)` |
### Other Styling Hooks
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| T040 | Shadow hooks | Warning | Shadows use `var(--slds-g-shadow-*)` |
| T041 | Border radius hooks | Warning | Border radius uses `var(--slds-g-radius-*)` |
| T042 | Border width hooks | Info | Border width uses `var(--slds-g-border-width-*)` |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| T040 | Shadow hooks | Warning | Manual | Shadows use `var(--slds-g-shadow-*)` |
| T041 | Border radius hooks | Warning | Manual | Border radius uses `var(--slds-g-radius-*)` |
| T042 | Border width hooks | Info | Manual | Border width uses `var(--slds-g-border-width-*)` |
### Hook Validity
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| T050 | Color hooks numbered | Warning | Every `--slds-g-color-*` hook ends in a number (no bare `on-surface`, `on-accent`, etc.) |
| T051 | No invented hooks | Critical | Every `--slds-g-*` hook referenced actually exists in `metadata/hooks-index.json` |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| T050 | Color hooks numbered | Warning | Manual | Every `--slds-g-color-*` hook ends in a number (no bare `on-surface`, `on-accent`, etc.) |
| T051 | No invented hooks | Critical | Script | Every `--slds-g-*` hook referenced actually exists in `metadata/hooks-index.json` |
---
@ -71,40 +79,40 @@ Complete catalog of quality checks performed during SLDS component validation.
### Labels and Names
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| A001 | Input labels | Critical | All `<input>`, `<select>`, `<textarea>` have labels |
| A002 | Button names | Critical | All `<button>`, `<lightning-button>` have accessible names |
| A003 | Link names | Critical | All `<a>` have descriptive text content |
| A004 | Icon alt text | Critical | All icons have `alternative-text` or empty for decorative |
| A005 | Image alt text | Critical | All `<img>` have `alt` attribute |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| A001 | Input labels | Critical | Script | All `<lightning-input>` have `label` attribute |
| A002 | Button names | Critical | Manual | All `<button>`, `<lightning-button>` have accessible names |
| A003 | Link names | Critical | Manual | All `<a>` have descriptive text content |
| A004 | Icon alt text | Critical | Script | All icons have `alternative-text` or empty for decorative |
| A005 | Image alt text | Critical | Script | All `<img>` have `alt` attribute |
### ARIA and Semantics
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| A010 | Heading hierarchy | Warning | H1 → H2 → H3 without skipping |
| A011 | ARIA roles | Warning | `role` attributes used correctly |
| A012 | ARIA labels | Warning | `aria-label`, `aria-labelledby` used appropriately |
| A013 | ARIA live | Info | Dynamic content uses `aria-live` regions |
| A014 | ARIA invalid | Warning | Invalid form fields have `aria-invalid="true"` |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| A010 | Heading hierarchy | Warning | Script | H1 → H2 → H3 without skipping |
| A011 | ARIA roles | Warning | Manual | `role` attributes used correctly |
| A012 | ARIA labels | Warning | Manual | `aria-label`, `aria-labelledby` used appropriately |
| A013 | ARIA live | Info | Manual | Dynamic content uses `aria-live` regions |
| A014 | ARIA invalid | Warning | Manual | Invalid form fields have `aria-invalid="true"` |
### Keyboard and Focus
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| A020 | Tab order | Warning | `tabindex` values are 0 or -1 only |
| A021 | Focus visible | Warning | No `outline: none` without alternative focus style |
| A022 | Interactive elements | Warning | Clickable elements are `<button>` or `<a>` |
| A023 | Focus management | Info | Modals trap focus, return focus on close |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| A020 | Tab order | Warning | Script | `tabindex` values are 0 or -1 only |
| A021 | Focus visible | Warning | Script | No `outline: none` without alternative focus style |
| A022 | Interactive elements | Warning | Script | Clickable elements are `<button>` or `<a>` |
| A023 | Focus management | Info | Manual | Modals trap focus, return focus on close |
### Visual Accessibility
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| A030 | Color not sole indicator | Warning | Status/errors use icon or text, not just color |
| A031 | Touch targets | Info | Interactive elements >= 44x44px on mobile |
| A032 | Text sizing | Info | Text can scale without breaking layout |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| A030 | Color not sole indicator | Warning | Manual | Status/errors use icon or text, not just color |
| A031 | Touch targets | Info | Manual | Interactive elements >= 44x44px on mobile |
| A032 | Text sizing | Info | Manual | Text can scale without breaking layout |
---
@ -112,31 +120,32 @@ Complete catalog of quality checks performed during SLDS component validation.
### CSS Anti-patterns
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| Q001 | No !important | Warning | No `!important` declarations |
| Q002 | No inline styles | Warning | No `style="..."` in HTML |
| Q003 | No deep nesting | Info | Selectors <= 3 levels deep |
| Q004 | No ID selectors | Info | No `#id` in CSS selectors |
| Q005 | No universal selectors | Info | No `*` in CSS selectors |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| Q001 | No !important | Warning | Script | No `!important` declarations |
| Q002 | No inline styles (HTML) | Warning | Script | No `style="..."` attributes in HTML |
| Q025 | No inline styles (JS) | Warning | Script | No `.style.*=` direct property assignment in JS |
| Q003 | No deep nesting | Info | Manual | Selectors <= 3 levels deep |
| Q004 | No ID selectors | Info | Manual | No `#id` in CSS selectors |
| Q005 | No universal selectors | Info | Manual | No `*` in CSS selectors |
### Naming Conventions
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| Q010 | Component prefix | Warning | Custom classes use component prefix |
| Q011 | CamelCase prefix | Warning | Prefix follows camelCase convention |
| Q012 | No SLDS naming | Warning | Custom classes don't start with `slds-` |
| Q013 | BEM consistency | Info | Class names follow consistent BEM pattern |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| Q010 | Component prefix | Warning | Manual | Custom classes use component prefix |
| Q011 | CamelCase prefix | Warning | Manual | Prefix follows camelCase convention |
| Q012 | Avoid dynamic SLDS class manipulation | Warning | Script | Avoid `.classList.add/remove/toggle('slds-*')` patterns in JS |
| Q013 | BEM consistency | Info | Manual | Class names follow consistent BEM pattern |
### Maintainability
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| Q020 | No magic numbers | Warning | All numeric values have clear purpose |
| Q021 | Z-index scale | Warning | Z-index values follow defined scale |
| Q022 | No fixed dimensions | Warning | Avoid fixed `width`/`height` in px |
| Q023 | CSS file size | Info | CSS file < 500 lines |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| Q020 | No magic numbers | Warning | Manual | All numeric values have clear purpose |
| Q021 | Z-index scale | Warning | Script | Z-index values follow defined scale |
| Q022 | No fixed dimensions | Warning | Manual | Avoid fixed `width`/`height` in px |
| Q023 | CSS file size | Info | Manual | CSS file < 500 lines |
---
@ -144,32 +153,32 @@ Complete catalog of quality checks performed during SLDS component validation.
### Lightning Base Components
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| C001 | Use LBC inputs | Warning | Use `<lightning-input>` not `<input>` |
| C002 | Use LBC buttons | Warning | Use `<lightning-button>` not `<button>` |
| C003 | Use LBC icons | Warning | Use `<lightning-icon>` not custom SVG |
| C004 | Use LBC combobox | Warning | Use `<lightning-combobox>` not `<select>` |
| C005 | Use LBC datatable | Info | Use `<lightning-datatable>` for tables |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| C001 | Use LBC inputs | Warning | Script | Use `<lightning-input>` not `<input>` |
| C002 | Use LBC buttons | Warning | Script | Use `<lightning-button>` not `<button>` |
| C003 | Use LBC icons | Warning | Manual | Use `<lightning-icon>` not custom SVG |
| C004 | Use LBC combobox | Warning | Script | Use `<lightning-combobox>` not `<select>` |
| C005 | Use LBC datatable | Info | Manual | Use `<lightning-datatable>` for tables |
### SLDS Blueprint Compliance
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| C010 | Card structure | Warning | Cards use `slds-card` class structure |
| C011 | Modal structure | Warning | Modals use `slds-modal` class structure |
| C012 | Form structure | Warning | Forms use `slds-form` or `slds-form-element` |
| C013 | Button variants | Info | Buttons use `slds-button_*` variants |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| C010 | Card structure | Warning | Manual | Cards use `slds-card` class structure |
| C011 | Modal structure | Warning | Manual | Modals use `slds-modal` class structure |
| C012 | Form structure | Warning | Manual | Forms use `slds-form` or `slds-form-element` |
| C013 | Button variants | Info | Manual | Buttons use `slds-button_*` variants |
### Semantic HTML
| ID | Check | Severity | Pass Criteria |
|----|-------|----------|---------------|
| C020 | Use button element | Warning | Clickable elements use `<button>` |
| C021 | Use nav element | Info | Navigation uses `<nav>` |
| C022 | Use article element | Info | Self-contained content uses `<article>` |
| C023 | Use section element | Info | Thematic grouping uses `<section>` |
| C024 | No div soup | Info | Meaningful elements used over nested `<div>` |
| ID | Check | Severity | Detection | Pass Criteria |
|----|-------|----------|-----------|---------------|
| C020 | Use button element | Warning | Manual | Clickable elements use `<button>` |
| C021 | Use nav element | Info | Manual | Navigation uses `<nav>` |
| C022 | Use article element | Info | Manual | Self-contained content uses `<article>` |
| C023 | Use section element | Info | Manual | Thematic grouping uses `<section>` |
| C024 | No div soup | Info | Manual | Meaningful elements used over nested `<div>` |
---
@ -186,8 +195,8 @@ const MISSING_FALLBACK = /var\(--slds-g-[^,)]+\)/g;
// !important usage
const IMPORTANT = /!important/g;
// Magic pixel values (not inside a var() fallback)
const MAGIC_PX = /:\s*\d+px(?![^;]*var\()/g;
// Magic pixel spacing values (not inside a var() fallback)
const MAGIC_PX = /\b(?:margin(?:-[a-z-]+)?|padding(?:-[a-z-]+)?|gap|row-gap|column-gap)\s*:\s*\d+px\b(?![^;]*var\()/g;
// High z-index (3+ digits)
const HIGH_ZINDEX = /z-index\s*:\s*(\d{3,})/g;
@ -233,7 +242,7 @@ const NATIVE_SELECT = /<select\s/gi;
1. **CSS Files**: Parse with regex, track line numbers, categorize findings; cross-reference hooks against `hooks-index.json` (T051)
2. **HTML Files**: Parse with regex, validate structure, check attributes
3. **JS Files**: Check for inline style assignment (`.style.*=`) and dynamic SLDS class manipulation (`.classList.add('slds-*')`)
4. **Cross-file**: Validate CSS classes used in HTML exist in CSS
4. **Cross-file/manual**: Review relationships between files that regex cannot validate reliably
---
@ -260,32 +269,40 @@ Overall = (Linter × 0.30) + (Theming × 0.20) + (Accessibility × 0.20)
### Automation Coverage
The script automates ~20 of the ~60 checks listed above. The remaining checks require agent manual review (Step 3 in SKILL.md). Categories with fewer automated checks (Code Quality, Component Usage) will tend toward 100 when no automated findings exist — agents should factor in manual review findings when interpreting these scores.
The script automates **17 of 53** checks listed above (marked **Script** in the Detection column). The remaining 36 require agent manual review (Step 3 in SKILL.md). Categories with fewer automated checks — especially Code Quality (4 of 13) and Component Usage (3 of 14) — will tend toward 100 when no automated findings exist. Treat the automated score as provisional: manual review findings must be reported separately and can block a production recommendation even when the score is high.
### Theming
```
Score = 100 - (T002/T051 criticals × 10) - (T010-T013 warnings × 3) - (T020-T042 info × 1)
Score = 100 - (critical issues in category × 10)
- (warnings in category × 3)
- (info in category × 1)
Min: 0
```
### Accessibility
```
Score = 100 - (A001-A005 criticals × 10) - (A010-A023 warnings × 3) - (A030-A032 info × 1)
Score = 100 - (critical issues in category × 10)
- (warnings in category × 3)
- (info in category × 1)
Min: 0
```
### Code Quality
```
Score = 100 - (Q001-Q005 warnings × 3) - (Q010-Q023 info × 1)
Score = 100 - (critical issues in category × 10)
- (warnings in category × 3)
- (info in category × 1)
Min: 0
```
### Component Usage
```
Score = 100 - (C001-C005 warnings × 3) - (C010-C024 info × 1)
Score = 100 - (critical issues in category × 10)
- (warnings in category × 3)
- (info in category × 1)
Min: 0
```

View File

@ -14,10 +14,13 @@ Always start with this format. It gives the user the full picture in a glanceabl
**Path:** `{component-path}` | **Complexity:** {small|medium|large} ({n} files, {n} lines)
**Generated:** {date}
## Grade: {grade} ({score}/100)
## Automated Grade: {grade} ({score}/100)
{grade-description}
**Manual Review Gate:** {Pass|Advisory|Blocking}
**Final Recommendation:** {Ready for production|Ready with follow-ups|Needs work|Failing}
| Category | Score | Grade |
|----------|-------|-------|
| Linter Compliance | {score}/100 | {status-emoji} {grade} |
@ -34,6 +37,8 @@ Always start with this format. It gives the user the full picture in a glanceabl
2. **{issue}** — `{file}:{line}` — {recommendation}
3. **{issue}** — `{file}:{line}` — {recommendation}
> Automated score reflects linter + script findings only. Manual review can still block ship.
>
> {accessibility-disclaimer-if-scored}
*Ask for the full report to see all findings, code examples, and action items.*
@ -98,6 +103,21 @@ Suggestions for improvement.
## Detailed Findings
### Manual Review Gate
**Gate:** {Pass|Advisory|Blocking}
| Review Area | Outcome | Notes |
|-------------|---------|-------|
| Loading states | {Pass|Advisory|Blocking} | {notes} |
| Error states | {Pass|Advisory|Blocking} | {notes} |
| Empty states | {Pass|Advisory|Blocking} | {notes} |
| Disabled states | {Pass|Advisory|Blocking} | {notes} |
| Semantic HTML | {Pass|Advisory|Blocking} | {notes} |
| Blueprint compliance | {Pass|Advisory|Blocking} | {notes} |
---
### Linter Compliance
**Violations Found:** {count}
@ -215,8 +235,8 @@ For programmatic consumption (e.g., CI integration or tracking over time). Produ
"totalLines": 280
},
"scores": {
"overall": 85,
"grade": "B",
"automatedOverall": 85,
"automatedGrade": "B",
"categories": {
"linter": { "score": 100, "grade": "A" },
"theming": { "score": 80, "grade": "B" },
@ -225,6 +245,11 @@ For programmatic consumption (e.g., CI integration or tracking over time). Produ
"componentUsage": { "score": 85, "grade": "B" }
}
},
"manualReview": {
"gate": "Advisory",
"findings": []
},
"finalRecommendation": "Ready with follow-ups",
"findings": {
"critical": [],
"warnings": [],
@ -258,19 +283,20 @@ For programmatic consumption (e.g., CI integration or tracking over time). Produ
| Grade | Description |
|-------|-------------|
| A | **Excellent** - Component follows SLDS best practices. Minor improvements possible. Ready for production. |
| B | **Good** - Component is well-structured with minor issues. Address warnings before deployment. |
| C | **Acceptable** - Component has notable issues that should be addressed. Not recommended for production without fixes. |
| D | **Needs Work** - Component has significant quality issues. Requires attention before code review. |
| F | **Critical** - Component has blocking issues that must be resolved. Not suitable for deployment. |
| A | **Excellent** - Strong automated result. Requires a passing manual review gate before calling it production-ready. |
| B | **Good** - Solid automated result. Requires manual review before a production recommendation. |
| C | **Acceptable** - Automated issues should be addressed before production. |
| D | **Needs Work** - Significant automated issues require attention before code review. |
| F | **Critical** - Automated checks found blocking issues. Not suitable for deployment. |
---
## Report Delivery Guidelines
1. **Always default to compact** — show the scorecard first, expand on request
2. **Group by severity** — critical issues first, then warnings, then info
3. **Include actionable recommendations** — every finding should have a clear fix
4. **Provide code examples** — show before/after for complex fixes in the expanded report
5. **Note complexity** — a "B" on a large component means something different than a "B" on a small one
6. **Add accessibility disclaimer** — when the accessibility score is included, note it checks attribute presence only
2. **Separate automated grade from final recommendation** — manual review can override ship readiness
3. **Group by severity** — critical issues first, then warnings, then info
4. **Include actionable recommendations** — every finding should have a clear fix
5. **Provide code examples** — show before/after for complex fixes in the expanded report
6. **Note complexity** — a "B" on a large component means something different than a "B" on a small one
7. **Add accessibility disclaimer** — when the accessibility score is included, note it checks attribute presence only

View File

@ -5,7 +5,7 @@
*
* Analyzes CSS and HTML files for SLDS quality issues beyond what the linter catches.
*
* Usage: node analyze-quality.cjs <component-path>
* Usage: node analyze-quality.cjs <component-path> [--hooks-index <path>]
*
* Output: JSON with findings categorized by severity
*/
@ -13,9 +13,15 @@
const fs = require('fs');
const path = require('path');
// Resolve applying-slds metadata relative to this script's location
const APPLYING_SLDS_ROOT = path.resolve(__dirname, '../../applying-slds');
const HOOKS_INDEX_PATH = path.join(APPLYING_SLDS_ROOT, 'metadata/hooks-index.json');
function resolveHooksIndexPath(args) {
const idx = args.indexOf('--hooks-index');
if (idx !== -1 && idx + 1 < args.length) {
return path.resolve(args[idx + 1]);
}
return null;
}
let HOOKS_INDEX_PATH = null;
// Severity levels
const CRITICAL = 'critical';
@ -45,8 +51,8 @@ const PATTERNS = {
recommendation: 'Remove !important, use proper specificity'
},
magicPixels: {
pattern: /:\s*(\d+)px(?![^;]*var\()/g,
severity: INFO,
pattern: /\b(?:margin(?:-[a-z-]+)?|padding(?:-[a-z-]+)?|gap|row-gap|column-gap)\s*:\s*(\d+)px\b(?![^;]*var\()/g,
severity: WARNING,
id: 'T021',
message: 'Magic pixel value not using spacing hook',
recommendation: 'Use var(--slds-g-spacing-*) or utility class'
@ -71,13 +77,13 @@ const PATTERNS = {
inlineStyleJS: {
pattern: /\.style\.\w+\s*=/g,
severity: WARNING,
id: 'Q002',
id: 'Q025',
message: 'Inline style manipulation in JavaScript',
recommendation: 'Use CSS classes instead of direct style property assignment'
},
classListManipulation: {
pattern: /\.classList\.(add|remove|toggle)\(\s*['"]slds-/g,
severity: INFO,
severity: WARNING,
id: 'Q012',
message: 'Dynamic SLDS class manipulation in JavaScript',
recommendation: 'Prefer declarative class bindings; avoid manipulating slds-* classes directly'
@ -129,21 +135,21 @@ const PATTERNS = {
},
nativeInput: {
pattern: /<input\s/gi,
severity: INFO,
severity: WARNING,
id: 'C001',
message: 'Native input element',
recommendation: 'Consider <lightning-input> for built-in labeling and validation'
},
nativeButton: {
pattern: /<button\s(?![^>]*class\s*=\s*["'][^"']*slds-button)/gi,
severity: INFO,
severity: WARNING,
id: 'C002',
message: 'Native button element',
recommendation: 'Consider <lightning-button> for SLDS styling consistency (suppressed if slds-button class present)'
},
nativeSelect: {
pattern: /<select\s/gi,
severity: INFO,
severity: WARNING,
id: 'C004',
message: 'Native select element',
recommendation: 'Consider <lightning-combobox> for consistency'
@ -263,10 +269,13 @@ function analyzeHeadings(filePath) {
let _validHooks = null;
function loadValidHooks() {
if (_validHooks) return _validHooks;
if (!HOOKS_INDEX_PATH) return null;
try {
const data = JSON.parse(fs.readFileSync(HOOKS_INDEX_PATH, 'utf-8'));
_validHooks = new Set(data.hooks.map(h => h.token));
} catch {
console.error(`WARNING: Could not load hooks-index.json at ${HOOKS_INDEX_PATH}`);
console.error('Invented-hook detection (T051) will be skipped.');
_validHooks = null;
}
return _validHooks;
@ -366,7 +375,7 @@ function calculateScores(findings) {
const categories = {
theming: { issues: 0, ids: ['T002', 'T010', 'T011', 'T021', 'T051'] },
accessibility: { issues: 0, ids: ['A001', 'A004', 'A005', 'A010', 'A020', 'A021', 'A022'] },
codeQuality: { issues: 0, ids: ['Q001', 'Q002', 'Q012', 'Q021'] },
codeQuality: { issues: 0, ids: ['Q001', 'Q002', 'Q012', 'Q021', 'Q025'] },
componentUsage: { issues: 0, ids: ['C001', 'C002', 'C004'] }
};
@ -465,7 +474,7 @@ function analyze(componentPath) {
totalFiles,
totalLines
},
note: "These are category scores only. Combine with SLDS linter results using the formula in SKILL.md Step 4 to compute the final overall grade.",
note: "These are automated category scores only. Combine them with SLDS linter results and the required Step 3 manual review gate in SKILL.md before making a final ship recommendation.",
scores: {
theming: { score: scores.theming, grade: getGrade(scores.theming) },
accessibility: { score: scores.accessibility, grade: getGrade(scores.accessibility) },
@ -491,16 +500,21 @@ function analyze(componentPath) {
// CLI entry point
if (require.main === module) {
const args = process.argv.slice(2);
const positionalArgs = args.filter((a, i) => !a.startsWith('--') && (i === 0 || !args[i - 1].startsWith('--')));
if (args.length === 0) {
if (positionalArgs.length === 0) {
console.log('SLDS Quality Analyzer');
console.log('Usage: node analyze-quality.cjs <component-path>');
console.log('Usage: node analyze-quality.cjs <component-path> [--hooks-index <path>]');
console.log('');
console.log('Options:');
console.log(' --hooks-index <path> Path to hooks-index.json (optional; enables T051 invented-hook detection)');
console.log('');
console.log('Output: JSON analysis of SLDS quality issues');
process.exit(0);
}
const result = analyze(args[0]);
HOOKS_INDEX_PATH = resolveHooksIndexPath(args);
const result = analyze(positionalArgs[0]);
console.log(JSON.stringify(result, null, 2));
}