#!/bin/bash # Populate content index.json files from existing markdown files # This script scans all markdown files in content directories and creates proper JSON index files set -e # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}ℹ️ $1${NC}"; } log_success() { echo -e "${GREEN}✅ $1${NC}"; } log_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; } CONTENT_DIR="content" TEMP_DIR="/tmp/content-indices" # Create temp directory mkdir -p "$TEMP_DIR" # Function to extract YAML frontmatter from markdown file extract_frontmatter() { local file="$1" awk '/^---$/{p++} p==1 && !/^---$/ {print} p==2{exit}' "$file" } # Function to parse YAML value parse_yaml_value() { local file="$1" local key="$2" extract_frontmatter "$file" | grep "^${key}:" | sed "s/^${key}: *//g" | sed 's/^"//g' | sed 's/"$//g' | head -1 } # Function to parse YAML array parse_yaml_array() { local file="$1" local key="$2" extract_frontmatter "$file" | sed -n "/^${key}:/,/^[^ ]/p" | grep "^ *-" | sed 's/^ *- *//g' | sed 's/^"//g' | sed 's/"$//g' | tr '\n' ',' | sed 's/,$//g' } # Function to generate JSON entry from markdown file generate_json_entry() { local md_file="$1" local content_type="$2" local language="$3" # Extract metadata local id=$(parse_yaml_value "$md_file" "id") local title=$(parse_yaml_value "$md_file" "title") local slug=$(parse_yaml_value "$md_file" "slug") local excerpt=$(parse_yaml_value "$md_file" "excerpt") local created_at=$(parse_yaml_value "$md_file" "date") local read_time=$(parse_yaml_value "$md_file" "read_time") local featured=$(parse_yaml_value "$md_file" "featured") local tags=$(parse_yaml_array "$md_file" "tags") local categories=$(parse_yaml_array "$md_file" "categories") # Generate ID from filename if not found in frontmatter if [ -z "$id" ]; then id=$(basename "$md_file" .md) fi # Generate slug from ID if not found if [ -z "$slug" ]; then slug="$id" fi # Default values and escape quotes for JSON title=$(echo "${title:-Untitled}" | sed 's/"/\\"/g') excerpt=$(echo "${excerpt:-}" | sed 's/"/\\"/g') created_at=${created_at:-$(date +"%Y-%m-%d")} read_time=${read_time:-"5 min read"} featured=${featured:-false} # Infer category from file path if not in frontmatter if [ -z "$categories" ]; then local dir_path=$(dirname "$md_file") local category=$(basename "$dir_path") if [ "$category" != "$language" ] && [ "$category" != "." ]; then categories="$category" fi fi # Format arrays for JSON local tags_json="" if [ -n "$tags" ]; then tags_json="\"$(echo "$tags" | sed 's/,/","/g')\"" fi local categories_json="" if [ -n "$categories" ]; then categories_json="\"$(echo "$categories" | sed 's/,/","/g')\"" fi # Get content for full-text search (first 200 chars) and escape quotes local content=$(tail -n +10 "$md_file" | head -c 200 | tr '\n' ' ' | sed 's/"/\\"/g') # Use jq to create proper JSON jq -n \ --arg id "$id" \ --arg title "$title" \ --arg slug "$slug" \ --arg language "$language" \ --arg content_type "$content_type" \ --argjson categories "[${categories_json}]" \ --argjson tags "[${tags_json}]" \ --argjson featured "$featured" \ --arg excerpt "$excerpt" \ --arg content "$content" \ --arg created_at "$created_at" \ --arg read_time "$read_time" \ '{ id: $id, title: $title, slug: $slug, language: $language, content_type: $content_type, categories: $categories, tags: $tags, emoji: null, featured: $featured, excerpt: $excerpt, content: $content, created_at: $created_at, updated_at: null, read_time: $read_time }' } # Function to process content type directory process_content_type() { local content_type="$1" local content_type_dir="${CONTENT_DIR}/${content_type}" if [ ! -d "$content_type_dir" ]; then log_warning "Content type directory not found: $content_type_dir" return fi log_info "Processing content type: $content_type" # Process each language directory for lang_dir in "$content_type_dir"/*; do if [ -d "$lang_dir" ]; then local language=$(basename "$lang_dir") log_info " Processing language: $language" local temp_entries="$TEMP_DIR/${content_type}_${language}_entries.json" echo "[]" > "$temp_entries" # Find all markdown files in this directory and subdirectories find "$lang_dir" -name "*.md" -type f | while read -r md_file; do log_info " Processing: $(basename "$md_file")" # Generate JSON entry and save to temp file local entry_file="$TEMP_DIR/entry_$(basename "$md_file" .md).json" generate_json_entry "$md_file" "$content_type" "$language" > "$entry_file" # Add to temp entries file local temp_with_entry="$TEMP_DIR/temp_entry.json" jq --slurpfile entry "$entry_file" '. += $entry' "$temp_entries" > "$temp_with_entry" mv "$temp_with_entry" "$temp_entries" rm "$entry_file" done # Create final index file local index_file="${lang_dir}/index.json" local entries=$(cat "$temp_entries") cat > "$index_file" << EOF { "${content_type}": ${entries}, "language": "$language" } EOF local count=$(jq "length" "$temp_entries") log_success " Created index for $content_type/$language with $count entries" fi done } # Main execution log_info "Starting content index population..." # Check if content directory exists if [ ! -d "$CONTENT_DIR" ]; then log_warning "Content directory not found: $CONTENT_DIR" exit 1 fi # Check if jq is available if ! command -v jq &> /dev/null; then log_warning "jq is required but not installed. Please install jq." exit 1 fi # Process each content type process_content_type "blog" process_content_type "recipes" # Cleanup rm -rf "$TEMP_DIR" log_success "Content index population completed!" log_info "Run 'just dev' or rebuild the project to embed the updated indices."