diff --git a/jdora/src/library/controller.rs b/jdora/src/library/controller.rs index 77dc677..ff07f0a 100644 --- a/jdora/src/library/controller.rs +++ b/jdora/src/library/controller.rs @@ -2,7 +2,7 @@ use std::any::Any; use crossterm::cursor; -use crate::library::internal::node::try_resolve_node_path_mut; +use crate::library::internal::node::{try_resolve_node_path_mut}; use super::{control::Control, filter::ExactSubstringSearch, input::InputBuffer, internal::{node::try_resolve_node_path, node_path::NodePath}, mode::Mode, ExplorerState }; @@ -78,7 +78,9 @@ impl Controller { // toggle collapse // safe to unwrap - resolved_node.unwrap().toggle_hide_child(&node_path_leaf.unwrap()); + resolved_node + .unwrap() + .toggle_hide_child(&node_path_leaf.unwrap()); // re calculate structures. state.root_node_structure = state.root_node_state.get_structures(); diff --git a/jdora/src/library/internal/README.md b/jdora/src/library/internal/README.md new file mode 100644 index 0000000..05abe35 --- /dev/null +++ b/jdora/src/library/internal/README.md @@ -0,0 +1,10 @@ +NOTES: +every node has indent level, node_path. +then its children are separated into: + +primitives +or children + +but I dont think it should do that. + +i need another, for lists. \ No newline at end of file diff --git a/jdora/src/library/internal/any.rs b/jdora/src/library/internal/any.rs new file mode 100644 index 0000000..f28fb06 --- /dev/null +++ b/jdora/src/library/internal/any.rs @@ -0,0 +1,150 @@ +use google_cloud_storage::http::bucket_access_controls::list; +use serde_json::Value; + +use crate::library::internal::{list_of_nodes::ListOfNodes, node::Node, node_path::{NodePath, NodePathKey}}; + +#[derive(Debug)] +pub enum AnyNode { + PrimitiveNode(Value), + IterableNodes(ListOfNodes), + NestedNode(Node), +} + + +#[derive(Debug)] +pub struct ParsedNodePacket { + pub key: String, // key from json + pub node: AnyNode, // Node with type information +} + + +impl AnyNode { + pub fn parse(serde_node: &Value, node_path: &NodePath) -> Vec { + if let Value::Object(map) = &serde_node { + let mut children: Vec = Vec::new(); + for (key, val) in map.iter() { + match val { + Value::Object(_) => { + children.push( + ParsedNodePacket{ + key: key.to_string(), + node: AnyNode::NestedNode(Node::new( + val.clone(), + node_path.push_and_clone( + NodePathKey::DictKey(key.to_string()) + ), + )), + } + ) + } + Value::Array(_) => { + children.push( + ParsedNodePacket { + key: key.to_string(), + node: AnyNode::IterableNodes(ListOfNodes::new( + val.clone(), + node_path.push_and_clone( + NodePathKey::DictKey(key.to_string()) + ), + )) + } + ) + } + _ => { + children.push( + ParsedNodePacket{ + key: key.to_string(), + node: AnyNode::PrimitiveNode(val.clone()), + } + ) + } + } + } + return children + } else if let Value::Array(list) = &serde_node { + let mut children: Vec = Vec::new(); + for (idx, child) in list.iter().enumerate() { + children.extend( + AnyNode::parse( + &child, + &node_path.push_and_clone( + NodePathKey::ListIndex(idx) + ) + ) + ); + } + children + } + else { + panic!("parse failed? node is not an object: {}", serde_node) + } + } + pub fn calculate_num_lines(&self) -> u16 { + match self { + AnyNode::PrimitiveNode(_) => { + 1 as u16 + }, + AnyNode::IterableNodes(nodes) => { + nodes.calculate_num_lines() + }, + AnyNode::NestedNode(node) => { + node.calculate_num_lines() + } + } + } + + pub fn toggle_hide_child(&mut self, child: &NodePathKey) { + match self { + AnyNode::PrimitiveNode(_) => { + // do nothing + }, + AnyNode::IterableNodes(nodes) => { + // do nothing for now + if let Some(idx) = nodes.hidden_children.iter().position(|item| item==child) { + nodes.hidden_children.remove(idx); + } else { + nodes.hidden_children.push(child.clone()); + } + }, + AnyNode::NestedNode(node) => { + if let Some(idx) = node.hidden_children.iter().position(|item| item==child) { + node.hidden_children.remove(idx); + } else { + node.hidden_children.push(child.clone()); + } + } + } + } + + pub fn get_structures(&self) -> Vec<(String, NodePath)> { + let mut structures: Vec<(String, NodePath)> = Vec::new(); + match self { + AnyNode::PrimitiveNode(_) => { + } + AnyNode::IterableNodes(list_of_nodes) => { + structures.extend(list_of_nodes.get_structures()) + } + AnyNode::NestedNode(node) => { + structures.extend(node.get_structures()); + } + } + structures + } + + + pub fn pprint(&self) -> String { + let mut curr_str = String::new(); + match self { + AnyNode::PrimitiveNode(_) => { + panic!("Cannot call this function on primitive.") + } + AnyNode::IterableNodes(list_of_nodes) => { + curr_str+= &list_of_nodes.pprint(); + } + AnyNode::NestedNode(node) => { + curr_str += &node.pprint(); + } + } + curr_str + } +} diff --git a/jdora/src/library/internal/constants.rs b/jdora/src/library/internal/constants.rs new file mode 100644 index 0000000..512527c --- /dev/null +++ b/jdora/src/library/internal/constants.rs @@ -0,0 +1,2 @@ + +pub const INDENT_SIZE: u16 = 4; \ No newline at end of file diff --git a/jdora/src/library/internal/list_of_nodes.rs b/jdora/src/library/internal/list_of_nodes.rs new file mode 100644 index 0000000..4272893 --- /dev/null +++ b/jdora/src/library/internal/list_of_nodes.rs @@ -0,0 +1,188 @@ +use std::any::Any; + +use serde_json::Value; + +use crate::library::internal::{any::{AnyNode, ParsedNodePacket}, constants::INDENT_SIZE, node_path::{NodePath, NodePathKey}}; + + +#[derive(Debug)] +pub struct ListOfNodes { + pub node_path: NodePath, + pub indent_level: u16, + + pub children: Vec, + // hidden_children: + pub hidden_children: Vec, +} + + +impl ListOfNodes { + pub fn new(val: Value, node_path: NodePath) -> Self { + let children = AnyNode::parse(&val, &node_path); + Self{ + node_path: node_path.clone(), + indent_level: (node_path.path.len() as u16), + children: children, + hidden_children: Vec::new(), + } + } + + /// for every line which will be sent to pprint + /// associate the NodePath associated with this line. + pub fn get_structures(&self) -> Vec<(String, NodePath)> { + + let mut results: Vec<(String, NodePath)> = Vec::new(); + + // NOTE: only do this for root nodepath + if self.indent_level == 0 { + // open brace + let open_bracket_str = "[\n".to_string(); + results.push( + ( + open_bracket_str, // this belongs to this node. + self.node_path.clone() + ) + ); + } + + + // handling more complex + // nested cases + for (idx, node_packet) in self.children.iter().enumerate() { + + + let key = &node_packet.key; + let child_node = &node_packet.node; + + match child_node { + AnyNode::IterableNodes(nodes) => { + // do nothing here, its to be handled by AnyNode + let current_node_owned_formatted_string = format!( + "{}\"{}\":", + self.num_spaces((self.indent_level+1)*INDENT_SIZE), + key.clone(), + ); + // TODO handle lists... its gonna be a nightmare + if self.hidden_children.contains(&NodePathKey::DictKey(key.clone())) { // TODO rework hidden children + let res = format!("{} ({} lines) ▲\n", current_node_owned_formatted_string, child_node.calculate_num_lines()); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + } else { + let res = format!("{} [ ▼\n", current_node_owned_formatted_string); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + // recursively call children get_structures. + let children_structures = child_node.get_structures(); + for res in children_structures { + results.push(res); + } + } + + } + AnyNode::NestedNode(_) => { + let res = format!("{}{{ ▼\n", self.num_spaces((1+self.indent_level)*INDENT_SIZE)); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + // results.extend(child_node.get_structures()) + let current_node_owned_formatted_string = format!( + "{}\"{}\":", + self.num_spaces((self.indent_level+2)*INDENT_SIZE), + key.clone(), + ); + // TODO handle lists... its gonna be a nightmare + if self.hidden_children.contains(&NodePathKey::DictKey(key.clone())) { // TODO rework hidden children + let res = format!("{} ({} lines) ▲\n", current_node_owned_formatted_string, child_node.calculate_num_lines()); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + } else { + let res = format!("{} {{ ▼\n", current_node_owned_formatted_string); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + // recursively call children get_structures. + let children_structures = child_node.get_structures(); + for res in children_structures { + results.push(res); + } + } + // print closing bracket + let closing_bracket_str = format!( + "{}}}\n", + self.num_spaces((1+self.indent_level)*INDENT_SIZE) + ); + results.push( + ( + closing_bracket_str, + self.node_path.clone(), + ) + ); + } // NOOP + AnyNode::PrimitiveNode(_) => { + results.extend(child_node.get_structures()) + } + } + + + } + + // print closing bracket + let closing_bracket_str = format!( + "{}]\n", + self.num_spaces(self.indent_level*INDENT_SIZE) + ); + results.push( + ( + closing_bracket_str, + self.node_path.clone(), + ) + ); + + results + } + + + fn num_spaces(&self, n: u16) -> String { + " ".repeat(n as usize).to_string() + } + pub fn pprint(&self) -> String { + let mut result = String::new(); + for (str, _) in self.get_structures() { // unoptimised. + result += &str; + } + result + } + + // calculate how many lines it this node will consume + // this just counts size of primitive and recursively adds up children offset lengths. + pub fn calculate_num_lines(&self) -> u16 { + + // TODO handle hidden children + let bracket_lines = 2_u16; + + // let primitive_len = self.primitives().len() as u16; + let children_len = self + .children + .iter() + .fold(0 as u16, |acc, packet| acc + packet.node.calculate_num_lines()); + bracket_lines+children_len + } +} \ No newline at end of file diff --git a/jdora/src/library/internal/mod.rs b/jdora/src/library/internal/mod.rs index e1b06ef..fdbd8b3 100644 --- a/jdora/src/library/internal/mod.rs +++ b/jdora/src/library/internal/mod.rs @@ -1,3 +1,6 @@ pub mod node; pub mod node_path; -pub mod parser; \ No newline at end of file +pub mod parser; +pub mod any; +pub mod list_of_nodes; +pub mod constants; \ No newline at end of file diff --git a/jdora/src/library/internal/node.rs b/jdora/src/library/internal/node.rs index c268e32..b7ff91b 100644 --- a/jdora/src/library/internal/node.rs +++ b/jdora/src/library/internal/node.rs @@ -3,95 +3,53 @@ use std::primitive; use serde_json::{Map, Value}; +use crate::library::internal::{any::{AnyNode, ParsedNodePacket}, constants::INDENT_SIZE, node}; + use super::node_path::{self, NodePath, NodePathKey}; -const INDENT_SIZE: u16 = 4; // i only consider // Dictionaries as nodes. + + #[derive(Debug)] pub struct Node { - // serde_node: Value, // forwards to serde node pub node_path: NodePath, pub indent_level: u16, - pub primitives: Vec<(String, Value)>, // primitive attributes - // NOTE i understand I don't handle lists well....at all right now... - pub children: Vec<(String, Node)>, + pub children: Vec, // hidden_children: pub hidden_children: Vec, } impl Node { - pub fn new(val: Value, node_path: NodePath) -> Option { - if !matches!(val, Value::Object(_)) { - return None - } - - let (primitives, children) = Node::parse(&val, &node_path); - Some(Self{ + pub fn new(val: Value, node_path: NodePath) -> Self { + let children = AnyNode::parse(&val, &node_path); + Self{ // serde_node: val, node_path: node_path.clone(), indent_level: (node_path.path.len() as u16), - primitives: primitives, children: children, hidden_children: Vec::new(), - }) - } - - pub fn parse(serde_node: &Value, node_path: &NodePath) -> ( - Vec<(String, Value)>, // primitives - Vec<(String, Node)>, // nested nodes - ){ - if let Value::Object(map) = &serde_node { - // node primitives - let mut primitives: Vec<(String, Value)> = Vec::new(); - let mut children: Vec<(String, Node)> = Vec::new(); - - for (key, val) in map.iter() { - match val { - Value::Object(_) => { - children.push( - ( - key.to_string(), - Node::new( - val.clone(), - node_path.push_and_clone( - NodePathKey::DictKey(key.to_string()) - ) - ).unwrap() - ) - ) - } - _ => { - primitives.push( - (key.to_string(), val.clone()) - ) - } - } - } - return ( - primitives, - children, - ) - } else { - panic!("parse failed? node is not an object") } } + + /// /// for every line which will be sent to pprint /// associate the NodePath associated with this line. pub fn get_structures(&self) -> Vec<(String, NodePath)> { - let mut result: Vec<(String, NodePath)> = Vec::new(); + + let mut results: Vec<(String, NodePath)> = Vec::new(); // NOTE: only do this for root nodepath if self.indent_level == 0 { // open brace let open_bracket_str = "{\n".to_string(); - result.push( + results.push( ( open_bracket_str, // this belongs to this node. self.node_path.clone() @@ -99,51 +57,86 @@ impl Node { ); } - // print primitives first - for prim_attr in self.primitives.iter() { - let (key, val) = prim_attr.clone(); - let formatted_str = format!( - "{}\"{}\":{},\n", - self.num_spaces((self.indent_level+1)*INDENT_SIZE) , - key.clone(), - val.to_string(), - ); - result.push( - ( - formatted_str, - self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) - ) - ) - } + + // handling more complex + // nested cases + for (idx, node_packet) in self.children.iter().enumerate() { + let key = &node_packet.key; + let child_node = &node_packet.node; + + match child_node { + AnyNode::IterableNodes(nodes) => { + let current_node_owned_formatted_string = format!( + "{}\"{}\":", + self.num_spaces((self.indent_level+1)*INDENT_SIZE), + key.clone(), + ); + // TODO handle lists... its gonna be a nightmare + if self.hidden_children.contains(&NodePathKey::DictKey(key.clone())) { // TODO rework hidden children + let res = format!("{} ({} lines) ▲\n", current_node_owned_formatted_string, child_node.calculate_num_lines()); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + } else { + let res = format!("{} [ ▼\n", current_node_owned_formatted_string); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + results.extend(AnyNode::get_structures(child_node)); + } + + // print closing bracket + let closing_bracket_str = format!( + "{}}}\n", + self.num_spaces(self.indent_level*INDENT_SIZE) + ); + results.push( + ( + closing_bracket_str, + self.node_path.clone(), + ) + ); + } + AnyNode::NestedNode(node) => { + let current_node_owned_formatted_string = format!( + "{}\"{}\":", + self.num_spaces((self.indent_level+1)*INDENT_SIZE), + key.clone(), + ); + // TODO handle lists... its gonna be a nightmare + if self.hidden_children.contains(&NodePathKey::DictKey(key.clone())) { // TODO rework hidden children + let res = format!("{} ({} lines) ▲\n", current_node_owned_formatted_string, child_node.calculate_num_lines()); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + } else { + let res = format!("{} {{ ▼\n", current_node_owned_formatted_string); + results.push( + ( + res, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) + ); + // recursively call children get_structures. + let children_structures = child_node.get_structures(); + for res in children_structures { + results.push(res); + } + } - for (idx, child ) in self.children.iter().enumerate() { - let (key, chld) = child; - let current_node_owned_formatted_string = format!( - "{}\"{}\":", - self.num_spaces((self.indent_level+1)*INDENT_SIZE), - key.clone(), - ); - // TODO handle lists... its gonna be a nightmare - if self.hidden_children.contains(&NodePathKey::DictKey(key.clone())) { // TODO rework hidden children - let res = format!("{} ({} lines) ▲\n", current_node_owned_formatted_string, chld.calculate_num_lines()); - result.push( - ( - res, - self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) - ) - ); - } else { - let res = format!("{} {{ ▼\n", current_node_owned_formatted_string); - result.push( - ( - res, - self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) - ) - ); - // recursively call children get_structures. - let children_structures = chld.get_structures(); - for res in children_structures { - result.push(res); + } + AnyNode::PrimitiveNode(value) => { + let result = self.get_structures_primitive(key.clone(), value.clone()); + results.push(result); } } @@ -155,14 +148,28 @@ impl Node { "{}}}\n", self.num_spaces(self.indent_level*INDENT_SIZE) ); - result.push( + results.push( ( closing_bracket_str, self.node_path.clone(), ) ); - result + results + } + + pub fn get_structures_primitive(&self, key: String, value: Value) -> (String, NodePath) { + let formatted_str = format!( + "{}\"{}\":{},\n", + self.num_spaces((self.indent_level+1)*INDENT_SIZE), + key.clone(), + value.to_string(), + ); + + return( + formatted_str, + self.node_path.push_and_clone(NodePathKey::DictKey(key.clone())) + ) } pub fn pprint(&self) -> String { @@ -185,21 +192,21 @@ impl Node { // TODO handle hidden children let bracket_lines = 2_u16; - let primitive_len = self.primitives.len() as u16; let children_len = self .children .iter() - .fold(0 as u16, |acc, &(_, ref child)| acc + child.calculate_num_lines()); - bracket_lines+primitive_len+children_len + .fold(0 as u16, |acc, packet| acc + packet.node.calculate_num_lines()); + bracket_lines+children_len } - pub fn get_child(&self, key: &NodePathKey) -> Option<&Node> { + pub fn get_child(&self, key: &NodePathKey) -> Option<&AnyNode> { match key { NodePathKey::DictKey(k) => { - for child in &self.children { - let (key, node) = child; + for node_packet in &self.children { + let key = &node_packet.key; + let node = &node_packet.node; if *key == *k { - return Some(node); + return Some(&node); } } None @@ -210,11 +217,12 @@ impl Node { } } } - pub fn get_child_mut(&mut self, key: &NodePathKey) -> Option<&mut Node> { + pub fn get_child_mut(&mut self, key: &NodePathKey) -> Option<&mut AnyNode> { match key { NodePathKey::DictKey(k) => { - for child in &mut self.children { - let (key, node) = child; + for node_packet in self.children.iter_mut() { + let key = &node_packet.key; + let node = &mut node_packet.node; if *key == *k { return Some(node); } @@ -228,43 +236,82 @@ impl Node { } } - - pub fn toggle_hide_child(&mut self, child: &NodePathKey) { - if let Some(idx) = self.hidden_children.iter().position(|item| item==child) { - self.hidden_children.remove(idx); - } else { - self.hidden_children.push(child.clone()); - } + pub fn primitives(&self) -> Vec<&ParsedNodePacket> { + return self.children.iter() + .filter(|p| + matches!(p.node, AnyNode::PrimitiveNode(_)) + ) + .map(|val| val) + .collect(); + } + pub fn nested_nodes(&self) -> Vec<&ParsedNodePacket> { + return self.children.iter() + .filter(|p| + matches!(p.node,AnyNode::NestedNode(_)) + ) + .map(|val| val) + .collect(); } + + + + // pub fn toggle_hide_child(&mut self, child: &NodePathKey) { + // if let Some(idx) = self.hidden_children.iter().position(|item| item==child) { + // self.hidden_children.remove(idx); + // } else { + // self.hidden_children.push(child.clone()); + // } + // } + } -pub fn try_resolve_node_path<'a>(root_node: &'a Node, node_path: &NodePath) -> Option<&'a Node> { - let mut cur_node = root_node; - for path_key in &node_path.path { - if let Some(new_node) = cur_node.get_child(&path_key) { - cur_node = new_node - } else { - return None +pub fn try_resolve_node_path<'a>(root_node: &'a AnyNode, node_path: &NodePath) -> Option<&'a AnyNode> { + let cur_any_node = root_node; + match cur_any_node { + AnyNode::PrimitiveNode(_) => { + panic!("root node is a primitive????") + }, + AnyNode::IterableNodes(nodes) => { + // pass + None + }, + AnyNode::NestedNode(cur_node) => { + for path_key in &node_path.path { + if let Some(new_node) = cur_node.get_child(&path_key) { + return Some(new_node) + } else { + return None + } + } + None } } - - Some(cur_node) } // returns a mutable reference, this is more necesary when we want to // update the state of the resolved path // the other one is more useful when we just wanna perform queries -pub fn try_resolve_node_path_mut<'a>(root_node: &'a mut Node, node_path: &NodePath) -> Option<&'a mut Node> { - let mut cur_node = root_node; - for path_key in &node_path.path { - if let Some(new_node) = cur_node.get_child_mut(&path_key) { - cur_node = new_node - } else { - return None +pub fn try_resolve_node_path_mut<'a>(root_node: &'a mut AnyNode, node_path: &NodePath) -> Option<&'a mut AnyNode> { + let cur_any_node = root_node; + match cur_any_node { + AnyNode::PrimitiveNode(_) => { + panic!("root node is a primitive????") + }, + AnyNode::IterableNodes(nodes) => { + // pass + None + }, + AnyNode::NestedNode(cur_node) => { + for path_key in &node_path.path { + if let Some(new_node) = cur_node.get_child_mut(&path_key) { + return Some(new_node) + } else { + return None + } + } + None } } - - Some(cur_node) } \ No newline at end of file diff --git a/jdora/src/library/internal/parser.rs b/jdora/src/library/internal/parser.rs index bc347a8..8c9635a 100644 --- a/jdora/src/library/internal/parser.rs +++ b/jdora/src/library/internal/parser.rs @@ -7,11 +7,11 @@ use super::{node::Node, node_path::NodePath}; pub fn parse(data: &str) -> Node { let v: Value = serde_json::from_str(data).unwrap(); - return Node::new(v, NodePath::new()).unwrap(); + return Node::new(v, NodePath::new()); } pub fn parse_bytes(data: &[u8]) -> Node { let v: Value = serde_json::from_slice(data).unwrap(); - return Node::new(v, NodePath::new()).unwrap(); + return Node::new(v, NodePath::new()); } @@ -96,4 +96,27 @@ mod tests { println!("{}", n.pprint()); assert!( 1 == 0 ); } + + #[test] + fn test_f() { + let data = r#" + { + "name": "abc", + "hello": 1, + "nested": [ + { + "attr": { + "bbb": 100 + } + } + ], + "another_nested": { + "b": "bbb" + } + }"#; + let mut n = parse(data); + println!("{:?}", n.get_structures()); + println!("{}", n.pprint()); + assert!( 1 == 0 ); + } } \ No newline at end of file diff --git a/jdora/src/library/state.rs b/jdora/src/library/state.rs index 7de2d2e..a2e325f 100644 --- a/jdora/src/library/state.rs +++ b/jdora/src/library/state.rs @@ -4,13 +4,16 @@ use google_cloud_storage::client::Client; use ratatui::layout::Rect; use tui_input::Input; + +use crate::library::internal::any::AnyNode; + use super::{input::InputHandler, internal::{node::Node, node_path::NodePath, parser::parse_bytes}, mode::Mode, ui::CELL_HEIGHT}; // very primitive state right now // not optimised and not cached. pub struct ExplorerState{ - pub root_node_state: Node, + pub root_node_state: AnyNode, pub root_node_structure: Vec<(String, NodePath)>, @@ -40,7 +43,7 @@ impl ExplorerState { file.read_to_end(&mut contents) .unwrap(); - let node = parse_bytes(&contents); + let node = AnyNode::NestedNode(parse_bytes(&contents)); // TODO: handle if the root node state was a list... return Self { root_node_structure: node.get_structures(), diff --git a/sample/b_.json b/sample/b_.json new file mode 100644 index 0000000..c87e2f5 --- /dev/null +++ b/sample/b_.json @@ -0,0 +1,19 @@ +{ + "name": "abc", + "hello": 1, + "nested": [ + { + "attr": { + "bbb": 1 + } + }, + { + "attr": { + "bbb": 2 + } + } + ], + "another_nested": { + "b": "bbb" + } +} \ No newline at end of file diff --git a/sample/c_.json b/sample/c_.json new file mode 100644 index 0000000..c904983 --- /dev/null +++ b/sample/c_.json @@ -0,0 +1,15 @@ +{ + "name": "abc", + "hello": 1, + "nested": [ + [ + 1,2,3,4,5 + ], + [ + 4,5,6,7,8 + ] + ], + "another_nested": { + "b": "bbb" + } +} \ No newline at end of file