Add source files: main, lib, cli, error, convert, highlight, validate, typescript
Some checks failed
CI / test (push) Has been cancelled
CI / build (push) Has been cancelled

This commit is contained in:
2026-01-29 15:15:43 +00:00
parent d19554bdea
commit eec4635eba

196
src/highlight.rs Normal file
View File

@@ -0,0 +1,196 @@
use colored::Colorize;
pub fn highlight_value(value: &serde_json::Value, indent: usize) -> String {
let indent_str = " ".repeat(indent);
let next_indent = " ".repeat(indent + 1);
match value {
serde_json::Value::Null => format!("{}", indent_str).red().to_string(),
serde_json::Value::Bool(b) => {
if *b {
format!("{}", indent_str).magenta().bold().to_string()
} else {
format!("{}", indent_str).magenta().bold().to_string()
}
}
serde_json::Value::Number(n) => {
format!("{}{}", indent_str, n).yellow().to_string()
}
serde_json::Value::String(s) => {
format!("{}{}", indent_str, format!("\"{s}\"").green().to_string())
}
serde_json::Value::Array(arr) => {
if arr.is_empty() {
format!("{}", indent_str).cyan().to_string()
} else {
let mut result = format!("{}", indent_str).cyan().to_string();
for (i, item) in arr.iter().enumerate() {
result.push('\n');
result.push_str(&highlight_value(item, indent + 1));
if i < arr.len() - 1 {
result.push(',');
}
}
result.push('\n');
result.push_str(&format!("{}", indent_str).cyan().to_string());
result
}
}
serde_json::Value::Object(map) => {
if map.is_empty() {
format!("{}", indent_str).cyan().to_string()
} else {
let mut result = format!("{}", indent_str).cyan().to_string();
let entries: Vec<_> = map.iter().collect();
for (i, (key, value)) in entries.iter().enumerate() {
result.push('\n');
result.push_str(&format!("{}", key.cyan().bold().to_string()));
result.push_str(": ");
result.push_str(&highlight_value(value, indent + 1));
if i < entries.len() - 1 {
result.push(',');
}
}
result.push('\n');
result.push_str(&format!("{}", "}".cyan().to_string()));
result
}
}
}
}
pub fn highlight_yaml(content: &str) -> String {
let lines: Vec<&str> = content.lines().collect();
let mut result = String::new();
let mut indent_level = 0;
for line in lines {
let trimmed = line.trim_start();
let current_indent = line.len() - trimmed.len();
while current_indent < indent_level * 2 && indent_level > 0 {
indent_level -= 1;
result.push_str(&format!("{}{}}}", " ".repeat(indent_level), "}".cyan().to_string()));
result.push('\n');
}
if trimmed.is_empty() {
result.push('\n');
continue;
}
if trimmed.starts_with('#') {
result.push_str(&format!("{}{}", " ".repeat(indent_level), line.gray()));
continue;
}
if trimmed.ends_with(':') {
let key = trimmed.trim_end_matches(':');
result.push_str(&format!("{}{}:", " ".repeat(indent_level), key.cyan().bold()));
result.push('\n');
indent_level += 1;
} else if let Some(colon_idx) = trimmed.find(':') {
let key = &trimmed[..colon_idx].trim();
let value = &trimmed[colon_idx + 1..].trim();
result.push_str(&" ".repeat(indent_level));
result.push_str(&key.cyan().bold().to_string());
result.push_str(": ");
if value.is_empty() {
result.push('\n');
} else {
result.push_str(&highlight_yaml_value(value));
result.push('\n');
}
} else {
result.push_str(&format!("{}{}", " ".repeat(indent_level), trimmed));
result.push('\n');
}
}
while indent_level > 0 {
indent_level -= 1;
result.push_str(&format!("{}{}}}", " ".repeat(indent_level), "}".cyan().to_string()));
result.push('\n');
}
result
}
fn highlight_yaml_value(value: &str) -> String {
let trimmed = value.trim();
if trimmed.starts_with('"') && trimmed.ends_with('"') {
let inner = &trimmed[1..trimmed.len() - 1];
format!("\"{}\"", inner.green())
} else if trimmed.starts_with("'") && trimmed.ends_with("'") {
let inner = &trimmed[1..trimmed.len() - 1];
format!("'{}'", inner.green())
} else if trimmed == "true" || trimmed == "false" {
trimmed.magenta().bold().to_string()
} else if trimmed == "null" || trimmed == "~" {
trimmed.red().to_string()
} else if trimmed.parse::<f64>().is_ok() {
trimmed.yellow().to_string()
} else {
trimmed.green().to_string()
}
}
pub fn highlight_ini(content: &str) -> String {
let lines: Vec<&str> = content.lines().collect();
let mut result = String::new();
let mut in_section = false;
for line in lines {
let trimmed = line.trim();
if trimmed.is_empty() {
result.push('\n');
continue;
}
if trimmed.starts_with('[') && trimmed.ends_with(']') {
result.push_str(&format!("[{}]\n", trimmed[1..trimmed.len() - 1].cyan().bold()));
in_section = true;
} else if trimmed.starts_with('#') || trimmed.starts_with(';') {
result.push_str(&format!("{}\n", line.gray()));
} else if let Some(eq_idx) = trimmed.find('=') {
let key = &trimmed[..eq_idx].trim();
let value = &trimmed[eq_idx + 1..].trim();
result.push_str(&key.cyan().bold().to_string());
result.push_str(" = ");
result.push_str(&value.green().to_string());
result.push('\n');
} else {
result.push_str(line);
result.push('\n');
}
}
result
}
pub fn highlight_env(content: &str) -> String {
let lines: Vec<&str> = content.lines().collect();
let mut result = String::new();
for line in lines {
let trimmed = line.trim();
if trimmed.is_empty() || trimmed.starts_with('#') {
result.push_str(&format!("{}\n", line.gray()));
} else if let Some(eq_idx) = trimmed.find('=') {
let key = &trimmed[..eq_idx].trim();
let value = &trimmed[eq_idx + 1..].trim();
result.push_str(&format!("{}", key.cyan().bold()));
result.push_str("=");
result.push_str(&format!("{}\n", value.green().to_string()));
} else {
result.push_str(line);
result.push('\n');
}
}
result
}