website-htmx-rustelo-code/scripts/sh/content/content-manager.sh

392 lines
13 KiB
Bash
Raw Permalink Normal View History

2026-07-10 03:44:13 +01:00
#!/bin/bash
# Unified Content Management Script
# Replaces: generate-index.sh, validate-id-consistency.sh, validate-content.sh
# Usage: ./content-manager.sh [command] [options]
set -e
# Get script directory and load shared library
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib.sh"
# =============================================================================
# COMMAND FUNCTIONS
# =============================================================================
# Generate JSON indices from markdown frontmatter
cmd_generate_indices() {
log_step "Generating content indices..."
local content_types=($(get_enabled_content_types))
local languages=($(get_supported_languages))
local total_errors=0
for content_type in "${content_types[@]}"; do
for language in "${languages[@]}"; do
if ! content_dir_exists "$content_type" "$language"; then
log_warning "Content directory not found: ${CONTENT_DIR}/${content_type}/${language}"
continue
fi
log_step "Generating $content_type index for language: $language"
local content_dir="${CONTENT_DIR}/${content_type}/${language}"
local index_file="$content_dir/index.json"
local temp_entries="/tmp/index_entries_$$"
local entry_count=0
# Clear temp file
> "$temp_entries"
# Process each markdown file
for md_file in $(get_markdown_files "$content_type" "$language"); do
if process_markdown_file "$md_file" "$content_type" "$language" > /tmp/json_entry_$$; then
# Add comma if not first entry
if [ $entry_count -gt 0 ]; then
echo "," >> "$temp_entries"
fi
cat /tmp/json_entry_$$ >> "$temp_entries"
entry_count=$((entry_count + 1))
rm -f /tmp/json_entry_$$
else
log_warning "Failed to process: $md_file"
fi
done
# Determine array name (keep legacy naming for recipes)
local array_name="${content_type}_posts"
if [ "$content_type" = "recipes" ]; then
array_name="prescriptions" # Keep legacy array name for recipes
fi
# Build final index.json
cat > "$index_file" << EOF
{
"$array_name": [
$(cat "$temp_entries")
],
"language": "$language"
}
EOF
# Validate JSON
if validate_json "$index_file"; then
log_success "Generated valid $content_type index ($language): $entry_count entries"
else
log_error "Generated invalid JSON for $content_type ($language)"
total_errors=$((total_errors + 1))
fi
# Cleanup
rm -f "$temp_entries"
done
done
if [ $total_errors -eq 0 ]; then
log_success "🎉 Index generation completed successfully!"
else
log_error "Index generation completed with $total_errors errors"
exit 1
fi
}
# Validate ID consistency across languages
cmd_validate_ids() {
log_step "Validating ID consistency across languages..."
local content_types=($(get_enabled_content_types))
local languages=($(get_supported_languages))
local total_errors=0
local primary_lang="en"
for content_type in "${content_types[@]}"; do
log_step "Validating $content_type ID consistency..."
local primary_dir="${CONTENT_DIR}/${content_type}/${primary_lang}"
if [ ! -d "$primary_dir" ]; then
log_error "Primary language directory not found: $primary_dir"
total_errors=$((total_errors + 1))
continue
fi
local temp_ids="/tmp/id_validation_${content_type}_$$"
> "$temp_ids"
# Collect all IDs from primary language
for primary_file in $(get_markdown_files "$content_type" "$primary_lang"); do
local filename=$(basename "$primary_file" .md)
local primary_id=$(extract_id "$primary_file")
if [ -z "$primary_id" ]; then
log_warning "No ID found in primary file: $primary_file"
continue
fi
echo "$filename:$primary_id" >> "$temp_ids"
# Check corresponding files in other languages
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
log_warning "Missing $lang translation for $filename"
continue
fi
local lang_id=$(extract_id "$lang_file")
if [ -z "$lang_id" ]; then
log_error "No ID found in $lang file: $lang_file"
total_errors=$((total_errors + 1))
continue
fi
if [ "$primary_id" != "$lang_id" ]; then
log_error "ID mismatch for $filename: $primary_lang='$primary_id' vs $lang='$lang_id'"
total_errors=$((total_errors + 1))
fi
done
done
# Check for duplicate IDs within each language
for lang in "${languages[@]}"; do
if ! content_dir_exists "$content_type" "$lang"; then
continue
fi
local temp_lang_ids="/tmp/lang_ids_${content_type}_${lang}_$$"
> "$temp_lang_ids"
for md_file in $(get_markdown_files "$content_type" "$lang"); do
local file_id=$(extract_id "$md_file")
if [ -n "$file_id" ]; then
echo "$file_id" >> "$temp_lang_ids"
fi
done
# Check for duplicates
local duplicates=$(sort "$temp_lang_ids" | uniq -d)
if [ -n "$duplicates" ]; then
echo "$duplicates" | while read -r duplicate_id; do
log_error "Duplicate ID '$duplicate_id' found in $content_type ($lang)"
total_errors=$((total_errors + 1))
done
fi
rm -f "$temp_lang_ids"
done
rm -f "$temp_ids"
done
if [ $total_errors -eq 0 ]; then
log_success "🎉 All content IDs are consistent across languages!"
else
log_error "❌ Content validation failed with $total_errors issue(s)"
exit 1
fi
}
# Validate content structure and quality
cmd_validate_content() {
log_step "Validating content structure and quality..."
local content_types=($(get_enabled_content_types))
local languages=($(get_supported_languages))
local total_issues=0
for content_type in "${content_types[@]}"; do
for language in "${languages[@]}"; do
if ! content_dir_exists "$content_type" "$language"; then
log_warning "Content directory not found: ${CONTENT_DIR}/${content_type}/${language}"
continue
fi
log_step "Validating $content_type content for language: $language"
local issues_found=0
# Check for index.json
local index_file="${CONTENT_DIR}/${content_type}/${language}/index.json"
if [ -f "$index_file" ]; then
if validate_json "$index_file"; then
log_success "Valid index.json for $content_type ($language)"
else
log_error "Invalid index.json for $content_type ($language)"
issues_found=$((issues_found + 1))
fi
else
log_warning "No index.json found for $content_type ($language)"
issues_found=$((issues_found + 1))
fi
# Validate markdown files
local md_files=($(get_markdown_files "$content_type" "$language"))
local valid_files=0
for md_file in "${md_files[@]}"; do
if has_valid_frontmatter "$md_file"; then
valid_files=$((valid_files + 1))
else
log_error "Invalid or missing frontmatter: $md_file"
issues_found=$((issues_found + 1))
fi
done
log_info "$content_type ($language): $valid_files/${#md_files[@]} files with valid frontmatter"
total_issues=$((total_issues + issues_found))
done
done
if [ $total_issues -eq 0 ]; then
log_success "🎉 All content validation passed!"
else
log_error "❌ Content validation found $total_issues issue(s)"
exit 1
fi
}
# Show content statistics
cmd_stats() {
log_step "Generating content statistics..."
local content_types=($(get_enabled_content_types))
local languages=($(get_supported_languages))
echo ""
echo "📊 Content Statistics:"
echo "======================"
for content_type in "${content_types[@]}"; do
echo ""
echo "📝 Content Type: $content_type"
echo "--------------------------------"
local total_files=0
for language in "${languages[@]}"; do
if content_dir_exists "$content_type" "$language"; then
local md_files=($(get_markdown_files "$content_type" "$language"))
local count=${#md_files[@]}
echo " $language: $count files"
total_files=$((total_files + count))
else
echo " $language: 0 files (directory not found)"
fi
done
echo " Total: $total_files files"
done
echo ""
echo "🌍 Languages: ${languages[*]}"
echo "📂 Content Types: ${content_types[*]}"
echo "📍 Content Directory: $CONTENT_DIR"
}
# =============================================================================
# MAIN COMMAND DISPATCHER
# =============================================================================
show_help() {
cat << EOF
Unified Content Management Script
Usage: $0 [command] [options]
Commands:
generate-indices Generate index.json files from markdown frontmatter
validate-ids Validate ID consistency across languages
validate-content Validate content structure and quality
stats Show content statistics
all Run generate-indices, validate-ids, and validate-content
help Show this help message
Options:
--content-dir DIR Content directory (default: content)
--verbose Enable verbose output
Examples:
$0 generate-indices
$0 validate-ids
$0 validate-content
$0 all
$0 stats
This script replaces the previous separate scripts:
- generate-index.sh
- validate-id-consistency.sh
- validate-content.sh
The script automatically reads content types from content-kinds.toml
and supports all enabled content types and languages.
EOF
}
# Parse command line arguments
VERBOSE=false
CONTENT_DIR_OVERRIDE=""
while [[ $# -gt 0 ]]; do
case $1 in
--content-dir)
CONTENT_DIR_OVERRIDE="$2"
shift 2
;;
--verbose)
VERBOSE=true
shift
;;
--help|-h|help)
show_help
exit 0
;;
*)
COMMAND="$1"
shift
;;
esac
done
# Override content directory if specified
if [ -n "$CONTENT_DIR_OVERRIDE" ]; then
CONTENT_DIR="$CONTENT_DIR_OVERRIDE"
CONTENT_KINDS_FILE="${CONTENT_DIR}/content-kinds.toml"
fi
# Initialize library
init_content_lib "content-manager"
# Execute command
case "${COMMAND:-help}" in
generate-indices|indices|index)
cmd_generate_indices
;;
validate-ids|validate-id|ids)
cmd_validate_ids
;;
validate-content|validate|content)
cmd_validate_content
;;
stats|statistics|info)
cmd_stats
;;
all|full)
cmd_generate_indices
echo ""
cmd_validate_ids
echo ""
cmd_validate_content
;;
help|--help|-h)
show_help
;;
*)
log_error "Unknown command: $COMMAND"
echo ""
show_help
exit 1
;;
esac