Feat v0.6.16 usability survey gate (#51)
All checks were successful
All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #51.
This commit is contained in:
287
scripts/generate-ui-inventory.sh
Executable file
287
scripts/generate-ui-inventory.sh
Executable file
@@ -0,0 +1,287 @@
|
||||
#!/usr/bin/env bash
|
||||
# generate-ui-inventory.sh — Walk kernel + package CSS, extract class selectors with metadata.
|
||||
# Outputs ui-inventory.json to stdout.
|
||||
# Usage: bash scripts/generate-ui-inventory.sh [css-dir] [packages-dir]
|
||||
|
||||
set -euo pipefail
|
||||
CSS_DIR="${1:-src/css}"
|
||||
PKG_DIR="${2:-packages}"
|
||||
|
||||
# Collect all CSS files: kernel + packages
|
||||
FILES=()
|
||||
for f in "$CSS_DIR"/*.css; do [ -f "$f" ] && FILES+=("$f"); done
|
||||
for f in "$PKG_DIR"/*/css/main.css; do [ -f "$f" ] && FILES+=("$f"); done
|
||||
|
||||
# Derive surface name from file path
|
||||
surface_for() {
|
||||
local f="$1"
|
||||
if [[ "$f" == "$PKG_DIR"/* ]]; then
|
||||
local slug
|
||||
slug="$(basename "$(dirname "$(dirname "$f")")")"
|
||||
echo "ext/$slug"
|
||||
else
|
||||
local base
|
||||
base="$(basename "$f" .css)"
|
||||
echo "kernel/$base"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "["
|
||||
first_entry=true
|
||||
|
||||
for f in "${FILES[@]}"; do
|
||||
surface="$(surface_for "$f")"
|
||||
relpath="$f"
|
||||
|
||||
in_comment=0
|
||||
in_keyframes=0
|
||||
in_fontface=0
|
||||
brace_depth=0
|
||||
media_breakpoint=""
|
||||
current_selector=""
|
||||
current_line=0
|
||||
current_classes=""
|
||||
current_spacing=""
|
||||
current_fontsize=""
|
||||
current_breakpoints=""
|
||||
lineno=0
|
||||
|
||||
while IFS= read -r line; do
|
||||
lineno=$((lineno + 1))
|
||||
|
||||
# Track block comments
|
||||
if (( in_comment )); then
|
||||
[[ "$line" == *"*/"* ]] && in_comment=0
|
||||
continue
|
||||
fi
|
||||
if [[ "$line" == *"/*"* ]] && [[ "$line" != *"*/"* ]]; then
|
||||
in_comment=1
|
||||
continue
|
||||
fi
|
||||
|
||||
# Trim leading whitespace
|
||||
trimmed="${line#"${line%%[![:space:]]*}"}"
|
||||
[[ -z "$trimmed" ]] && continue
|
||||
[[ "$trimmed" == /\** ]] && continue
|
||||
|
||||
# Track @keyframes blocks
|
||||
if [[ "$trimmed" =~ ^@keyframes ]]; then
|
||||
in_keyframes=1
|
||||
continue
|
||||
fi
|
||||
if (( in_keyframes )); then
|
||||
[[ "$trimmed" == "}" ]] && in_keyframes=0
|
||||
continue
|
||||
fi
|
||||
|
||||
# Skip @font-face
|
||||
if [[ "$trimmed" =~ ^@font-face ]]; then
|
||||
in_fontface=1
|
||||
continue
|
||||
fi
|
||||
if (( in_fontface )); then
|
||||
[[ "$trimmed" == *"}"* ]] && in_fontface=0
|
||||
continue
|
||||
fi
|
||||
|
||||
# Track @media breakpoints
|
||||
if [[ "$trimmed" =~ ^@media.*max-width ]]; then
|
||||
if [[ "$trimmed" =~ 768 ]]; then
|
||||
media_breakpoint="768px"
|
||||
elif [[ "$trimmed" =~ 1024 ]]; then
|
||||
media_breakpoint="1024px"
|
||||
else
|
||||
media_breakpoint="other"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
# Skip other @-rules
|
||||
[[ "$trimmed" =~ ^@.+ ]] && continue
|
||||
|
||||
# Handle closing brace
|
||||
if [[ "$trimmed" == "}" ]]; then
|
||||
if [[ -n "$media_breakpoint" ]] && (( brace_depth == 0 )); then
|
||||
media_breakpoint=""
|
||||
fi
|
||||
# If we had an open selector block, emit it
|
||||
if [[ -n "$current_selector" ]]; then
|
||||
# Build breakpoints array
|
||||
bp_json="[]"
|
||||
if [[ -n "$current_breakpoints" ]]; then
|
||||
bp_json="["
|
||||
bp_first=true
|
||||
for bp in $current_breakpoints; do
|
||||
$bp_first && bp_first=false || bp_json="$bp_json,"
|
||||
bp_json="$bp_json\"$bp\""
|
||||
done
|
||||
bp_json="$bp_json]"
|
||||
fi
|
||||
|
||||
# Build spacing array
|
||||
sp_json="[]"
|
||||
if [[ -n "$current_spacing" ]]; then
|
||||
sp_json="["
|
||||
sp_first=true
|
||||
# Deduplicate
|
||||
seen_sp=""
|
||||
for sp in $current_spacing; do
|
||||
[[ " $seen_sp " == *" $sp "* ]] && continue
|
||||
seen_sp="$seen_sp $sp"
|
||||
$sp_first && sp_first=false || sp_json="$sp_json,"
|
||||
sp_json="$sp_json\"$sp\""
|
||||
done
|
||||
sp_json="$sp_json]"
|
||||
fi
|
||||
|
||||
# Build font-size array
|
||||
fs_json="[]"
|
||||
if [[ -n "$current_fontsize" ]]; then
|
||||
fs_json="["
|
||||
fs_first=true
|
||||
for fs in $current_fontsize; do
|
||||
$fs_first && fs_first=false || fs_json="$fs_json,"
|
||||
fs_json="$fs_json\"$fs\""
|
||||
done
|
||||
fs_json="$fs_json]"
|
||||
fi
|
||||
|
||||
# Build classes array
|
||||
cls_json="["
|
||||
cls_first=true
|
||||
for cls in $current_classes; do
|
||||
$cls_first && cls_first=false || cls_json="$cls_json,"
|
||||
cls_json="$cls_json\"$cls\""
|
||||
done
|
||||
cls_json="$cls_json]"
|
||||
|
||||
$first_entry && first_entry=false || printf ",\n"
|
||||
printf ' {"surface":"%s","component":"%s","classes":%s,"file":"%s","line":%d,"responsive_breakpoints":%s,"spacing_tokens_used":%s,"font_size_tokens_used":%s}' \
|
||||
"$surface" "$current_selector" "$cls_json" "$relpath" "$current_line" "$bp_json" "$sp_json" "$fs_json"
|
||||
|
||||
current_selector=""
|
||||
current_classes=""
|
||||
current_spacing=""
|
||||
current_fontsize=""
|
||||
current_breakpoints=""
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
# Selector line — contains a class and an opening brace
|
||||
if [[ "$trimmed" == *"."* ]] && [[ "$trimmed" == *"{"* ]]; then
|
||||
# Extract the selector part (before {)
|
||||
sel_part="${trimmed%%\{*}"
|
||||
# Extract the property part (after {), may have properties on the same line
|
||||
prop_part="${trimmed#*\{}"
|
||||
prop_part="${prop_part%\}}"
|
||||
|
||||
# Get all class names from the selector
|
||||
classes=""
|
||||
tmp="$sel_part"
|
||||
while [[ "$tmp" =~ \.([a-zA-Z_][a-zA-Z0-9_-]*) ]]; do
|
||||
cls="${BASH_REMATCH[1]}"
|
||||
classes="$classes $cls"
|
||||
tmp="${tmp#*${BASH_REMATCH[0]}}"
|
||||
done
|
||||
|
||||
# Use the first class as the component name
|
||||
first_cls=""
|
||||
for c in $classes; do first_cls="$c"; break; done
|
||||
[[ -z "$first_cls" ]] && continue
|
||||
|
||||
current_selector="$first_cls"
|
||||
current_line=$lineno
|
||||
current_classes="$classes"
|
||||
current_spacing=""
|
||||
current_fontsize=""
|
||||
current_breakpoints=""
|
||||
[[ -n "$media_breakpoint" ]] && current_breakpoints="$media_breakpoint"
|
||||
|
||||
# Check inline properties (single-line rules like .foo { padding: ...; })
|
||||
if [[ -n "$prop_part" ]]; then
|
||||
# Extract spacing tokens
|
||||
sp_tmp="$prop_part"
|
||||
while [[ "$sp_tmp" =~ var\(--sp-([0-9h]+)\) ]]; do
|
||||
current_spacing="$current_spacing --sp-${BASH_REMATCH[1]}"
|
||||
sp_tmp="${sp_tmp#*${BASH_REMATCH[0]}}"
|
||||
done
|
||||
# Extract font-size
|
||||
if [[ "$prop_part" =~ font-size:[[:space:]]*([^;]+) ]]; then
|
||||
fs_val="${BASH_REMATCH[1]}"
|
||||
fs_val="${fs_val%"${fs_val##*[![:space:]]}"}"
|
||||
current_fontsize="$current_fontsize $fs_val"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If the rule is self-closing (has } on the same line), emit now
|
||||
if [[ "$trimmed" == *"}"* ]]; then
|
||||
bp_json="[]"
|
||||
if [[ -n "$current_breakpoints" ]]; then
|
||||
bp_json="[\"$current_breakpoints\"]"
|
||||
fi
|
||||
sp_json="[]"
|
||||
if [[ -n "$current_spacing" ]]; then
|
||||
sp_json="["
|
||||
sp_first=true
|
||||
seen_sp=""
|
||||
for sp in $current_spacing; do
|
||||
[[ " $seen_sp " == *" $sp "* ]] && continue
|
||||
seen_sp="$seen_sp $sp"
|
||||
$sp_first && sp_first=false || sp_json="$sp_json,"
|
||||
sp_json="$sp_json\"$sp\""
|
||||
done
|
||||
sp_json="$sp_json]"
|
||||
fi
|
||||
fs_json="[]"
|
||||
if [[ -n "$current_fontsize" ]]; then
|
||||
fs_json="["
|
||||
fs_first=true
|
||||
for fs in $current_fontsize; do
|
||||
$fs_first && fs_first=false || fs_json="$fs_json,"
|
||||
fs_json="$fs_json\"$fs\""
|
||||
done
|
||||
fs_json="$fs_json]"
|
||||
fi
|
||||
cls_json="["
|
||||
cls_first=true
|
||||
for cls in $current_classes; do
|
||||
$cls_first && cls_first=false || cls_json="$cls_json,"
|
||||
cls_json="$cls_json\"$cls\""
|
||||
done
|
||||
cls_json="$cls_json]"
|
||||
|
||||
$first_entry && first_entry=false || printf ",\n"
|
||||
printf ' {"surface":"%s","component":"%s","classes":%s,"file":"%s","line":%d,"responsive_breakpoints":%s,"spacing_tokens_used":%s,"font_size_tokens_used":%s}' \
|
||||
"$surface" "$current_selector" "$cls_json" "$relpath" "$current_line" "$bp_json" "$sp_json" "$fs_json"
|
||||
|
||||
current_selector=""
|
||||
current_classes=""
|
||||
current_spacing=""
|
||||
current_fontsize=""
|
||||
current_breakpoints=""
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
# Property line inside an open block
|
||||
if [[ -n "$current_selector" ]]; then
|
||||
# Extract spacing tokens
|
||||
sp_tmp="$trimmed"
|
||||
while [[ "$sp_tmp" =~ var\(--sp-([0-9h]+)\) ]]; do
|
||||
current_spacing="$current_spacing --sp-${BASH_REMATCH[1]}"
|
||||
sp_tmp="${sp_tmp#*${BASH_REMATCH[0]}}"
|
||||
done
|
||||
# Extract font-size
|
||||
if [[ "$trimmed" =~ font-size:[[:space:]]*([^;]+) ]]; then
|
||||
fs_val="${BASH_REMATCH[1]}"
|
||||
fs_val="${fs_val%"${fs_val##*[![:space:]]}"}"
|
||||
current_fontsize="$current_fontsize $fs_val"
|
||||
fi
|
||||
fi
|
||||
|
||||
done < "$f"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "]"
|
||||
Reference in New Issue
Block a user