Skip to content

Lint_design_principles

FieldValue
TypeSkill Resource
Source~/.copilot/skills/design/scripts/lint_design_principles.sh
DescriptionNot specified

Source Content

#!/usr/bin/env bash
# Heuristic lint for the design-principles house rules: ADR-009 (icon-text
# CSS grid) and ADR-008 (one neutral border per local stack).
#
# Usage:
# lint_design_principles.sh <path>
#
# Example:
# scripts/lint_design_principles.sh src/components/ui/Card.tsx
# scripts/lint_design_principles.sh src/components/patterns/
#
# Exit code is non-zero if any hard check fails. This script shells out to no
# external tools — it is pure grep/awk — so there is no degradation path.
#
# IMPORTANT — both checks below are heuristic, grep-based pattern matching,
# not real AST/JSX parsing. They cannot see element nesting, prop boundaries,
# or component structure the way a compiler does. Expect false positives on
# unusual formatting and false negatives on cleverly split className strings.
# Use this as a fast first pass, not a substitute for code review.
set -uo pipefail
TARGET="${1:-}"
if [[ -z "$TARGET" || ! -e "$TARGET" ]]; then
echo "Usage: $0 <file-or-dir>" >&2
exit 2
fi
fail=0
warn() { printf '⚠️ %s\n' "$1"; }
error() { printf '❌ %s\n' "$1"; fail=1; }
ok() { printf '✅ %s\n' "$1"; }
# Collect target .tsx/.jsx files.
files=()
if [[ -d "$TARGET" ]]; then
while IFS= read -r -d '' f; do
files+=("$f")
done < <(find "$TARGET" -type f \( -name '*.tsx' -o -name '*.jsx' \) -print0)
else
files+=("$TARGET")
fi
if [[ "${#files[@]}" -eq 0 ]]; then
warn "no .tsx/.jsx files found under $TARGET — nothing to check"
exit 0
fi
echo "== house rule: icon-text layout must be CSS grid, never flex-col (ADR-009) =="
icon_signal_re='(lucide-react|Icon["'\'']?[[:space:]]*(from|;)|<svg|[A-Za-z]+Icon\b)'
flex_col_re='flex-col'
grid_ok_re='grid-cols-\[auto_1fr(_auto)?\]'
for f in "${files[@]}"; do
file_has_icon_signal=0
grep -qE "$icon_signal_re" "$f" && file_has_icon_signal=1
file_has_grid_ok=0
grep -qE "$grid_ok_re" "$f" && file_has_grid_ok=1
# Flag flex-col lines that have an icon signal within +/-5 lines.
flex_col_line_nums=$(grep -nE "$flex_col_re" "$f" | cut -d: -f1 || true)
if [[ -n "$flex_col_line_nums" && "$file_has_icon_signal" -eq 1 ]]; then
total_lines=$(wc -l < "$f" | tr -d ' ')
while IFS= read -r ln; do
[[ -z "$ln" ]] && continue
start=$(( ln - 5 )); (( start < 1 )) && start=1
end=$(( ln + 5 )); (( end > total_lines )) && end=total_lines
window=$(sed -n "${start},${end}p" "$f")
if grep -qE "$icon_signal_re" <<< "$window"; then
error "$f:$ln — flex-col near an icon signal (icon import/<svg>/*Icon) — icon rows must use grid grid-cols-[auto_1fr] or [auto_1fr_auto], never flex-col (ADR-009)"
fi
done <<< "$flex_col_line_nums"
fi
if [[ "$file_has_grid_ok" -eq 1 ]]; then
ok_lines=$(grep -nE "$grid_ok_re" "$f" | cut -d: -f1 | tr '\n' ',' | sed 's/,$//')
ok "$f:$ok_lines — grid-cols-[auto_1fr...] icon-grid pattern found"
fi
done
echo
echo "== house rule: one neutral border per local stack (ADR-008) =="
# Non-exempt border utility, e.g. border, border-2, border-border, border-muted.
# Exempt: ring-*, border-destructive, border-primary (semantic-state carve-outs).
border_re='\bborder(-[a-z0-9/]+)?\b'
exempt_re='border-(destructive|primary)\b'
for f in "${files[@]}"; do
# Find className-bearing lines with a non-exempt border utility.
border_lines=$(grep -nE "$border_re" "$f" | grep -vE "$exempt_re" | grep -E 'className' || true)
count=$(grep -cE "$border_re" <<< "$border_lines" 2>/dev/null || true)
[[ -z "$count" ]] && count=0
if [[ "$count" -ge 3 ]]; then
error "$f — ${count} non-exempt border declarations found in one file (parent+child+ likely doubled border, ADR-008 allows one neutral perimeter border per local stack):"
echo "$border_lines" | sed "s#^# ${f}:#"
elif [[ "$count" -eq 2 ]]; then
warn "$f — 2 non-exempt border declarations found (heuristic/best-effort — grep cannot see JSX nesting, so this may be two sibling elements, not a nested parent+child; verify manually per ADR-008):"
echo "$border_lines" | sed "s#^# ${f}:#"
else
ok "$f — no doubled-border signal (0-1 non-exempt border declarations)"
fi
done
echo
if [[ "$fail" -eq 0 ]]; then
echo "All hard checks passed. (Heuristic/grep-based — verify by eye, not AST-exact.)"
else
echo "One or more checks failed — see ❌ lines above. (Heuristic/grep-based — confirm before treating as ground truth.)"
fi
exit "$fail"