Declare input and output types of commands (#6796)

* Add failing test that list of ints and floats is List<Number>

* Start defining subtype relation

* Make it possible to declare input and output types for commands

- Enforce them in tests

* Declare input and output types of commands

* Add formatted signatures to `help commands` table

* Revert SyntaxShape::Table -> Type::Table change

* Revert unnecessary derive(Hash) on SyntaxShape

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
This commit is contained in:
Dan Davison
2022-11-09 16:55:05 -05:00
committed by GitHub
parent f878276de7
commit df94052180
238 changed files with 2315 additions and 756 deletions

View File

@ -4,7 +4,8 @@ use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
};
use nu_utils::locale::get_system_locale_string;
use std::fmt::{Display, Write};
@ -21,6 +22,11 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("date format")
.input_output_types(vec![
(Type::Date, Type::String),
(Type::String, Type::String),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.switch("list", "lists strftime cheatsheet", Some('l'))
.optional(
"format string",
@ -66,8 +72,18 @@ impl Command for SubCommand {
fn examples(&self) -> Vec<Example> {
vec![
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Format a given date-time using the default format (RFC 2822).",
// example: r#"'2021-10-22 20:00:12 +01:00' | into datetime | date format"#,
// result: Some(Value::String {
// val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
// span: Span::test_data(),
// }),
// },
Example {
description: "Format a given date using the default format (RFC 2822).",
description:
"Format a given date-time as a string using the default format (RFC 2822).",
example: r#""2021-10-22 20:00:12 +01:00" | date format"#,
result: Some(Value::String {
val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
@ -75,13 +91,13 @@ impl Command for SubCommand {
}),
},
Example {
description: "Format a given date using a given format string.",
example: "date format '%Y-%m-%d'",
description: "Format the current date-time using a given format string.",
example: r#"date now | date format "%Y-%m-%d %H:%M:%S""#,
result: None,
},
Example {
description: "Format a given date using a given format string.",
example: r#"date format "%Y-%m-%d %H:%M:%S""#,
description: "Format the current date using a given format string.",
example: r#"date now | date format "%Y-%m-%d %H:%M:%S""#,
result: None,
},
Example {

View File

@ -3,7 +3,7 @@ use chrono::{DateTime, FixedOffset, Local};
use chrono_humanize::HumanTime;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Value};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value};
#[derive(Clone)]
pub struct SubCommand;
@ -13,7 +13,13 @@ impl Command for SubCommand {
}
fn signature(&self) -> Signature {
Signature::build("date humanize").category(Category::Date)
Signature::build("date humanize")
.input_output_types(vec![
(Type::Date, Type::String),
(Type::String, Type::String),
])
.allow_variants_without_examples(true)
.category(Category::Date)
}
fn usage(&self) -> &str {
@ -45,21 +51,11 @@ impl Command for SubCommand {
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Print a 'humanized' format for the date, relative to now.",
example: "date humanize",
result: Some(Value::String {
val: "now".to_string(),
span: Span::test_data(),
}),
},
Example {
description: "Print a 'humanized' format for the date, relative to now.",
example: r#""2021-10-22 20:00:12 +01:00" | date humanize"#,
result: None,
},
]
vec![Example {
description: "Print a 'humanized' format for the date, relative to now.",
example: r#""2021-10-22 20:00:12 +01:00" | date humanize"#,
result: None,
}]
}
}

View File

@ -2,7 +2,7 @@ use chrono_tz::TZ_VARIANTS;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, Value,
Category, Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, Type, Value,
};
#[derive(Clone)]
@ -14,7 +14,9 @@ impl Command for SubCommand {
}
fn signature(&self) -> Signature {
Signature::build("date list-timezone").category(Category::Date)
Signature::build("date list-timezone")
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
.category(Category::Date)
}
fn usage(&self) -> &str {

View File

@ -1,7 +1,7 @@
use chrono::Local;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, IntoPipelineData, PipelineData, Signature, Value};
use nu_protocol::{Category, Example, IntoPipelineData, PipelineData, Signature, Type, Value};
#[derive(Clone)]
pub struct SubCommand;
@ -11,7 +11,9 @@ impl Command for SubCommand {
}
fn signature(&self) -> Signature {
Signature::build("date now").category(Category::Date)
Signature::build("date now")
.input_output_types(vec![(Type::Nothing, Type::Date)])
.category(Category::Date)
}
fn usage(&self) -> &str {

View File

@ -2,6 +2,7 @@ use crate::date::utils::parse_date_from_string;
use chrono::{DateTime, Datelike, FixedOffset, Local, Timelike};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Type;
use nu_protocol::{
Category, Example, PipelineData, ShellError::DatetimeParseError, Signature, Span, Value,
};
@ -15,11 +16,17 @@ impl Command for SubCommand {
}
fn signature(&self) -> Signature {
Signature::build("date to-record").category(Category::Date)
Signature::build("date to-record")
.input_output_types(vec![
(Type::Date, Type::Record(vec![])),
(Type::String, Type::Record(vec![])),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.category(Category::Date)
}
fn usage(&self) -> &str {
"Convert the date into a structured table."
"Convert the date into a record."
}
fn search_terms(&self) -> Vec<&str> {
@ -38,46 +45,54 @@ impl Command for SubCommand {
}
fn examples(&self) -> Vec<Example> {
let example_result_1 = || {
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::Record { cols, vals, span })
};
vec![
Example {
description: "Convert the current date into a structured table.",
example: "date to-table",
description: "Convert the current date into a record.",
example: "date to-record",
result: None,
},
Example {
description: "Convert the current date into a structured table.",
description: "Convert the current date into a record.",
example: "date now | date to-record",
result: None,
},
Example {
description: "Convert a given date into a structured table.",
example: " '2020-04-12 22:10:57 +0200' | date to-record",
result: {
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::Record { cols, vals, span })
},
description: "Convert a date string into a record.",
example: "'2020-04-12 22:10:57 +0200' | date to-record",
result: example_result_1(),
},
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Convert a date into a record.",
// example: "'2020-04-12 22:10:57 +0200' | into datetime | date to-record",
// result: example_result_1(),
// },
]
}
}

View File

@ -2,6 +2,7 @@ use crate::date::utils::parse_date_from_string;
use chrono::{DateTime, Datelike, FixedOffset, Local, Timelike};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Type;
use nu_protocol::{
Category, Example, PipelineData, ShellError::DatetimeParseError, Signature, Span, Value,
};
@ -15,7 +16,13 @@ impl Command for SubCommand {
}
fn signature(&self) -> Signature {
Signature::build("date to-table").category(Category::Date)
Signature::build("date to-table")
.input_output_types(vec![
(Type::Date, Type::Table(vec![])),
(Type::String, Type::Table(vec![])),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.category(Category::Date)
}
fn usage(&self) -> &str {
@ -38,49 +45,57 @@ impl Command for SubCommand {
}
fn examples(&self) -> Vec<Example> {
let example_result_1 = || {
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::List {
vals: vec![Value::Record { cols, vals, span }],
span,
})
};
vec![
Example {
description: "Convert the date into a structured table.",
description: "Convert the current date into a table.",
example: "date to-table",
result: None,
},
Example {
description: "Convert the date into a structured table.",
description: "Convert the date into a table.",
example: "date now | date to-table",
result: None,
},
Example {
description: "Convert a given date into a structured table.",
example: " '2020-04-12 22:10:57 +0200' | date to-table",
result: {
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::List {
vals: vec![Value::Record { cols, vals, span }],
span,
})
},
description: "Convert a given date into a table.",
example: "'2020-04-12 22:10:57 +0200' | date to-table",
result: example_result_1(),
},
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Convert a given date into a table.",
// example: "'2020-04-12 22:10:57 +0200' | into datetime | date to-table",
// result: example_result_1(),
// },
]
}
}

View File

@ -5,7 +5,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
use chrono::{FixedOffset, TimeZone};
@ -20,6 +20,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("date to-timezone")
.input_output_types(vec![(Type::Date, Type::Date), (Type::String, Type::Date)])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.required("time zone", SyntaxShape::String, "time zone description")
.category(Category::Date)
}
@ -62,6 +64,16 @@ impl Command for SubCommand {
}
fn examples(&self) -> Vec<Example> {
let example_result_1 = || {
let dt = FixedOffset::east(5 * 3600)
.ymd(2020, 10, 10)
.and_hms(13, 00, 00);
Some(Value::Date {
val: dt,
span: Span::test_data(),
})
};
vec![
Example {
description: "Get the current date in UTC+05:00",
@ -81,19 +93,14 @@ impl Command for SubCommand {
Example {
description: "Get the current date in Hawaii",
example: r#""2020-10-10 10:00:00 +02:00" | date to-timezone "+0500""#,
// result: None
// The following should be the result of the test, but it fails. Cannot figure it out why.
result: {
let dt = FixedOffset::east(5 * 3600)
.ymd(2020, 10, 10)
.and_hms(13, 00, 00);
Some(Value::Date {
val: dt,
span: Span::test_data(),
})
},
result: example_result_1(),
},
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Get the current date in Hawaii, from a datetime object",
// example: r#""2020-10-10 10:00:00 +02:00" | into datetime | date to-timezone "+0500""#,
// result: example_result_1(),
// },
]
}
}