mirror of
https://github.com/nushell/nushell.git
synced 2025-04-24 13:18:18 +02:00
allow Range to expand to array-like when converting to json (#8047)
# Description Fixes #8002, which expands ranges `1..3` to expand to array-like when saving and converting to json. Now, ``` > 1..3 | save foo.json # foo.json [ 1, 2, 3 ] > 1..3 | to json [ 1, 2, 3 ] ``` # User-Facing Changes _(List of all changes that impact the user experience here. This helps us keep track of breaking changes.)_ # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - [X] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - [X] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - [X] `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
parent
253b223e65
commit
42f0b55de0
@ -48,6 +48,8 @@ impl Command for ToJson {
|
|||||||
let use_tabs = call.has_flag("tabs");
|
let use_tabs = call.has_flag("tabs");
|
||||||
|
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
|
// allow ranges to expand and turn into array
|
||||||
|
let input = input.try_expand_range()?;
|
||||||
let value = input.into_value(span);
|
let value = input.into_value(span);
|
||||||
let json_value = value_to_json_value(&value)?;
|
let json_value = value_to_json_value(&value)?;
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ impl Command for ToNuon {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let input = input.try_expand_range()?;
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
val: to_nuon(call, input)?,
|
val: to_nuon(call, input)?,
|
||||||
span: call.head,
|
span: call.head,
|
||||||
|
@ -39,6 +39,7 @@ impl Command for ToText {
|
|||||||
} else {
|
} else {
|
||||||
"\n"
|
"\n"
|
||||||
};
|
};
|
||||||
|
let input = input.try_expand_range()?;
|
||||||
|
|
||||||
if let PipelineData::ListStream(stream, _) = input {
|
if let PipelineData::ListStream(stream, _) = input {
|
||||||
Ok(PipelineData::ExternalStream {
|
Ok(PipelineData::ExternalStream {
|
||||||
|
@ -64,6 +64,7 @@ impl Command for ToXml {
|
|||||||
let head = call.head;
|
let head = call.head;
|
||||||
let config = engine_state.get_config();
|
let config = engine_state.get_config();
|
||||||
let pretty: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "pretty")?;
|
let pretty: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "pretty")?;
|
||||||
|
let input = input.try_expand_range()?;
|
||||||
to_xml(input, head, pretty, config)
|
to_xml(input, head, pretty, config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ impl Command for ToYaml {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
|
let input = input.try_expand_range()?;
|
||||||
to_yaml(input, head)
|
to_yaml(input, head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,3 +283,21 @@ fn save_list_stream() {
|
|||||||
assert_eq!(actual, "a\nb\nc\nd\n")
|
assert_eq!(actual, "a\nb\nc\nd\n")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn writes_out_range() {
|
||||||
|
Playground::setup("save_test_14", |dirs, sandbox| {
|
||||||
|
sandbox.with_files(vec![]);
|
||||||
|
|
||||||
|
let expected_file = dirs.test().join("list_sample.json");
|
||||||
|
|
||||||
|
nu!(
|
||||||
|
cwd: dirs.root(),
|
||||||
|
r#"1..3 | save save_test_14/list_sample.json"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let actual = file_contents(expected_file);
|
||||||
|
println!("{actual}");
|
||||||
|
assert_eq!(actual, "[\n 1,\n 2,\n 3\n]")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -108,3 +108,26 @@ fn top_level_values_from_json() {
|
|||||||
assert_eq!(actual.out, type_name);
|
assert_eq!(actual.out, type_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ranges_to_json_as_array() {
|
||||||
|
let value = r#"[ 1, 2, 3]"#;
|
||||||
|
let actual = nu!(r#"1..3 | to json"#);
|
||||||
|
assert_eq!(actual.out, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unbounded_from_in_range_fails() {
|
||||||
|
let actual = nu!(r#"1.. | to json"#);
|
||||||
|
assert!(actual.err.contains("Cannot create range"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inf_in_range_fails() {
|
||||||
|
let actual = nu!(r#"inf..5 | to json"#);
|
||||||
|
assert!(actual.err.contains("Cannot create range"));
|
||||||
|
let actual = nu!(r#"5..inf | to json"#);
|
||||||
|
assert!(actual.err.contains("Cannot create range"));
|
||||||
|
let actual = nu!(r#"-inf..inf | to json"#);
|
||||||
|
assert!(actual.err.contains("Cannot create range"));
|
||||||
|
}
|
||||||
|
@ -604,6 +604,53 @@ impl PipelineData {
|
|||||||
(self, false)
|
(self, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Try to convert Value from Value::Range to Value::List.
|
||||||
|
/// This is useful to expand Value::Range into array notation, specifically when
|
||||||
|
/// converting `to json` or `to nuon`.
|
||||||
|
/// `1..3 | to XX -> [1,2,3]`
|
||||||
|
pub fn try_expand_range(self) -> Result<PipelineData, ShellError> {
|
||||||
|
let input = match self {
|
||||||
|
PipelineData::Value(Value::Range { val, span }, ..) => {
|
||||||
|
match (&val.to, &val.from) {
|
||||||
|
(Value::Float { val, .. }, _) | (_, Value::Float { val, .. }) => {
|
||||||
|
if *val == f64::INFINITY || *val == f64::NEG_INFINITY {
|
||||||
|
return Err(ShellError::GenericError(
|
||||||
|
"Cannot create range".into(),
|
||||||
|
"Infinity is not allowed when converting to json".into(),
|
||||||
|
Some(span),
|
||||||
|
Some("Consider removing infinity".into()),
|
||||||
|
vec![],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Int { val, span }, _) => {
|
||||||
|
if *val == i64::MAX || *val == i64::MIN {
|
||||||
|
return Err(ShellError::GenericError(
|
||||||
|
"Cannot create range".into(),
|
||||||
|
"Unbounded ranges are not allowed when converting to json".into(),
|
||||||
|
Some(*span),
|
||||||
|
Some(
|
||||||
|
"Consider using ranges with valid start and end point.".into(),
|
||||||
|
),
|
||||||
|
vec![],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
let range_values: Vec<Value> = val.into_range_iter(None)?.collect();
|
||||||
|
PipelineData::Value(
|
||||||
|
Value::List {
|
||||||
|
vals: range_values,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => self,
|
||||||
|
};
|
||||||
|
Ok(input)
|
||||||
|
}
|
||||||
|
|
||||||
/// Consume and print self data immediately.
|
/// Consume and print self data immediately.
|
||||||
///
|
///
|
||||||
|
Loading…
Reference in New Issue
Block a user