bevy_xray_parser 0.1.0

Parse Bevy source code to extract state hierarchies, plugin dependencies, and schedule configurations
Documentation
use std::path::PathBuf;

use bevy_xray_parser::graph;
use bevy_xray_parser::parser;

fn main() {
    let path = std::env::args()
        .nth(1)
        .map(PathBuf::from)
        .unwrap_or_else(|| PathBuf::from("."));

    let path = path.canonicalize().unwrap_or_else(|e| {
        eprintln!("Cannot resolve path '{}': {e}", path.display());
        std::process::exit(1);
    });

    let state_graph = match parser::parse_workspace(&path) {
        Ok(g) => g,
        Err(e) => {
            eprintln!("Parse error: {e}");
            std::process::exit(1);
        }
    };

    // --- States ---
    println!("States ({})", state_graph.states.len());
    for state in &state_graph.states {
        let kind = match &state.kind {
            bevy_xray_parser::model::StateKind::Root => "Root".to_string(),
            bevy_xray_parser::model::StateKind::Sub {
                source_state,
                source_variant,
            } => format!("Sub({source_state}::{source_variant})"),
            bevy_xray_parser::model::StateKind::Computed { source_states } => {
                format!("Computed({})", source_states.join(", "))
            }
        };
        println!("  {} [{}]", state.name, kind);
    }

    // --- Plugins ---
    println!("\nPlugins ({})", state_graph.plugins.len());
    for plugin in &state_graph.plugins {
        println!("  {}{}", plugin.name, plugin.crate_name);
        for sub in &plugin.sub_plugins {
            println!("    sub: {sub}");
        }
    }

    // --- System Sets ---
    println!("\nSystem Sets ({})", state_graph.system_sets.len());
    for set in &state_graph.system_sets {
        println!("  {}{}", set.name, set.crate_name);
    }

    // --- Plugin Tree ---
    let tree = graph::build_plugin_tree(&state_graph);
    println!("\nPlugin Dependency Tree ({} roots)", tree.len());
    fn print_tree(node: &graph::PluginTreeNode, depth: usize) {
        let indent = "  ".repeat(depth);
        let marker = if node.is_group { "[G] " } else { "" };
        println!("{indent}{marker}{}", node.display_name);
        for child in &node.children {
            print_tree(child, depth + 1);
        }
    }
    for root in &tree {
        print_tree(root, 1);
    }
}