use crate::tools::libdcf_info::{parse_dcf_info, DcfError};
use clap::Parser;
use dc_bundle::definition_file::load_design_def;
use serde::Serialize;
use std::fs::File;
use std::io::{self, Read, Write};
use std::mem;
#[derive(Debug)]
#[allow(dead_code)]
pub struct ParseError(pub String);
impl From<std::io::Error> for ParseError {
fn from(e: std::io::Error) -> Self {
eprintln!("Error opening file: {:?}", e);
ParseError(format!("Error opening file: {:?}", e))
}
}
impl From<dc_bundle::Error> for ParseError {
fn from(e: dc_bundle::Error) -> Self {
eprintln!("Error during deserialization: {:?}", e);
ParseError(format!("Error during deserialization: {:?}", e))
}
}
impl From<DcfError> for ParseError {
fn from(e: DcfError) -> Self {
match e {
DcfError::Io(e) => e.into(),
DcfError::DcBundle(e) => e.into(),
DcfError::Parse(s) => ParseError(s),
}
}
}
#[derive(Parser, Debug)]
pub struct Args {
pub dcf_file: std::path::PathBuf,
#[clap(long, short)]
pub node: Option<String>,
#[clap(long)]
pub varinfo: bool,
#[clap(long)]
pub json: bool,
#[clap(long, short)]
pub output: Option<std::path::PathBuf>,
}
pub fn dcf_info(args: Args) -> Result<(), ParseError> {
let file_path = &args.dcf_file;
let node = args.node;
let mut writer: Box<dyn Write> = match args.output {
Some(path) => Box::new(File::create(path)?),
None => Box::new(io::stdout()),
};
if args.json {
match parse_dcf_info(file_path) {
Ok(info) => match serde_json::to_string(&info) {
Ok(json_string) => {
writeln!(writer, "{}", json_string)?;
}
Err(e) => {
#[derive(Serialize)]
struct ErrorWrapper {
error: String,
}
let err_json = serde_json::to_string(&ErrorWrapper {
error: format!("Error serializing: {:?}", e),
})
.unwrap();
writeln!(writer, "{}", err_json)?;
}
},
Err(e) => {
#[derive(Serialize)]
struct ErrorDetail {
message: String,
}
#[derive(Serialize)]
struct ErrorWrapper {
error: ErrorDetail,
}
let err_json = serde_json::to_string(&ErrorWrapper {
error: ErrorDetail { message: format!("{:?}", e) },
})
.unwrap();
writeln!(writer, "{}", err_json)?;
}
}
return Ok(());
}
let mut file = File::open(file_path)?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer)?;
let load_result = load_design_def(file_path);
if let Ok((header, doc)) = load_result {
writeln!(writer, "Deserialized file")?;
writeln!(writer, " DC Version: {}", header.dc_version)?;
writeln!(writer, " Doc ID: {}", header.id)?;
writeln!(writer, " Figma Version: {}", header.response_version)?;
writeln!(writer, " Name: {}", header.name)?;
writeln!(writer, " Last Modified: {}", header.last_modified)?;
if args.varinfo {
if let Some(variable_map) = doc.variable_map.as_ref() {
writeln!(writer, "Variables: {:#?}", variable_map)?;
}
}
if let Some(node) = node {
writeln!(writer, "Dumping file from node: {}:", node)?;
if let Some(view) =
doc.views.get(&dc_bundle::definition::NodeQuery::name(&node).encode())
{
writeln!(writer, "{:#?}", view)?;
} else {
return Err(ParseError(format!("Node: {} not found in document.", node)));
}
}
} else {
let mut document_file = File::open(file_path)?;
let mut buffer = [0; mem::size_of::<u32>()]; document_file.read_exact(&mut buffer)?;
let version = u32::from_le_bytes(buffer);
if version < 27 {
writeln!(writer, "DC Version: {}", version)?;
writeln!(
writer,
"DCF files version < 27 do not have additional information to parse."
)?;
} else {
eprintln!("Failed to load file {:?}", file_path);
return Err(ParseError(format!("Failed to load file {:?}", file_path)));
}
}
Ok(())
}