Skip to content

Commit 8ab43d2

Browse files
authored
feat(cst): add _or_set methods (#45)
1 parent bd19332 commit 8ab43d2

File tree

2 files changed

+151
-10
lines changed

2 files changed

+151
-10
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ let json_text = r#"{
4343
}"#;
4444

4545
let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
46-
let root_obj = root.object_value_or_create().unwrap();
46+
let root_obj = root.object_value_or_set();
4747

4848
root_obj.get("data").unwrap().set_value(json!({
4949
"nested": true

src/cst/mod.rs

+150-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//! }"#;
1414
//!
1515
//! let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
16-
//! let root_obj = root.object_value_or_create().unwrap();
16+
//! let root_obj = root.object_value_or_set();
1717
//!
1818
//! root_obj.get("data").unwrap().set_value(json!({
1919
//! "nested": true
@@ -785,7 +785,7 @@ impl CstContainerNode {
785785
);
786786
}
787787
CstInputValue::Array(elements) => {
788-
let array_node: CstContainerNode = CstArray::new().into();
788+
let array_node: CstContainerNode = CstArray::new_no_tokens().into();
789789
self.raw_insert_child(insert_index, array_node.clone().into());
790790

791791
array_node.raw_append_child(CstToken::new('[').into());
@@ -828,7 +828,7 @@ impl CstContainerNode {
828828
array_node.raw_append_child(CstToken::new(']').into());
829829
}
830830
CstInputValue::Object(properties) => {
831-
let object_node: CstContainerNode = CstObject::new().into();
831+
let object_node: CstContainerNode = CstObject::new_no_tokens().into();
832832
self.raw_insert_child(insert_index, object_node.clone().into());
833833

834834
object_node.raw_append_child(CstToken::new('{').into());
@@ -1020,7 +1020,7 @@ impl CstRootNode {
10201020
/// }"#;
10211021
///
10221022
/// let root = CstRootNode::parse(json_text, &ParseOptions::default()).unwrap();
1023-
/// let root_obj = root.object_value_or_create().unwrap();
1023+
/// let root_obj = root.object_value_or_set();
10241024
///
10251025
/// root_obj.get("data").unwrap().set_value(json!({
10261026
/// "nested": true
@@ -1110,7 +1110,7 @@ impl CstRootNode {
11101110
let indents = compute_indents(&self.clone().into());
11111111
let mut insert_index = if let Some(root_value) = self.value() {
11121112
let index = root_value.child_index();
1113-
root_value.remove();
1113+
root_value.remove_raw();
11141114
index
11151115
} else {
11161116
let children = self.children();
@@ -1145,6 +1145,9 @@ impl CstRootNode {
11451145

11461146
/// Gets or creates the root value as an object, returns `Some` if successful
11471147
/// or `None` if the root value already exists and is not an object.
1148+
///
1149+
/// Note: Use `.object_value_or_set()` to overwrite the root value when
1150+
/// it's not an object.
11481151
pub fn object_value_or_create(&self) -> Option<CstObject> {
11491152
match self.value() {
11501153
Some(CstNode::Container(CstContainerNode::Object(node))) => Some(node),
@@ -1156,13 +1159,30 @@ impl CstRootNode {
11561159
}
11571160
}
11581161

1162+
/// Gets the value if it's an object or sets the root value as an object.
1163+
///
1164+
/// Note: Use `.object_value_or_create()` to not overwrite the root value
1165+
/// when it's not an object.
1166+
pub fn object_value_or_set(&self) -> CstObject {
1167+
match self.value() {
1168+
Some(CstNode::Container(CstContainerNode::Object(node))) => node,
1169+
_ => {
1170+
self.set_value(CstInputValue::Object(Vec::new()));
1171+
self.object_value().unwrap()
1172+
}
1173+
}
1174+
}
1175+
11591176
/// Gets the value if its an array.
11601177
pub fn array_value(&self) -> Option<CstArray> {
11611178
self.value()?.as_array()
11621179
}
11631180

11641181
/// Gets or creates the root value as an object, returns `Some` if successful
11651182
/// or `None` if the root value already exists and is not an object.
1183+
///
1184+
/// Note: Use `.array_value_or_set()` to overwrite the root value when
1185+
/// it's not an array.
11661186
pub fn array_value_or_create(&self) -> Option<CstArray> {
11671187
match self.value() {
11681188
Some(CstNode::Container(CstContainerNode::Array(node))) => Some(node),
@@ -1174,6 +1194,20 @@ impl CstRootNode {
11741194
}
11751195
}
11761196

1197+
/// Gets the value if it's an object or sets the root value as an object.
1198+
///
1199+
/// Note: Use `.array_value_or_create()` to not overwrite the root value
1200+
/// when it's not an object.
1201+
pub fn array_value_or_set(&self) -> CstArray {
1202+
match self.value() {
1203+
Some(CstNode::Container(CstContainerNode::Array(node))) => node,
1204+
_ => {
1205+
self.set_value(CstInputValue::Array(Vec::new()));
1206+
self.array_value().unwrap()
1207+
}
1208+
}
1209+
}
1210+
11771211
/// Ensures this object's values use trailing commas.
11781212
///
11791213
/// Note: This does not cause future values to use trailing commas.
@@ -1408,10 +1442,17 @@ impl_container_methods!(CstObject, Object);
14081442
impl CstObject {
14091443
add_root_node_method!();
14101444

1411-
fn new() -> Self {
1445+
fn new_no_tokens() -> Self {
14121446
Self(CstValueInner::new(Vec::new()))
14131447
}
14141448

1449+
fn new_with_tokens() -> Self {
1450+
let object = CstObject::new_no_tokens();
1451+
let container: CstContainerNode = object.clone().into();
1452+
container.raw_append_children(vec![CstToken::new('{').into(), CstToken::new('}').into()]);
1453+
object
1454+
}
1455+
14151456
/// Array property by name.
14161457
///
14171458
/// Returns `None` if the property doesn't exist or is not an array.
@@ -1425,6 +1466,9 @@ impl CstObject {
14251466
/// Ensures a property exists with an array value returning the array.
14261467
///
14271468
/// Returns `None` if the property value exists, but is not an array.
1469+
///
1470+
/// Note: Use `.array_value_or_set(..)` to overwrite an existing
1471+
/// non-array property value.
14281472
pub fn array_value_or_create(&self, name: &str) -> Option<CstArray> {
14291473
match self.get(name) {
14301474
Some(prop) => match prop.value()? {
@@ -1438,6 +1482,37 @@ impl CstObject {
14381482
}
14391483
}
14401484

1485+
/// Ensures a property exists with an array value returning the array.
1486+
///
1487+
/// Note: Use `.array_value_or_create(..)` to not overwrite an existing
1488+
/// non-array property value.
1489+
pub fn array_value_or_set(&self, name: &str) -> CstArray {
1490+
match self.get(name) {
1491+
Some(prop) => match prop.value() {
1492+
Some(CstNode::Container(CstContainerNode::Array(node))) => node,
1493+
Some(node) => {
1494+
let mut index = node.child_index();
1495+
node.remove_raw();
1496+
let container: CstContainerNode = prop.clone().into();
1497+
let array = CstArray::new_with_tokens();
1498+
container.raw_insert_child(Some(&mut index), array.clone().into());
1499+
array
1500+
}
1501+
_ => {
1502+
let mut index = prop.children().len();
1503+
let container: CstContainerNode = prop.clone().into();
1504+
let array = CstArray::new_with_tokens();
1505+
container.raw_insert_child(Some(&mut index), array.clone().into());
1506+
array
1507+
}
1508+
},
1509+
None => {
1510+
self.append(name, CstInputValue::Array(Vec::new()));
1511+
self.array_value(name).unwrap()
1512+
}
1513+
}
1514+
}
1515+
14411516
/// Object property by name.
14421517
///
14431518
/// Returns `None` if the property doesn't exist or is not an object.
@@ -1451,6 +1526,9 @@ impl CstObject {
14511526
/// Ensures a property exists with an object value returning the object.
14521527
///
14531528
/// Returns `None` if the property value exists, but is not an object.
1529+
///
1530+
/// Note: Use `.object_value_or_set(..)` to overwrite an existing
1531+
/// non-array property value.
14541532
pub fn object_value_or_create(&self, name: &str) -> Option<CstObject> {
14551533
match self.get(name) {
14561534
Some(prop) => match prop.value()? {
@@ -1464,6 +1542,37 @@ impl CstObject {
14641542
}
14651543
}
14661544

1545+
/// Ensures a property exists with an object value returning the object.
1546+
///
1547+
/// Note: Use `.object_value_or_create(..)` to not overwrite an existing
1548+
/// non-object property value.
1549+
pub fn object_value_or_set(&self, name: &str) -> CstObject {
1550+
match self.get(name) {
1551+
Some(prop) => match prop.value() {
1552+
Some(CstNode::Container(CstContainerNode::Object(node))) => node,
1553+
Some(node) => {
1554+
let mut index = node.child_index();
1555+
node.remove_raw();
1556+
let container: CstContainerNode = prop.clone().into();
1557+
let object = CstObject::new_with_tokens();
1558+
container.raw_insert_child(Some(&mut index), object.clone().into());
1559+
object
1560+
}
1561+
_ => {
1562+
let mut index = prop.children().len();
1563+
let container: CstContainerNode = prop.clone().into();
1564+
let object = CstObject::new_with_tokens();
1565+
container.raw_insert_child(Some(&mut index), object.clone().into());
1566+
object
1567+
}
1568+
},
1569+
None => {
1570+
self.append(name, CstInputValue::Object(Vec::new()));
1571+
self.object_value(name).unwrap()
1572+
}
1573+
}
1574+
}
1575+
14671576
/// Property by name.
14681577
///
14691578
/// Returns `None` if the property doesn't exist.
@@ -1742,10 +1851,17 @@ impl_container_methods!(CstArray, Array);
17421851
impl CstArray {
17431852
add_root_node_method!();
17441853

1745-
fn new() -> Self {
1854+
fn new_no_tokens() -> Self {
17461855
Self(CstValueInner::new(Vec::new()))
17471856
}
17481857

1858+
fn new_with_tokens() -> Self {
1859+
let array = CstArray::new_no_tokens();
1860+
let container: CstContainerNode = array.clone().into();
1861+
container.raw_append_children(vec![CstToken::new('[').into(), CstToken::new(']').into()]);
1862+
array
1863+
}
1864+
17491865
/// Elements of the array.
17501866
pub fn elements(&self) -> Vec<CstNode> {
17511867
self
@@ -2133,7 +2249,7 @@ impl<'a> CstBuilder<'a> {
21332249
}
21342250

21352251
fn build_object(&mut self, object: ast::Object<'_>) -> CstContainerNode {
2136-
let container = CstContainerNode::Object(CstObject::new());
2252+
let container = CstContainerNode::Object(CstObject::new_no_tokens());
21372253
let mut last_range_end = object.range.start;
21382254
for prop in object.properties {
21392255
self.scan_from_to(&container, last_range_end, prop.range.start);
@@ -2203,7 +2319,7 @@ impl<'a> CstBuilder<'a> {
22032319
}
22042320

22052321
fn build_array(&mut self, array: ast::Array<'_>) -> CstContainerNode {
2206-
let container = CstContainerNode::Array(CstArray::new());
2322+
let container = CstContainerNode::Array(CstArray::new_no_tokens());
22072323
let mut last_range_end = array.range.start;
22082324
for element in array.elements {
22092325
let element_range = element.range();
@@ -3460,6 +3576,31 @@ value3: true
34603576
);
34613577
}
34623578

3579+
#[test]
3580+
fn or_set_methods() {
3581+
let cst = build_cst("");
3582+
let array = cst.array_value_or_set();
3583+
assert_eq!(array.to_string(), "[]");
3584+
assert_eq!(cst.to_string(), "[]\n");
3585+
let object = cst.object_value_or_set();
3586+
assert_eq!(object.to_string(), "{}");
3587+
assert_eq!(cst.to_string(), "{}\n");
3588+
let value = object.array_value_or_set("test");
3589+
assert_eq!(value.to_string(), "[]");
3590+
assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
3591+
let value = object.object_value_or_set("test");
3592+
assert_eq!(value.to_string(), "{}");
3593+
assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
3594+
let value = object.array_value_or_set("test");
3595+
assert_eq!(value.to_string(), "[]");
3596+
assert_eq!(cst.to_string(), "{\n \"test\": []\n}\n");
3597+
value.append(json!(1));
3598+
assert_eq!(cst.to_string(), "{\n \"test\": [1]\n}\n");
3599+
let value = object.object_value_or_set("test");
3600+
assert_eq!(value.to_string(), "{}");
3601+
assert_eq!(cst.to_string(), "{\n \"test\": {}\n}\n");
3602+
}
3603+
34633604
#[test]
34643605
fn expression_properties_and_values() {
34653606
#[track_caller]

0 commit comments

Comments
 (0)