website-htmx-rustelo-code/scripts/sh/content/validate-id-consistency.sh

370 lines
11 KiB
Bash
Raw Permalink Normal View History

2026-07-10 03:44:13 +01:00
#!/bin/bash
# Content ID Consistency Validator
# This script validates that content IDs are consistent between language versions
# It should be run during content generation to catch ID mismatches early
set -e
# Configuration
CONTENT_DIR="content"
CONTENT_KINDS_FILE="content/content-kinds.toml"
# Supported languages
LANGUAGES=("en" "es")
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Get enabled content types from content-kinds.toml
get_content_types() {
if [ ! -f "$CONTENT_KINDS_FILE" ]; then
echo "blog recipes" # fallback
return
fi
# Extract content type names from TOML where enabled = true
grep -A 10 "^\[\[content_kinds\]\]" "$CONTENT_KINDS_FILE" | \
awk '
/^\[\[content_kinds\]\]/ { in_section = 1; name = ""; enabled = ""; next }
/^name = / { if (in_section) { name = $3; gsub(/["'"'"']/, "", name) } }
/^enabled = / { if (in_section) { enabled = $3; gsub(/["'"'"']/, "", enabled) } }
/^$/ || /^\[/ {
if (in_section && name && enabled == "true") print name
in_section = 0; name = ""; enabled = ""
}
END { if (in_section && name && enabled == "true") print name }
' | tr '\n' ' '
}
# Helper functions
log_error() {
echo -e "${RED}❌ ERROR: $1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ WARNING: $1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_info() {
echo -e "${BLUE} $1${NC}"
}
log_step() {
echo -e "${CYAN}🔧 $1${NC}"
}
# Extract ID from markdown frontmatter
extract_id() {
local file="$1"
if [ ! -f "$file" ]; then
echo ""
return
fi
# Extract ID from YAML frontmatter
if head -1 "$file" | grep -q "^---$"; then
awk '/^---$/{flag++; next} flag==1 && /^---$/{flag++} flag==1 && /^id:/{print $2; exit}' "$file" | sed 's/["\047]//g'
fi
}
# Extract filename without extension
get_filename() {
local file="$1"
basename "$file" .md
}
# Validate ID consistency for a content type
validate_content_type() {
local content_type="$1"
local errors=0
local warnings=0
log_step "Validating $content_type ID consistency..."
# Get the primary language directory (English)
local primary_lang="en"
local primary_dir="${CONTENT_DIR}/${content_type}/${primary_lang}"
if [ ! -d "$primary_dir" ]; then
log_error "Primary language directory not found: $primary_dir"
return 1
fi
# Create temporary files for tracking
local temp_dir="/tmp/id_validation_$$"
mkdir -p "$temp_dir"
# Process each markdown file in primary language
for primary_file in "$primary_dir"/*.md; do
if [ ! -f "$primary_file" ]; then
continue
fi
local filename=$(get_filename "$primary_file")
local primary_id=$(extract_id "$primary_file")
if [ -z "$primary_id" ]; then
log_warning "No ID found in primary file: $primary_file"
warnings=$((warnings + 1))
continue
fi
log_info "Checking $content_type: $filename (ID: $primary_id)"
# Check corresponding files in other languages
for lang in "${LANGUAGES[@]}"; do
if [ "$lang" = "$primary_lang" ]; then
continue
fi
local lang_dir="${CONTENT_DIR}/${content_type}/${lang}"
local lang_file="${lang_dir}/${filename}.md"
if [ ! -f "$lang_file" ]; then
log_warning "Missing $lang translation for $filename"
warnings=$((warnings + 1))
continue
fi
local lang_id=$(extract_id "$lang_file")
if [ -z "$lang_id" ]; then
log_error "No ID found in $lang file: $lang_file"
errors=$((errors + 1))
continue
fi
if [ "$primary_id" != "$lang_id" ]; then
log_error "ID mismatch for $filename:"
log_error " $primary_lang: '$primary_id'"
log_error " $lang: '$lang_id'"
log_error " Files: $primary_file <-> $lang_file"
errors=$((errors + 1))
# Store mismatch for summary
echo "$content_type,$filename,$primary_lang,$primary_id,$lang,$lang_id" >> "$temp_dir/mismatches.csv"
else
log_success "$lang: $lang_id"
fi
done
done
# Generate summary
if [ -f "$temp_dir/mismatches.csv" ]; then
echo ""
log_error "ID MISMATCHES FOUND:"
echo -e "${RED}Content Type | Filename | ${primary_lang} ID | Other Lang | Other ID${NC}"
echo -e "${RED}-------------|----------|--------|-----------|--------${NC}"
while IFS=',' read -r content_type filename primary_lang primary_id other_lang other_id; do
echo -e "${RED}$content_type | $filename | $primary_id | $other_lang | $other_id${NC}"
done < "$temp_dir/mismatches.csv"
echo ""
fi
# Cleanup
rm -rf "$temp_dir"
if [ $errors -gt 0 ]; then
log_error "$content_type validation failed with $errors errors and $warnings warnings"
return 1
elif [ $warnings -gt 0 ]; then
log_warning "$content_type validation completed with $warnings warnings"
return 0
else
log_success "$content_type validation passed - all IDs are consistent"
return 0
fi
}
# Generate fix suggestions
generate_fix_suggestions() {
local content_type="$1"
local primary_lang="en"
local primary_dir="${CONTENT_DIR}/${content_type}/${primary_lang}"
echo ""
log_step "Generating fix suggestions for $content_type..."
for primary_file in "$primary_dir"/*.md; do
if [ ! -f "$primary_file" ]; then
continue
fi
local filename=$(get_filename "$primary_file")
local primary_id=$(extract_id "$primary_file")
if [ -z "$primary_id" ]; then
continue
fi
for lang in "${LANGUAGES[@]}"; do
if [ "$lang" = "$primary_lang" ]; then
continue
fi
local lang_file="${CONTENT_DIR}/${content_type}/${lang}/${filename}.md"
if [ ! -f "$lang_file" ]; then
continue
fi
local lang_id=$(extract_id "$lang_file")
if [ -n "$lang_id" ] && [ "$primary_id" != "$lang_id" ]; then
echo ""
log_info "Fix command for $filename ($lang):"
echo " sed -i 's/^id: \"$lang_id\"/id: \"$primary_id\"/' \"$lang_file\""
echo " # OR use your editor to change ID from '$lang_id' to '$primary_id'"
fi
done
done
}
# Check for duplicate IDs within a language
check_duplicate_ids() {
local content_type="$1"
local lang="$2"
local content_dir="${CONTENT_DIR}/${content_type}/${lang}"
if [ ! -d "$content_dir" ]; then
return 0
fi
local temp_file="/tmp/ids_${content_type}_${lang}_$$"
# Extract all IDs
for md_file in "$content_dir"/*.md; do
if [ -f "$md_file" ]; then
local id=$(extract_id "$md_file")
if [ -n "$id" ]; then
echo "$id|$(basename "$md_file")" >> "$temp_file"
fi
fi
done
if [ ! -f "$temp_file" ]; then
return 0
fi
# Check for duplicates
local duplicates=$(cut -d'|' -f1 "$temp_file" | sort | uniq -d)
if [ -n "$duplicates" ]; then
log_error "Duplicate IDs found in $content_type ($lang):"
echo "$duplicates" | while read -r duplicate_id; do
log_error " ID '$duplicate_id' used in:"
grep "^$duplicate_id|" "$temp_file" | cut -d'|' -f2 | while read -r filename; do
log_error " - $filename"
done
done
rm -f "$temp_file"
return 1
fi
rm -f "$temp_file"
return 0
}
# Main validation function
main() {
echo "🔍 Content ID Consistency Validator"
echo "===================================="
echo ""
# Get enabled content types dynamically
local content_types=($(get_content_types))
log_info "Enabled content types: ${content_types[*]}"
echo ""
local total_errors=0
local has_suggestions=false
# Check for duplicate IDs within each language
log_step "Checking for duplicate IDs within languages..."
for content_type in "${content_types[@]}"; do
for lang in "${LANGUAGES[@]}"; do
if ! check_duplicate_ids "$content_type" "$lang"; then
total_errors=$((total_errors + 1))
fi
done
done
# Validate cross-language ID consistency
for content_type in "${content_types[@]}"; do
if ! validate_content_type "$content_type"; then
total_errors=$((total_errors + 1))
has_suggestions=true
fi
done
# Generate fix suggestions if there were errors
if [ "$has_suggestions" = true ]; then
for content_type in "${content_types[@]}"; do
generate_fix_suggestions "$content_type"
done
fi
echo ""
echo "======================================"
if [ $total_errors -eq 0 ]; then
log_success "🎉 All content IDs are consistent across languages!"
echo ""
log_info "✅ Content integrity validated"
log_info "✅ No duplicate IDs found"
log_info "✅ Cross-language ID consistency confirmed"
exit 0
else
log_error "❌ Content validation failed with $total_errors issue(s)"
echo ""
log_error "REQUIRED ACTIONS:"
log_error "1. Fix ID mismatches using the suggested commands above"
log_error "2. Ensure all content has consistent IDs across languages"
log_error "3. Re-run this validator to confirm fixes"
log_error "4. Update your content generation process to prevent future mismatches"
echo ""
log_info "💡 TIP: Use 'id' for cross-language lookup and 'slug' for URLs"
log_info "💡 TIP: Add this script to your CI/CD pipeline to catch issues early"
exit 1
fi
}
# Show usage if no arguments
if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
echo "Content ID Consistency Validator"
echo ""
echo "Usage: $0 [OPTIONS]"
echo ""
echo "This script validates that content IDs are consistent between language versions."
echo "It checks all enabled content types in all supported languages."
echo ""
echo "Options:"
echo " --help, -h Show this help message"
echo ""
echo "What it checks:"
echo " ✓ ID consistency across language versions"
echo " ✓ Duplicate IDs within the same language"
echo " ✓ Missing translations"
echo " ✓ Frontmatter format validation"
echo ""
echo "Integration:"
echo " Add to justfile: just validate-content-ids"
echo " Add to CI/CD pipeline for automated validation"
echo " Run before content deployment"
echo ""
exit 0
fi
# Run main validation
main "$@"