diff --git a/src/wasm/headline.rs b/src/wasm/headline.rs index bd803f4..4e01435 100644 --- a/src/wasm/headline.rs +++ b/src/wasm/headline.rs @@ -5,14 +5,39 @@ use super::ast_node::WasmAstNode; use super::macros::to_wasm; use super::to_wasm::ToWasm; use super::AdditionalProperties; +use super::AdditionalPropertyValue; use crate::compare::ElispFact; use crate::types::Heading; +use crate::types::HeadlineLevel; +use crate::types::PriorityCookie; +use crate::types::TodoKeywordType; use crate::wasm::to_wasm::ToWasmStandardProperties; #[derive(Debug, Serialize, Deserialize)] pub struct WasmHeadline { #[serde(flatten)] pub(crate) additional_properties: AdditionalProperties, + pub(crate) level: HeadlineLevel, + pub(crate) tags: Vec, + #[serde(rename = "todo-keyword")] + pub(crate) todo_keyword: Option, + #[serde(rename = "todo-type")] + pub(crate) todo_type: Option, + pub(crate) title: Vec, + pub(crate) priority: Option, + #[serde(rename = "archivedp")] + pub(crate) is_archived: bool, + #[serde(rename = "commentedp")] + pub(crate) is_comment: bool, + #[serde(rename = "raw-value")] + pub(crate) raw_value: String, + #[serde(rename = "footnote-section-p")] + pub(crate) is_footnote_section: bool, + pub(crate) scheduled: Option>, + pub(crate) deadline: Option>, + pub(crate) closed: Option>, + #[serde(rename = "pre-blank")] + pub(crate) pre_blank: usize, } to_wasm!( @@ -21,8 +46,18 @@ to_wasm!( original, wasm_context, { WasmAstNode::Headline(original) }, - { "TODO".into() }, + { "headline".into() }, { + let mut additional_properties = AdditionalProperties::default(); + for (name, val) in original.get_additional_properties().map(|node_property| { + ( + node_property.property_name.to_uppercase(), + AdditionalPropertyValue::SingleString(node_property.value.unwrap_or("").to_owned()), + ) + }) { + additional_properties.properties.insert(name, val); + } + let children = original .children .iter() @@ -36,7 +71,65 @@ to_wasm!( Ok(( children, WasmHeadline { - additional_properties: AdditionalProperties::default(), + additional_properties, + level: original.level, + tags: original.tags.iter().map(|tag| (*tag).to_owned()).collect(), + todo_keyword: original + .todo_keyword + .as_ref() + .map(|(_, keyword)| (*keyword).to_owned()), + todo_type: original + .todo_keyword + .as_ref() + .map(|(keyword, _)| match keyword { + TodoKeywordType::Done => "done".to_owned(), + TodoKeywordType::Todo => "todo".to_owned(), + }), + title: original + .title + .iter() + .map(|child| { + child + .to_wasm(wasm_context.clone()) + .map(Into::::into) + }) + .collect::, _>>()?, + priority: original.priority_cookie, + is_archived: original.is_archived, + is_comment: original.is_comment, + raw_value: original.get_raw_value(), + is_footnote_section: original.is_footnote_section, + scheduled: original + .scheduled + .as_ref() + .map(|child| { + child + .to_wasm(wasm_context.clone()) + .map(Into::::into) + }) + .map_or(Ok(None), |r| r.map(Some))? + .map(|child| Box::new(child)), + deadline: original + .deadline + .as_ref() + .map(|child| { + child + .to_wasm(wasm_context.clone()) + .map(Into::::into) + }) + .map_or(Ok(None), |r| r.map(Some))? + .map(|child| Box::new(child)), + closed: original + .closed + .as_ref() + .map(|child| { + child + .to_wasm(wasm_context.clone()) + .map(Into::::into) + }) + .map_or(Ok(None), |r| r.map(Some))? + .map(|child| Box::new(child)), + pre_blank: 0, }, )) } diff --git a/src/wasm_test/compare.rs b/src/wasm_test/compare.rs index 20de4eb..8917f2a 100644 --- a/src/wasm_test/compare.rs +++ b/src/wasm_test/compare.rs @@ -58,11 +58,36 @@ fn compare_json_value<'b, 's>( compare_plain_text(source, e, w) } (serde_json::Value::Null, Token::Atom("nil")) => Ok(WasmDiffResult::default()), + (serde_json::Value::Bool(false), Token::Atom("nil")) => Ok(WasmDiffResult::default()), + (serde_json::Value::Bool(true), Token::Atom(e)) if (*e) != "nil" => { + Ok(WasmDiffResult::default()) + } + (serde_json::Value::Bool(w), Token::Atom(e)) => { + let mut result = WasmDiffResult::default(); + result.status.push(WasmDiffStatus::Bad( + format!( + "Value mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = e, + wasm = w, + ) + .into(), + )); + Ok(result) + } + (serde_json::Value::Number(w), Token::Atom(e)) if w.to_string().as_str() == (*e) => { + Ok(WasmDiffResult::default()) + } + (serde_json::Value::Array(w), Token::Atom("nil")) if w.is_empty() => { + Ok(WasmDiffResult::default()) + } + (serde_json::Value::String(w), Token::Atom(e)) if w.as_str() == *e => { + Ok(WasmDiffResult::default()) + } (serde_json::Value::Null, Token::Atom(_)) => todo!(), (serde_json::Value::Null, Token::List(_)) => todo!(), (serde_json::Value::Null, Token::TextWithProperties(_)) => todo!(), (serde_json::Value::Null, Token::Vector(_)) => todo!(), - (serde_json::Value::Bool(_), Token::Atom(_)) => todo!(), + // (serde_json::Value::Bool(_), Token::Atom(_)) => todo!(), (serde_json::Value::Bool(_), Token::List(_)) => todo!(), (serde_json::Value::Bool(_), Token::TextWithProperties(_)) => todo!(), (serde_json::Value::Bool(_), Token::Vector(_)) => todo!(), @@ -70,7 +95,19 @@ fn compare_json_value<'b, 's>( (serde_json::Value::Number(_), Token::List(_)) => todo!(), (serde_json::Value::Number(_), Token::TextWithProperties(_)) => todo!(), (serde_json::Value::Number(_), Token::Vector(_)) => todo!(), - (serde_json::Value::String(_), Token::Atom(_)) => todo!(), + // (serde_json::Value::String(_), Token::Atom(_)) => todo!(), + (serde_json::Value::String(w), Token::Atom(e)) => { + let mut result = WasmDiffResult::default(); + result.status.push(WasmDiffStatus::Bad( + format!( + "Value mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = e, + wasm = w, + ) + .into(), + )); + Ok(result) + } (serde_json::Value::String(_), Token::List(_)) => todo!(), (serde_json::Value::String(_), Token::TextWithProperties(_)) => todo!(), (serde_json::Value::String(_), Token::Vector(_)) => todo!(), @@ -85,6 +122,31 @@ fn compare_json_value<'b, 's>( } } +fn compare_optional_json_value<'b, 's>( + source: &'s str, + emacs: Option<&'b Token<'s>>, + wasm: Option<&serde_json::Value>, +) -> Result, Box> { + match (emacs, wasm) { + (None, None) | (None, Some(serde_json::Value::Null)) | (Some(Token::Atom("nil")), None) => { + Ok(WasmDiffResult::default()) + } + (Some(e), Some(w)) => compare_json_value(source, e, w), + _ => Ok(WasmDiffResult { + status: vec![WasmDiffStatus::Bad( + format!( + "Nullness mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = emacs, + wasm = wasm + ) + .into(), + )], + children: Vec::new(), + name: "".into(), + }), + } +} + fn compare_ast_node<'e, 's, 'w>( source: &'s str, emacs: &'e Vec>, @@ -137,12 +199,21 @@ fn compare_ast_node<'e, 's, 'w>( .keys() .map(|s| (*s).to_owned()) .collect(); + // wasm_attributes_map.iter().filter_map(|(k,v)| if matches!(v, serde_json::Value::Null) {None} else {Some(k)}).map(wasm_key_to_emacs_key) let wasm_keys: std::collections::BTreeSet = std::iter::once(":standard-properties".to_owned()) .chain(wasm_attributes_map.keys().map(wasm_key_to_emacs_key)) .collect(); let emacs_only_attributes: Vec<&String> = emacs_keys.difference(&wasm_keys).collect(); - let wasm_only_attributes: Vec<&String> = wasm_keys.difference(&emacs_keys).collect(); + let wasm_only_attributes: Vec<&String> = wasm_keys + .difference(&emacs_keys) + .filter(|attribute| { + emacs_attributes_map + .get(attribute.as_str()) + .map(|token| !matches!(token, Token::Atom("nil"))) + .unwrap_or(false) + }) + .collect(); if !emacs_only_attributes.is_empty() { result.status.push(WasmDiffStatus::Bad( format!( @@ -180,14 +251,10 @@ fn compare_ast_node<'e, 's, 'w>( for attribute_name in wasm_attributes_map.keys() { let mut layer = WasmDiffResult::default(); layer.name = Cow::Owned(attribute_name.clone()); - let wasm_attribute_value = wasm_attributes_map - .get(attribute_name) - .ok_or("Key should exist in both wasm and elisp at this point.")?; + let wasm_attribute_value = wasm_attributes_map.get(attribute_name); let emacs_key = wasm_key_to_emacs_key(attribute_name); - let emacs_attribute_value = *emacs_attributes_map - .get(emacs_key.as_str()) - .ok_or("Key should exist in both wasm and elisp at this point.")?; - layer.extend(compare_json_value( + let emacs_attribute_value = emacs_attributes_map.get(emacs_key.as_str()).map(|e| *e); + layer.extend(compare_optional_json_value( source, emacs_attribute_value, wasm_attribute_value,