mirror of
https://github.com/sagiegurari/duckscript
synced 2024-10-02 22:24:40 +00:00
New --collection flag to json_encode command which encodes maps/arrays instead of variables #175
This commit is contained in:
parent
7d231e16da
commit
1cc459defa
|
@ -3,6 +3,7 @@
|
|||
### v0.8.4
|
||||
|
||||
* New --collection flag to json_parse command which returns maps/arrays instead of variables #175
|
||||
* New --collection flag to json_encode command which encodes maps/arrays instead of variables #175
|
||||
|
||||
### v0.8.3
|
||||
|
||||
|
|
12
docs/sdk.md
12
docs/sdk.md
|
@ -4105,11 +4105,14 @@ string = json_encode var_name
|
|||
```
|
||||
|
||||
This function will encode all variables, starting from the root variable as a JSON string.<br>
|
||||
Since duckscript is untyped, all boolean and numeric values will be encoded as strings.
|
||||
Since duckscript is untyped, all boolean and numeric values will be encoded as strings.<br>
|
||||
If --collection is passed, the provided value is considered as string or a map/array handle which is used to fetch
|
||||
the tree data and create the json string.
|
||||
|
||||
#### Parameters
|
||||
|
||||
The root variable name
|
||||
* Option --collection flag to make the encoding use the maps/arrays and values
|
||||
* The root variable name (or a handle/value in case --collection is provided)
|
||||
|
||||
#### Return Value
|
||||
|
||||
|
@ -4118,8 +4121,13 @@ The JSON string
|
|||
#### Examples
|
||||
|
||||
```sh
|
||||
# will parse and encode to plain variables
|
||||
package = json_parse "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
|
||||
jsonstring = json_encode package
|
||||
|
||||
# will parse and encode to maps/arrays
|
||||
package = json_parse --collection "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
|
||||
jsonstring = json_encode --collection ${package}
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -3,11 +3,14 @@ string = json_encode var_name
|
|||
```
|
||||
|
||||
This function will encode all variables, starting from the root variable as a JSON string.<br>
|
||||
Since duckscript is untyped, all boolean and numeric values will be encoded as strings.
|
||||
Since duckscript is untyped, all boolean and numeric values will be encoded as strings.<br>
|
||||
If --collection is passed, the provided value is considered as string or a map/array handle which is used to fetch
|
||||
the tree data and create the json string.
|
||||
|
||||
#### Parameters
|
||||
|
||||
The root variable name
|
||||
* Option --collection flag to make the encoding use the maps/arrays and values
|
||||
* The root variable name (or a handle/value in case --collection is provided)
|
||||
|
||||
#### Return Value
|
||||
|
||||
|
@ -16,6 +19,11 @@ The JSON string
|
|||
#### Examples
|
||||
|
||||
```sh
|
||||
# will parse and encode to plain variables
|
||||
package = json_parse "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
|
||||
jsonstring = json_encode package
|
||||
|
||||
# will parse and encode to maps/arrays
|
||||
package = json_parse --collection "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
|
||||
jsonstring = json_encode --collection ${package}
|
||||
```
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::sdk::std::json::OBJECT_VALUE;
|
||||
use crate::utils::pckg;
|
||||
use crate::utils::state::get_handles_sub_state;
|
||||
use duckscript::types::command::{Command, CommandResult, Commands};
|
||||
use duckscript::types::instruction::Instruction;
|
||||
use duckscript::types::runtime::StateValue;
|
||||
use serde_json::map::Map;
|
||||
use serde_json::Value;
|
||||
use serde_json::{Number, Value};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -92,7 +93,10 @@ fn encode_any(name: &str, values: &HashMap<&str, &str>) -> Result<Value, String>
|
|||
}
|
||||
}
|
||||
|
||||
fn encode(name: &str, variables: &HashMap<String, String>) -> Result<String, String> {
|
||||
fn encode_from_variables(
|
||||
name: &str,
|
||||
variables: &HashMap<String, String>,
|
||||
) -> Result<String, String> {
|
||||
let mut object_variables: HashMap<&str, &str> = HashMap::new();
|
||||
|
||||
for (key, value) in variables {
|
||||
|
@ -111,6 +115,68 @@ fn encode(name: &str, variables: &HashMap<String, String>) -> Result<String, Str
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_from_state_value(
|
||||
state_value: &StateValue,
|
||||
state: &HashMap<String, StateValue>,
|
||||
) -> Result<Value, String> {
|
||||
match state_value {
|
||||
StateValue::Boolean(value) => Ok(Value::Bool(*value)),
|
||||
StateValue::Number(value) => Ok(Value::Number(Number::from(*value))),
|
||||
StateValue::UnsignedNumber(value) => Ok(Value::Number(Number::from(*value))),
|
||||
StateValue::Number32Bit(value) => Ok(Value::Number(Number::from(*value))),
|
||||
StateValue::UnsignedNumber32Bit(value) => Ok(Value::Number(Number::from(*value))),
|
||||
StateValue::Number64Bit(value) => Ok(Value::Number(Number::from(*value))),
|
||||
StateValue::UnsignedNumber64Bit(value) => Ok(Value::Number(Number::from(*value))),
|
||||
StateValue::String(value) => match state.get(value) {
|
||||
Some(sub_state_value) => encode_from_state_value(sub_state_value, state),
|
||||
None => Ok(Value::String(value.to_string())),
|
||||
},
|
||||
StateValue::List(list) => {
|
||||
let mut items = vec![];
|
||||
|
||||
for item in list {
|
||||
match encode_from_state_value(item, state) {
|
||||
Ok(item_value) => {
|
||||
items.push(item_value);
|
||||
}
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Value::Array(items))
|
||||
}
|
||||
StateValue::SubState(sub_state) => {
|
||||
let mut items = Map::new();
|
||||
|
||||
for (key, value) in sub_state {
|
||||
match encode_from_state_value(value, state) {
|
||||
Ok(item_value) => {
|
||||
items.insert(key.to_string(), item_value);
|
||||
}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Object(items))
|
||||
}
|
||||
StateValue::ByteArray(_) => Err("Unsupported value type.".to_string()),
|
||||
StateValue::Set(_) => Err("Unsupported value type.".to_string()),
|
||||
StateValue::Any(_) => Err("Unsupported value type.".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_from_state(value: &str, state: &HashMap<String, StateValue>) -> Result<String, String> {
|
||||
let json_value = match state.get(value) {
|
||||
Some(state_value) => encode_from_state_value(state_value, state),
|
||||
None => Ok(Value::String(value.to_string())),
|
||||
};
|
||||
|
||||
match json_value {
|
||||
Ok(json_value_obj) => Ok(json_value_obj.to_string()),
|
||||
Err(error) => Err(error.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct CommandImpl {
|
||||
package: String,
|
||||
|
@ -140,7 +206,7 @@ impl Command for CommandImpl {
|
|||
fn run_with_context(
|
||||
&self,
|
||||
arguments: Vec<String>,
|
||||
_state: &mut HashMap<String, StateValue>,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
variables: &mut HashMap<String, String>,
|
||||
_output_variable: Option<String>,
|
||||
_instructions: &Vec<Instruction>,
|
||||
|
@ -150,10 +216,25 @@ impl Command for CommandImpl {
|
|||
if arguments.is_empty() {
|
||||
CommandResult::Error("No JSON root variable name provided.".to_string())
|
||||
} else {
|
||||
match encode(&arguments[0], variables) {
|
||||
let (start_index, as_state) = if arguments.len() > 1 && arguments[0] == "--collection" {
|
||||
(1, true)
|
||||
} else {
|
||||
(0, false)
|
||||
};
|
||||
|
||||
if as_state {
|
||||
let state = get_handles_sub_state(state);
|
||||
|
||||
match encode_from_state(&arguments[start_index], state) {
|
||||
Ok(output) => CommandResult::Continue(Some(output)),
|
||||
Err(error) => CommandResult::Error(error),
|
||||
}
|
||||
} else {
|
||||
match encode_from_variables(&arguments[start_index], variables) {
|
||||
Ok(output) => CommandResult::Continue(Some(output)),
|
||||
Err(error) => CommandResult::Error(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ fn test_simple_types
|
|||
assert_false ${defined}
|
||||
end
|
||||
|
||||
fn test_all_types
|
||||
fn test_all_types_as_vars
|
||||
jsonstring = set "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
|
||||
package = json_parse ${jsonstring}
|
||||
|
||||
|
@ -98,3 +98,43 @@ fn test_all_types
|
|||
assert_eq ${package2.keywords[1].directories.test} spec
|
||||
end
|
||||
|
||||
fn test_all_types_as_collections
|
||||
jsonstring = set "{\"name\": \"my package\", \"version\": 1, \"publish\": false, \"keywords\": [\"test1\", \"test2\"], \"directories\": {\"test\": \"spec\"}}"
|
||||
package = json_parse --collection ${jsonstring}
|
||||
|
||||
name = map_get ${package} name
|
||||
assert_eq ${name} "my package"
|
||||
version = map_get ${package} version
|
||||
assert_eq ${version} 1
|
||||
public = map_get ${package} public
|
||||
assert_false ${public}
|
||||
keywords_handle = map_get ${package} keywords
|
||||
length = array_length ${keywords_handle}
|
||||
assert_eq ${length} 2
|
||||
value = array_get ${keywords_handle} 0
|
||||
assert_eq ${value} test1
|
||||
value = array_get ${keywords_handle} 1
|
||||
assert_eq ${value} test2
|
||||
directories = map_get ${package} directories
|
||||
directory = map_get ${directories} test
|
||||
assert_eq ${directory} spec
|
||||
|
||||
map_put ${package} name "my package 2"
|
||||
name = map_get ${package} name
|
||||
assert_eq ${name} "my package 2"
|
||||
|
||||
update_jsonstring = json_encode --collection ${package}
|
||||
|
||||
release --recursive ${package}
|
||||
|
||||
package2 = json_parse ${update_jsonstring}
|
||||
assert_eq ${package2} "[OBJECT]"
|
||||
assert_eq ${package2.name} "my package 2"
|
||||
assert_eq ${package2.version} 1
|
||||
assert_eq ${package2.publish} false
|
||||
assert_eq ${package2.keywords.length} 2
|
||||
assert_eq ${package2.keywords[0]} test1
|
||||
assert_eq ${package2.keywords[1]} test2
|
||||
assert_eq ${package2.directories.test} spec
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue