Skip to main content
Glama
by 8b-is
json.rs3.95 kB
use super::Formatter; use crate::scanner::{FileNode, TreeStats}; use anyhow::Result; use serde_json::{json, Value}; use std::collections::HashMap; use std::io::Write; use std::path::{Path, PathBuf}; pub struct JsonFormatter { pub compact: bool, } impl JsonFormatter { pub fn new(compact: bool) -> Self { Self { compact } } fn build_json_tree(&self, nodes: &[FileNode], root_path: &Path) -> Value { // Build parent-child relationships let mut children_map: HashMap<PathBuf, Vec<&FileNode>> = HashMap::new(); let mut root_node = None; for node in nodes { if node.path == root_path { root_node = Some(node); } else if let Some(parent) = node.path.parent() { children_map .entry(parent.to_path_buf()) .or_default() .push(node); } } fn node_to_json( node: &FileNode, children_map: &HashMap<PathBuf, Vec<&FileNode>>, _root_path: &Path, ) -> Value { let name = node .path .file_name() .unwrap_or(node.path.as_os_str()) .to_string_lossy() .to_string(); let mut obj = json!({ "name": name, "type": match node.file_type { crate::scanner::FileType::Directory => "directory", crate::scanner::FileType::RegularFile => "file", crate::scanner::FileType::Symlink => "symlink", crate::scanner::FileType::Executable => "executable", crate::scanner::FileType::Socket => "socket", crate::scanner::FileType::Pipe => "pipe", crate::scanner::FileType::BlockDevice => "block_device", crate::scanner::FileType::CharDevice => "char_device", }, }); // Only add size for files, not directories if !node.is_dir { obj["size"] = json!(node.size); } // Add flags only if they're true if node.permission_denied { obj["permission_denied"] = json!(true); } if node.is_ignored { obj["ignored"] = json!(true); } if node.is_hidden { obj["hidden"] = json!(true); } if node.is_symlink { obj["symlink"] = json!(true); } // Add children for directories if let Some(children) = children_map.get(&node.path) { let mut sorted_children = children.to_vec(); sorted_children.sort_by(|a, b| match (a.is_dir, b.is_dir) { (true, false) => std::cmp::Ordering::Less, (false, true) => std::cmp::Ordering::Greater, _ => a.path.file_name().cmp(&b.path.file_name()), }); obj["children"] = json!(sorted_children .iter() .map(|child| node_to_json(child, children_map, _root_path)) .collect::<Vec<_>>()); } obj } if let Some(root) = root_node { node_to_json(root, &children_map, root_path) } else { json!({}) } } } impl Formatter for JsonFormatter { fn format( &self, writer: &mut dyn Write, nodes: &[FileNode], _stats: &TreeStats, root_path: &Path, ) -> Result<()> { let json_tree = self.build_json_tree(nodes, root_path); if self.compact { writeln!(writer, "{}", serde_json::to_string(&json_tree)?)?; } else { writeln!(writer, "{}", serde_json::to_string_pretty(&json_tree)?)?; } Ok(()) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server