forked from extern/nushell
Input output checking (#9680)
# Description This PR tights input/output type-checking a bit more. There are a lot of commands that don't have correct input/output types, so part of the effort is updating them. This PR now contains updates to commands that had wrong input/output signatures. It doesn't add examples for these new signatures, but that can be follow-up work. # User-Facing Changes BREAKING CHANGE BREAKING CHANGE This work enforces many more checks on pipeline type correctness than previous nushell versions. This strictness may uncover incompatibilities in existing scripts or shortcomings in the type information for internal commands. # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # 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
e66139e6bb
commit
786ba3bf91
@ -15,7 +15,13 @@ impl Command for BitsAnd {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bits and")
|
Signature::build("bits and")
|
||||||
.input_output_types(vec![(Type::Int, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required(
|
.required(
|
||||||
"target",
|
"target",
|
||||||
|
@ -16,7 +16,13 @@ impl Command for BitsNot {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bits not")
|
Signature::build("bits not")
|
||||||
.input_output_types(vec![(Type::Int, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.switch(
|
.switch(
|
||||||
"signed",
|
"signed",
|
||||||
|
@ -15,7 +15,13 @@ impl Command for BitsOr {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bits or")
|
Signature::build("bits or")
|
||||||
.input_output_types(vec![(Type::Int, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required(
|
.required(
|
||||||
"target",
|
"target",
|
||||||
|
@ -18,7 +18,13 @@ impl Command for BitsRol {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bits rol")
|
Signature::build("bits rol")
|
||||||
.input_output_types(vec![(Type::Int, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required("bits", SyntaxShape::Int, "number of bits to rotate left")
|
.required("bits", SyntaxShape::Int, "number of bits to rotate left")
|
||||||
.switch(
|
.switch(
|
||||||
|
@ -18,7 +18,13 @@ impl Command for BitsRor {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bits ror")
|
Signature::build("bits ror")
|
||||||
.input_output_types(vec![(Type::Int, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required("bits", SyntaxShape::Int, "number of bits to rotate right")
|
.required("bits", SyntaxShape::Int, "number of bits to rotate right")
|
||||||
.switch(
|
.switch(
|
||||||
|
@ -18,7 +18,13 @@ impl Command for BitsShl {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bits shl")
|
Signature::build("bits shl")
|
||||||
.input_output_types(vec![(Type::Int, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required("bits", SyntaxShape::Int, "number of bits to shift left")
|
.required("bits", SyntaxShape::Int, "number of bits to shift left")
|
||||||
.switch(
|
.switch(
|
||||||
|
@ -18,7 +18,13 @@ impl Command for BitsShr {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bits shr")
|
Signature::build("bits shr")
|
||||||
.input_output_types(vec![(Type::Int, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required("bits", SyntaxShape::Int, "number of bits to shift right")
|
.required("bits", SyntaxShape::Int, "number of bits to shift right")
|
||||||
.switch(
|
.switch(
|
||||||
|
@ -15,7 +15,13 @@ impl Command for BitsXor {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bits xor")
|
Signature::build("bits xor")
|
||||||
.input_output_types(vec![(Type::Int, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required(
|
.required(
|
||||||
"target",
|
"target",
|
||||||
|
@ -16,7 +16,13 @@ impl Command for BytesLen {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bytes length")
|
Signature::build("bytes length")
|
||||||
.input_output_types(vec![(Type::Binary, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Binary, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Binary)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -30,7 +30,10 @@ impl Command for BytesRemove {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bytes remove")
|
Signature::build("bytes remove")
|
||||||
.input_output_types(vec![(Type::Binary, Type::Binary)])
|
.input_output_types(vec![
|
||||||
|
(Type::Binary, Type::Binary),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.required("pattern", SyntaxShape::Binary, "the pattern to find")
|
.required("pattern", SyntaxShape::Binary, "the pattern to find")
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -30,7 +30,10 @@ impl Command for BytesReplace {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("bytes replace")
|
Signature::build("bytes replace")
|
||||||
.input_output_types(vec![(Type::Binary, Type::Binary)])
|
.input_output_types(vec![
|
||||||
|
(Type::Binary, Type::Binary),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.required("find", SyntaxShape::Binary, "the pattern to find")
|
.required("find", SyntaxShape::Binary, "the pattern to find")
|
||||||
.required("replace", SyntaxShape::Binary, "the replacement pattern")
|
.required("replace", SyntaxShape::Binary, "the replacement pattern")
|
||||||
.rest(
|
.rest(
|
||||||
|
@ -13,7 +13,13 @@ impl Command for SubCommand {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math cos")
|
Signature::build("math cos")
|
||||||
.switch("degrees", "Use degrees instead of radians", Some('d'))
|
.switch("degrees", "Use degrees instead of radians", Some('d'))
|
||||||
.input_output_types(vec![(Type::Number, Type::Float)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Float),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Float)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,13 @@ impl Command for SubCommand {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math sin")
|
Signature::build("math sin")
|
||||||
.switch("degrees", "Use degrees instead of radians", Some('d'))
|
.switch("degrees", "Use degrees instead of radians", Some('d'))
|
||||||
.input_output_types(vec![(Type::Number, Type::Float)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Float),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Float)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,13 @@ impl Command for SubCommand {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math tan")
|
Signature::build("math tan")
|
||||||
.switch("degrees", "Use degrees instead of radians", Some('d'))
|
.switch("degrees", "Use degrees instead of radians", Some('d'))
|
||||||
.input_output_types(vec![(Type::Number, Type::Float)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Float),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Float)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ fn basic_string_fails() {
|
|||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(actual.err.contains("Input type not supported"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
assert_eq!(actual.out, "");
|
assert_eq!(actual.out, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ impl Command for Collect {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("collect")
|
Signature::build("collect")
|
||||||
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::Any)])
|
.input_output_types(vec![(Type::Any, Type::Any)])
|
||||||
.required(
|
.required(
|
||||||
"closure",
|
"closure",
|
||||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||||
|
@ -17,15 +17,21 @@ impl Command for SubCommand {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("into decimal")
|
Signature::build("into decimal")
|
||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
|
(Type::Int, Type::Number),
|
||||||
(Type::String, Type::Number),
|
(Type::String, Type::Number),
|
||||||
(Type::Bool, Type::Number),
|
(Type::Bool, Type::Number),
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
"for a data structure input, convert data at the given cell paths",
|
"for a data structure input, convert data at the given cell paths",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Conversions)
|
.category(Category::Conversions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,17 @@ impl Command for SubCommand {
|
|||||||
(Type::Bool, Type::Int),
|
(Type::Bool, Type::Int),
|
||||||
// Unix timestamp in nanoseconds
|
// Unix timestamp in nanoseconds
|
||||||
(Type::Date, Type::Int),
|
(Type::Date, Type::Int),
|
||||||
|
(Type::Duration, Type::Int),
|
||||||
// TODO: Users should do this by dividing a Filesize by a Filesize explicitly
|
// TODO: Users should do this by dividing a Filesize by a Filesize explicitly
|
||||||
(Type::Filesize, Type::Int),
|
(Type::Filesize, Type::Int),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
Type::List(Box::new(Type::Int)),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.named("radix", SyntaxShape::Number, "radix of integer", Some('r'))
|
.named("radix", SyntaxShape::Number, "radix of integer", Some('r'))
|
||||||
.switch("little-endian", "use little-endian byte decoding", None)
|
.switch("little-endian", "use little-endian byte decoding", None)
|
||||||
.rest(
|
.rest(
|
||||||
|
@ -40,6 +40,10 @@ impl Command for SubCommand {
|
|||||||
(Type::Bool, Type::String),
|
(Type::Bool, Type::String),
|
||||||
(Type::Filesize, Type::String),
|
(Type::Filesize, Type::String),
|
||||||
(Type::Date, Type::String),
|
(Type::Date, Type::String),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
Type::List(Box::new(Type::String)),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
|
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
|
||||||
.rest(
|
.rest(
|
||||||
|
5
crates/nu-command/src/env/load_env.rs
vendored
5
crates/nu-command/src/env/load_env.rs
vendored
@ -19,7 +19,10 @@ impl Command for LoadEnv {
|
|||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
Signature::build("load-env")
|
Signature::build("load-env")
|
||||||
.input_output_types(vec![(Type::Record(vec![]), Type::Nothing)])
|
.input_output_types(vec![
|
||||||
|
(Type::Record(vec![]), Type::Nothing),
|
||||||
|
(Type::Nothing, Type::Nothing),
|
||||||
|
])
|
||||||
.allow_variants_without_examples(true)
|
.allow_variants_without_examples(true)
|
||||||
.optional(
|
.optional(
|
||||||
"update",
|
"update",
|
||||||
|
@ -16,11 +16,15 @@ impl Command for Append {
|
|||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
Signature::build("append")
|
Signature::build("append")
|
||||||
.input_output_types(vec![(
|
.input_output_types(vec![
|
||||||
|
(
|
||||||
Type::List(Box::new(Type::Any)),
|
Type::List(Box::new(Type::Any)),
|
||||||
Type::List(Box::new(Type::Any)),
|
Type::List(Box::new(Type::Any)),
|
||||||
)])
|
),
|
||||||
|
(Type::Record(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.required("row", SyntaxShape::Any, "the row, list, or table to append")
|
.required("row", SyntaxShape::Any, "the row, list, or table to append")
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ with 'transpose' first."#
|
|||||||
Type::List(Box::new(Type::Any)),
|
Type::List(Box::new(Type::Any)),
|
||||||
),
|
),
|
||||||
(Type::Table(vec![]), Type::List(Box::new(Type::Any))),
|
(Type::Table(vec![]), Type::List(Box::new(Type::Any))),
|
||||||
|
(Type::Any, Type::Any),
|
||||||
])
|
])
|
||||||
.required(
|
.required(
|
||||||
"closure",
|
"closure",
|
||||||
@ -48,6 +49,7 @@ with 'transpose' first."#
|
|||||||
"the closure to run",
|
"the closure to run",
|
||||||
)
|
)
|
||||||
.switch("keep-empty", "keep empty result cells", Some('k'))
|
.switch("keep-empty", "keep empty result cells", Some('k'))
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ impl Command for Find {
|
|||||||
Type::List(Box::new(Type::Any)),
|
Type::List(Box::new(Type::Any)),
|
||||||
Type::List(Box::new(Type::Any)),
|
Type::List(Box::new(Type::Any)),
|
||||||
),
|
),
|
||||||
(Type::String, Type::String),
|
(Type::String, Type::Any),
|
||||||
(
|
(
|
||||||
// For find -p
|
// For find -p
|
||||||
Type::Table(vec![]),
|
Type::Table(vec![]),
|
||||||
|
@ -33,12 +33,14 @@ impl Command for First {
|
|||||||
Type::Any,
|
Type::Any,
|
||||||
),
|
),
|
||||||
(Type::Binary, Type::Binary),
|
(Type::Binary, Type::Binary),
|
||||||
|
(Type::Range, Type::Any),
|
||||||
])
|
])
|
||||||
.optional(
|
.optional(
|
||||||
"rows",
|
"rows",
|
||||||
SyntaxShape::Int,
|
SyntaxShape::Int,
|
||||||
"starting from the front, the number of rows to return",
|
"starting from the front, the number of rows to return",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ If multiple cell paths are given, this will produce a list of values."#
|
|||||||
Type::Any,
|
Type::Any,
|
||||||
),
|
),
|
||||||
(Type::Table(vec![]), Type::Any),
|
(Type::Table(vec![]), Type::Any),
|
||||||
|
(Type::Record(vec![]), Type::Any),
|
||||||
])
|
])
|
||||||
.required(
|
.required(
|
||||||
"cell_path",
|
"cell_path",
|
||||||
@ -51,6 +52,7 @@ If multiple cell paths are given, this will produce a list of values."#
|
|||||||
"get path in a case sensitive manner",
|
"get path in a case sensitive manner",
|
||||||
Some('s'),
|
Some('s'),
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,10 @@ impl Command for Insert {
|
|||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::Record(vec![]), Type::Record(vec![])),
|
(Type::Record(vec![]), Type::Record(vec![])),
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
.required(
|
.required(
|
||||||
"field",
|
"field",
|
||||||
@ -30,6 +34,7 @@ impl Command for Insert {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"the new value to give the cell(s)",
|
"the new value to give the cell(s)",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ impl Command for Select {
|
|||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::Record(vec![]), Type::Record(vec![])),
|
(Type::Record(vec![]), Type::Record(vec![])),
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(Type::List(Box::new(Type::Any)), Type::Any),
|
||||||
])
|
])
|
||||||
.switch(
|
.switch(
|
||||||
"ignore-errors",
|
"ignore-errors",
|
||||||
@ -32,6 +33,7 @@ impl Command for Select {
|
|||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
"the columns to select from the table",
|
"the columns to select from the table",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,13 @@ impl Command for SortBy {
|
|||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
Signature::build("sort-by")
|
Signature::build("sort-by")
|
||||||
.input_output_types(vec![(Type::Table(vec![]), Type::Table(vec![]))])
|
.input_output_types(vec![
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.rest("columns", SyntaxShape::Any, "the column(s) to sort by")
|
.rest("columns", SyntaxShape::Any, "the column(s) to sort by")
|
||||||
.switch("reverse", "Sort in reverse order", Some('r'))
|
.switch("reverse", "Sort in reverse order", Some('r'))
|
||||||
.switch(
|
.switch(
|
||||||
@ -29,6 +35,7 @@ impl Command for SortBy {
|
|||||||
"Sort alphanumeric string-based columns naturally (1, 9, 10, 99, 100, ...)",
|
"Sort alphanumeric string-based columns naturally (1, 9, 10, 99, 100, ...)",
|
||||||
Some('n'),
|
Some('n'),
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ impl Command for Transpose {
|
|||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
(Type::Table(vec![]), Type::Record(vec![])),
|
(Type::Table(vec![]), Type::Record(vec![])),
|
||||||
|
(Type::Record(vec![]), Type::Table(vec![])),
|
||||||
])
|
])
|
||||||
.switch(
|
.switch(
|
||||||
"header-row",
|
"header-row",
|
||||||
@ -55,6 +56,7 @@ impl Command for Transpose {
|
|||||||
"on repetition of record fields due to `header-row`, keep all the values obtained",
|
"on repetition of record fields due to `header-row`, keep all the values obtained",
|
||||||
Some('a'),
|
Some('a'),
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
|
@ -17,7 +17,13 @@ impl Command for UniqBy {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("uniq-by")
|
Signature::build("uniq-by")
|
||||||
.input_output_types(vec![(Type::Table(vec![]), Type::Table(vec![]))])
|
.input_output_types(vec![
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.rest("columns", SyntaxShape::Any, "the column(s) to filter by")
|
.rest("columns", SyntaxShape::Any, "the column(s) to filter by")
|
||||||
.switch(
|
.switch(
|
||||||
"count",
|
"count",
|
||||||
@ -39,6 +45,7 @@ impl Command for UniqBy {
|
|||||||
"Return the input values that occur once only",
|
"Return the input values that occur once only",
|
||||||
Some('u'),
|
Some('u'),
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,10 @@ impl Command for Update {
|
|||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::Record(vec![]), Type::Record(vec![])),
|
(Type::Record(vec![]), Type::Record(vec![])),
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
.required(
|
.required(
|
||||||
"field",
|
"field",
|
||||||
@ -30,6 +34,7 @@ impl Command for Update {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"the new value to give the cell(s), or a closure to create the value",
|
"the new value to give the cell(s), or a closure to create the value",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,10 @@ impl Command for Upsert {
|
|||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::Record(vec![]), Type::Record(vec![])),
|
(Type::Record(vec![]), Type::Record(vec![])),
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
Type::List(Box::new(Type::Any)),
|
||||||
|
),
|
||||||
])
|
])
|
||||||
.required(
|
.required(
|
||||||
"field",
|
"field",
|
||||||
@ -30,6 +34,7 @@ impl Command for Upsert {
|
|||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"the new value to give the cell(s), or a closure to create the value",
|
"the new value to give the cell(s), or a closure to create the value",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,12 +32,14 @@ not supported."#
|
|||||||
Type::List(Box::new(Type::Any)),
|
Type::List(Box::new(Type::Any)),
|
||||||
),
|
),
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(Type::Range, Type::Any),
|
||||||
])
|
])
|
||||||
.required(
|
.required(
|
||||||
"row_condition",
|
"row_condition",
|
||||||
SyntaxShape::RowCondition,
|
SyntaxShape::RowCondition,
|
||||||
"Filter condition",
|
"Filter condition",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,10 @@ impl Command for Wrap {
|
|||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::List(Box::new(Type::Any)), Type::Table(vec![])),
|
(Type::List(Box::new(Type::Any)), Type::Table(vec![])),
|
||||||
(Type::Range, Type::Table(vec![])),
|
(Type::Range, Type::Table(vec![])),
|
||||||
|
(Type::Any, Type::Record(vec![])),
|
||||||
])
|
])
|
||||||
.required("name", SyntaxShape::String, "the name of the column")
|
.required("name", SyntaxShape::String, "the name of the column")
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,15 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math abs")
|
Signature::build("math abs")
|
||||||
.input_output_types(vec![(Type::Number, Type::Number)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Number),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,12 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math avg")
|
Signature::build("math avg")
|
||||||
.input_output_types(vec![(Type::List(Box::new(Type::Number)), Type::Number)])
|
.input_output_types(vec![
|
||||||
|
(Type::List(Box::new(Type::Number)), Type::Number),
|
||||||
|
(Type::List(Box::new(Type::Duration)), Type::Duration),
|
||||||
|
(Type::List(Box::new(Type::Filesize)), Type::Filesize),
|
||||||
|
])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,15 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math ceil")
|
Signature::build("math ceil")
|
||||||
.input_output_types(vec![(Type::Number, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,15 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math floor")
|
Signature::build("math floor")
|
||||||
.input_output_types(vec![(Type::Number, Type::Int)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,15 @@ impl Command for SubCommand {
|
|||||||
SyntaxShape::Number,
|
SyntaxShape::Number,
|
||||||
"Base for which the logarithm should be computed",
|
"Base for which the logarithm should be computed",
|
||||||
)
|
)
|
||||||
.input_output_types(vec![(Type::Number, Type::Float)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Float),
|
||||||
|
(Type::Number, Type::Int),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ impl Command for SubCommand {
|
|||||||
(Type::List(Box::new(Type::Number)), Type::Number),
|
(Type::List(Box::new(Type::Number)), Type::Number),
|
||||||
(Type::Table(vec![]), Type::Record(vec![])),
|
(Type::Table(vec![]), Type::Record(vec![])),
|
||||||
])
|
])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ impl Command for SubCommand {
|
|||||||
(Type::List(Box::new(Type::Number)), Type::Number),
|
(Type::List(Box::new(Type::Number)), Type::Number),
|
||||||
(Type::Table(vec![]), Type::Record(vec![])),
|
(Type::Table(vec![]), Type::Record(vec![])),
|
||||||
])
|
])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ impl Command for SubCommand {
|
|||||||
(Type::List(Box::new(Type::Number)), Type::Number),
|
(Type::List(Box::new(Type::Number)), Type::Number),
|
||||||
(Type::Table(vec![]), Type::Record(vec![])),
|
(Type::Table(vec![]), Type::Record(vec![])),
|
||||||
])
|
])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ impl Command for SubCommand {
|
|||||||
),
|
),
|
||||||
(Type::Table(vec![]), Type::Record(vec![])),
|
(Type::Table(vec![]), Type::Record(vec![])),
|
||||||
])
|
])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,13 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math round")
|
Signature::build("math round")
|
||||||
.input_output_types(vec![(Type::Number, Type::Number)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Number),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.named(
|
.named(
|
||||||
"precision",
|
"precision",
|
||||||
|
@ -12,8 +12,15 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math sqrt")
|
Signature::build("math sqrt")
|
||||||
.input_output_types(vec![(Type::Number, Type::Number)])
|
.input_output_types(vec![
|
||||||
|
(Type::Number, Type::Number),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
Type::List(Box::new(Type::Number)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,12 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("math sum")
|
Signature::build("math sum")
|
||||||
.input_output_types(vec![(Type::List(Box::new(Type::Number)), Type::Number)])
|
.input_output_types(vec![
|
||||||
|
(Type::List(Box::new(Type::Number)), Type::Number),
|
||||||
|
(Type::Range, Type::Number),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Math)
|
.category(Category::Math)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("url encode")
|
Signature::build("url encode")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![(Type::String, Type::String), (Type::List(Box::new(Type::String)), Type::List(Box::new(Type::String)))])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.switch(
|
.switch(
|
||||||
"all",
|
"all",
|
||||||
|
@ -35,6 +35,7 @@ impl Command for SubCommand {
|
|||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::String, Type::String),
|
(Type::String, Type::String),
|
||||||
(Type::List(Box::new(Type::String)), Type::String),
|
(Type::List(Box::new(Type::String)), Type::String),
|
||||||
|
(Type::Record(vec![]), Type::String),
|
||||||
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
||||||
])
|
])
|
||||||
.named(
|
.named(
|
||||||
@ -43,6 +44,7 @@ impl Command for SubCommand {
|
|||||||
"For a record or table input, join strings at the given columns",
|
"For a record or table input, join strings at the given columns",
|
||||||
Some('c'),
|
Some('c'),
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.rest("append", SyntaxShape::String, "Path to append to the input")
|
.rest("append", SyntaxShape::String, "Path to append to the input")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,12 +15,13 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("ansi strip")
|
Signature::build("ansi strip")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![(Type::String, Type::String), (Type::List(Box::new(Type::String)), Type::List(Box::new(Type::String)))])
|
||||||
.rest(
|
.rest(
|
||||||
"cell path",
|
"cell path",
|
||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
"for a data structure input, remove ANSI sequences from strings at the given cell paths",
|
"for a data structure input, remove ANSI sequences from strings at the given cell paths",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Platform)
|
.category(Category::Platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,12 @@ impl Command for Parse {
|
|||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"the pattern to match. Eg) \"{foo}: {bar}\"",
|
"the pattern to match. Eg) \"{foo}: {bar}\"",
|
||||||
)
|
)
|
||||||
.input_output_types(vec![(Type::String, Type::Table(vec![]))])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::Table(vec![])),
|
||||||
|
(Type::List(Box::new(Type::Any)), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.switch("regex", "use full regex syntax for patterns", Some('r'))
|
.switch("regex", "use full regex syntax for patterns", Some('r'))
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Strings)
|
.category(Category::Strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,8 +16,12 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("split row")
|
Signature::build("split row")
|
||||||
.input_output_types(vec![(Type::String, Type::List(Box::new(Type::String)))])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::List(Box::new(Type::String))),
|
||||||
|
(Type::List(Box::new(Type::String)), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.required(
|
.required(
|
||||||
"separator",
|
"separator",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
|
@ -17,7 +17,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str camel-case")
|
Signature::build("str camel-case")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -15,7 +15,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str capitalize")
|
Signature::build("str capitalize")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -15,7 +15,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str downcase")
|
Signature::build("str downcase")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -17,7 +17,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str kebab-case")
|
Signature::build("str kebab-case")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -17,7 +17,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str pascal-case")
|
Signature::build("str pascal-case")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -16,7 +16,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str screaming-snake-case")
|
Signature::build("str screaming-snake-case")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -16,7 +16,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str snake-case")
|
Signature::build("str snake-case")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -17,7 +17,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str title-case")
|
Signature::build("str title-case")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -14,8 +14,12 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str upcase")
|
Signature::build("str upcase")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
|
@ -32,6 +32,7 @@ impl Command for SubCommand {
|
|||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::String, Type::Bool),
|
(Type::String, Type::Bool),
|
||||||
(Type::Table(vec![]), Type::Table(vec![])),
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
(Type::List(Box::new(Type::String)), Type::List(Box::new(Type::Bool)))
|
||||||
])
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required("string", SyntaxShape::String, "the substring to find")
|
.required("string", SyntaxShape::String, "the substring to find")
|
||||||
|
@ -16,12 +16,16 @@ impl Command for StrJoin {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str join")
|
Signature::build("str join")
|
||||||
.input_output_types(vec![(Type::List(Box::new(Type::String)), Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::List(Box::new(Type::Any)), Type::String),
|
||||||
|
(Type::String, Type::String),
|
||||||
|
])
|
||||||
.optional(
|
.optional(
|
||||||
"separator",
|
"separator",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"optional separator to use when creating string",
|
"optional separator to use when creating string",
|
||||||
)
|
)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.category(Category::Strings)
|
.category(Category::Strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str length")
|
Signature::build("str length")
|
||||||
.input_output_types(vec![(Type::String, Type::Int)])
|
.input_output_types(vec![(Type::String, Type::Int), (Type::List(Box::new(Type::String)), Type::List(Box::new(Type::Int)))])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.switch(
|
.switch(
|
||||||
"grapheme-clusters",
|
"grapheme-clusters",
|
||||||
|
@ -34,7 +34,10 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str replace")
|
Signature::build("str replace")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.required("find", SyntaxShape::String, "the pattern to find")
|
.required("find", SyntaxShape::String, "the pattern to find")
|
||||||
.required("replace", SyntaxShape::String, "the replacement string")
|
.required("replace", SyntaxShape::String, "the replacement string")
|
||||||
|
@ -16,7 +16,13 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str reverse")
|
Signature::build("str reverse")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::String)),
|
||||||
|
Type::List(Box::new(Type::String)),
|
||||||
|
),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
|
@ -42,8 +42,9 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str substring")
|
Signature::build("str substring")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![(Type::String, Type::String), (Type::Table(vec![]), Type::Table(vec![]))])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.switch(
|
.switch(
|
||||||
"grapheme-clusters",
|
"grapheme-clusters",
|
||||||
"count indexes and split using grapheme clusters (all visible chars have length 1)",
|
"count indexes and split using grapheme clusters (all visible chars have length 1)",
|
||||||
|
@ -35,8 +35,16 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("str trim")
|
Signature::build("str trim")
|
||||||
.input_output_types(vec![(Type::String, Type::String)])
|
.input_output_types(vec![
|
||||||
|
(Type::String, Type::String),
|
||||||
|
(
|
||||||
|
Type::List(Box::new(Type::String)),
|
||||||
|
Type::List(Box::new(Type::String)),
|
||||||
|
),
|
||||||
|
(Type::Table(vec![]), Type::Table(vec![])),
|
||||||
|
])
|
||||||
.vectorizes_over_list(true)
|
.vectorizes_over_list(true)
|
||||||
|
.allow_variants_without_examples(true)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
|
@ -91,5 +91,5 @@ fn nth_missing_first_argument() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!("1 | drop 50");
|
let actual = nu!("1 | drop 50");
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ fn last_errors_on_negative_index() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!("1 | last");
|
let actual = nu!("1 | last");
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -32,5 +32,5 @@ fn can_round_float_with_negative_precision() {
|
|||||||
fn fails_with_wrong_input_type() {
|
fn fails_with_wrong_input_type() {
|
||||||
let actual = nu!("\"not_a_number\" | math round");
|
let actual = nu!("\"not_a_number\" | math round");
|
||||||
|
|
||||||
assert!(actual.err.contains("Input type not supported"))
|
assert!(actual.err.contains("command doesn't support"))
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,6 @@ fn print_created_paths() {
|
|||||||
pipeline(
|
pipeline(
|
||||||
r#"
|
r#"
|
||||||
mkdir -v dir_1 dir_2 dir_3
|
mkdir -v dir_1 dir_2 dir_3
|
||||||
| length
|
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ fn errors_if_no_columns_present() {
|
|||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(actual.err.contains("only record input data is supported"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,5 +14,5 @@ fn can_get_reverse_first() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!(cwd: ".", pipeline("1 | reverse"));
|
let actual = nu!(cwd: ".", pipeline("1 | reverse"));
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
@ -19,5 +19,5 @@ fn binary_skip() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!(cwd: ".", pipeline("1 | skip 2"));
|
let actual = nu!(cwd: ".", pipeline("1 | skip 2"));
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
@ -54,5 +54,5 @@ fn condition_is_met() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!(cwd: ".", pipeline("1 | skip until {|row| $row == 2}"));
|
let actual = nu!(cwd: ".", pipeline("1 | skip until {|row| $row == 2}"));
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
@ -54,5 +54,5 @@ fn condition_is_met() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!(cwd: ".", pipeline("1 | skip while {|row| $row == 2}"));
|
let actual = nu!(cwd: ".", pipeline("1 | skip while {|row| $row == 2}"));
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
@ -126,5 +126,5 @@ fn no_column_specified_fails() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!("1 | sort-by");
|
let actual = nu!("1 | sort-by");
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ fn fails_on_string() {
|
|||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -55,5 +55,5 @@ fn condition_is_met() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!(cwd: ".", pipeline("1 | take until {|row| $row == 2}"));
|
let actual = nu!(cwd: ".", pipeline("1 | take until {|row| $row == 2}"));
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
@ -54,5 +54,5 @@ fn condition_is_met() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!(cwd: ".", pipeline("1 | take while {|row| $row == 2}"));
|
let actual = nu!(cwd: ".", pipeline("1 | take while {|row| $row == 2}"));
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ fn contains_operator() {
|
|||||||
fn fail_on_non_iterator() {
|
fn fail_on_non_iterator() {
|
||||||
let actual = nu!(cwd: ".", pipeline(r#"{"name": "foo", "size": 3} | where name == "foo""#));
|
let actual = nu!(cwd: ".", pipeline(r#"{"name": "foo", "size": 3} | where name == "foo""#));
|
||||||
|
|
||||||
assert!(actual.err.contains("only_supports_this_input_type"));
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that filtering on columns that might be missing/null works
|
// Test that filtering on columns that might be missing/null works
|
||||||
|
@ -405,5 +405,5 @@ fn string_to_csv_error() {
|
|||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
assert!(actual.err.contains("can't convert"))
|
assert!(actual.err.contains("command doesn't support"))
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ fn table_to_toml_fails() {
|
|||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -83,7 +83,7 @@ fn string_to_toml_fails() {
|
|||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
assert!(actual.err.contains("command doesn't support"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
lite_parser::{lite_parse, LiteCommand, LiteElement, LitePipeline},
|
lite_parser::{lite_parse, LiteCommand, LiteElement, LitePipeline},
|
||||||
parse_mut,
|
parse_mut,
|
||||||
parse_patterns::{parse_match_pattern, parse_pattern},
|
parse_patterns::{parse_match_pattern, parse_pattern},
|
||||||
type_check::{math_result_type, type_compatible},
|
type_check::{self, math_result_type, type_compatible},
|
||||||
Token, TokenContents,
|
Token, TokenContents,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5582,6 +5582,8 @@ pub fn parse_block(
|
|||||||
|
|
||||||
block.span = Some(span);
|
block.span = Some(span);
|
||||||
|
|
||||||
|
type_check::check_block_input_output(working_set, &block);
|
||||||
|
|
||||||
block
|
block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Bits, Boolean, Comparison, Expr, Expression, Math, Operator},
|
ast::{
|
||||||
|
Bits, Block, Boolean, Comparison, Expr, Expression, Math, Operator, Pipeline,
|
||||||
|
PipelineElement,
|
||||||
|
},
|
||||||
engine::StateWorkingSet,
|
engine::StateWorkingSet,
|
||||||
ParseError, Type,
|
ParseError, Type,
|
||||||
};
|
};
|
||||||
@ -24,7 +27,30 @@ pub fn type_compatible(lhs: &Type, rhs: &Type) -> bool {
|
|||||||
|
|
||||||
match (lhs, rhs) {
|
match (lhs, rhs) {
|
||||||
(Type::List(c), Type::List(d)) => type_compatible(c, d),
|
(Type::List(c), Type::List(d)) => type_compatible(c, d),
|
||||||
(Type::List(c), Type::Table(_)) => matches!(**c, Type::Any),
|
(Type::ListStream, Type::List(_)) => true,
|
||||||
|
(Type::List(_), Type::ListStream) => true,
|
||||||
|
(Type::List(c), Type::Table(table_fields)) => {
|
||||||
|
if matches!(**c, Type::Any) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Type::Record(fields) = &**c {
|
||||||
|
is_compatible(fields, table_fields)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Type::Table(table_fields), Type::List(c)) => {
|
||||||
|
if matches!(**c, Type::Any) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Type::Record(fields) = &**c {
|
||||||
|
is_compatible(table_fields, fields)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
(Type::Number, Type::Int) => true,
|
(Type::Number, Type::Int) => true,
|
||||||
(Type::Int, Type::Number) => true,
|
(Type::Int, Type::Number) => true,
|
||||||
(Type::Number, Type::Float) => true,
|
(Type::Number, Type::Float) => true,
|
||||||
@ -921,3 +947,108 @@ pub fn math_result_type(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_pipeline_type(
|
||||||
|
working_set: &mut StateWorkingSet,
|
||||||
|
pipeline: &Pipeline,
|
||||||
|
input_type: Type,
|
||||||
|
) -> Type {
|
||||||
|
let mut current_type = input_type;
|
||||||
|
|
||||||
|
'elem: for elem in &pipeline.elements {
|
||||||
|
match elem {
|
||||||
|
PipelineElement::Expression(
|
||||||
|
_,
|
||||||
|
Expression {
|
||||||
|
expr: Expr::Call(call),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
let decl = working_set.get_decl(call.decl_id);
|
||||||
|
|
||||||
|
if current_type == Type::Any {
|
||||||
|
let mut new_current_type = None;
|
||||||
|
for (_, call_output) in decl.signature().input_output_types {
|
||||||
|
if let Some(inner_current_type) = &new_current_type {
|
||||||
|
if inner_current_type == &Type::Any {
|
||||||
|
break;
|
||||||
|
} else if inner_current_type != &call_output {
|
||||||
|
// Union unequal types to Any for now
|
||||||
|
new_current_type = Some(Type::Any)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_current_type = Some(call_output.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(new_current_type) = new_current_type {
|
||||||
|
current_type = new_current_type
|
||||||
|
} else {
|
||||||
|
current_type = Type::Any;
|
||||||
|
}
|
||||||
|
continue 'elem;
|
||||||
|
} else {
|
||||||
|
for (call_input, call_output) in decl.signature().input_output_types {
|
||||||
|
if type_compatible(&call_input, ¤t_type) {
|
||||||
|
current_type = call_output.clone();
|
||||||
|
continue 'elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !decl.signature().input_output_types.is_empty() {
|
||||||
|
working_set.error(ParseError::InputMismatch(current_type, call.head))
|
||||||
|
}
|
||||||
|
current_type = Type::Any;
|
||||||
|
}
|
||||||
|
PipelineElement::Expression(_, Expression { ty, .. }) => {
|
||||||
|
current_type = ty.clone();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
current_type = Type::Any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_block_input_output(working_set: &mut StateWorkingSet, block: &Block) {
|
||||||
|
// let inputs = block.input_types();
|
||||||
|
|
||||||
|
for (input_type, output_type) in &block.signature.input_output_types {
|
||||||
|
let mut current_type = input_type.clone();
|
||||||
|
let mut current_output_type = Type::Nothing;
|
||||||
|
|
||||||
|
for pipeline in &block.pipelines {
|
||||||
|
current_output_type = check_pipeline_type(working_set, pipeline, current_type);
|
||||||
|
current_type = Type::Nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !type_compatible(output_type, ¤t_output_type)
|
||||||
|
&& output_type != &Type::Any
|
||||||
|
&& current_output_type != Type::Any
|
||||||
|
{
|
||||||
|
working_set.error(ParseError::OutputMismatch(
|
||||||
|
output_type.clone(),
|
||||||
|
block
|
||||||
|
.pipelines
|
||||||
|
.last()
|
||||||
|
.expect("internal error: we should have pipelines")
|
||||||
|
.elements
|
||||||
|
.last()
|
||||||
|
.expect("internal error: we should have elements")
|
||||||
|
.span(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if block.signature.input_output_types.is_empty() {
|
||||||
|
let mut current_type = Type::Any;
|
||||||
|
|
||||||
|
for pipeline in &block.pipelines {
|
||||||
|
let _ = check_pipeline_type(working_set, pipeline, current_type);
|
||||||
|
current_type = Type::Nothing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::{Expr, Expression, Pipeline};
|
use super::Pipeline;
|
||||||
use crate::{ast::PipelineElement, engine::StateWorkingSet, Signature, Span, Type, VarId};
|
use crate::{ast::PipelineElement, Signature, Span, Type, VarId};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
@ -66,37 +66,6 @@ impl Block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input_type(&self, working_set: &StateWorkingSet) -> Type {
|
|
||||||
if let Some(first) = self.pipelines.first() {
|
|
||||||
if let Some(first) = first.elements.first() {
|
|
||||||
match first {
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
|
||||||
Expression {
|
|
||||||
expr: Expr::Call(call),
|
|
||||||
..
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
let decl = working_set.get_decl(call.decl_id);
|
|
||||||
|
|
||||||
decl.signature().get_input_type()
|
|
||||||
}
|
|
||||||
PipelineElement::Expression(
|
|
||||||
_,
|
|
||||||
Expression {
|
|
||||||
expr: Expr::ExternalCall(..),
|
|
||||||
..
|
|
||||||
},
|
|
||||||
) => Type::Any,
|
|
||||||
_ => Type::Nothing,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Type::Nothing
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Type::Nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn output_type(&self) -> Type {
|
pub fn output_type(&self) -> Type {
|
||||||
if let Some(last) = self.pipelines.last() {
|
if let Some(last) = self.pipelines.last() {
|
||||||
if let Some(last) = last.elements.last() {
|
if let Some(last) = last.elements.last() {
|
||||||
|
@ -48,6 +48,14 @@ pub enum ParseError {
|
|||||||
#[diagnostic(code(nu::parser::parse_mismatch_with_full_string_msg))]
|
#[diagnostic(code(nu::parser::parse_mismatch_with_full_string_msg))]
|
||||||
ExpectedWithStringMsg(String, #[label("expected {0}")] Span),
|
ExpectedWithStringMsg(String, #[label("expected {0}")] Span),
|
||||||
|
|
||||||
|
#[error("Command does not support {0} input.")]
|
||||||
|
#[diagnostic(code(nu::parser::input_type_mismatch))]
|
||||||
|
InputMismatch(Type, #[label("command doesn't support {0} input")] Span),
|
||||||
|
|
||||||
|
#[error("Command output doesn't match {0}.")]
|
||||||
|
#[diagnostic(code(nu::parser::output_type_mismatch))]
|
||||||
|
OutputMismatch(Type, #[label("command doesn't output {0}")] Span),
|
||||||
|
|
||||||
#[error("Type mismatch during operation.")]
|
#[error("Type mismatch during operation.")]
|
||||||
#[diagnostic(code(nu::parser::type_mismatch))]
|
#[diagnostic(code(nu::parser::type_mismatch))]
|
||||||
Mismatch(String, String, #[label("expected {0}, found {1}")] Span), // expected, found, span
|
Mismatch(String, String, #[label("expected {0}, found {1}")] Span), // expected, found, span
|
||||||
@ -526,6 +534,8 @@ impl ParseError {
|
|||||||
ParseError::KeywordMissingArgument(_, _, s) => *s,
|
ParseError::KeywordMissingArgument(_, _, s) => *s,
|
||||||
ParseError::MissingType(s) => *s,
|
ParseError::MissingType(s) => *s,
|
||||||
ParseError::TypeMismatch(_, _, s) => *s,
|
ParseError::TypeMismatch(_, _, s) => *s,
|
||||||
|
ParseError::InputMismatch(_, s) => *s,
|
||||||
|
ParseError::OutputMismatch(_, s) => *s,
|
||||||
ParseError::MissingRequiredFlag(_, s) => *s,
|
ParseError::MissingRequiredFlag(_, s) => *s,
|
||||||
ParseError::IncompleteMathExpression(s) => *s,
|
ParseError::IncompleteMathExpression(s) => *s,
|
||||||
ParseError::UnknownState(_, s) => *s,
|
ParseError::UnknownState(_, s) => *s,
|
||||||
|
@ -46,7 +46,7 @@ fn bits_xor_negative() -> TestResult {
|
|||||||
#[test]
|
#[test]
|
||||||
fn bits_xor_list() -> TestResult {
|
fn bits_xor_list() -> TestResult {
|
||||||
run_test(
|
run_test(
|
||||||
"[1 2 3 8 9 10] | bits xor 2 | str join '.'",
|
"[1 2 3 8 9 10] | bits xor 2 | into string | str join '.'",
|
||||||
"3.0.1.10.11.8",
|
"3.0.1.10.11.8",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ fn in_and_if_else() -> TestResult {
|
|||||||
#[test]
|
#[test]
|
||||||
fn help_works_with_missing_requirements() -> TestResult {
|
fn help_works_with_missing_requirements() -> TestResult {
|
||||||
// `each while` is part of the *extra* feature and adds 3 lines
|
// `each while` is part of the *extra* feature and adds 3 lines
|
||||||
let expected_length = if cfg!(feature = "extra") { "65" } else { "62" };
|
let expected_length = if cfg!(feature = "extra") { "66" } else { "63" };
|
||||||
run_test(r#"each --help | lines | length"#, expected_length)
|
run_test(r#"each --help | lines | length"#, expected_length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user