nu_cmd_lang/core_commands/attr/
deprecated.rs1use nu_cmd_base::WrapCall;
2use nu_engine::command_prelude::*;
3
4#[derive(Clone)]
5pub struct AttrDeprecated;
6
7impl Command for AttrDeprecated {
8 fn name(&self) -> &str {
9 "attr deprecated"
10 }
11
12 fn signature(&self) -> Signature {
13 Signature::build("attr deprecated")
14 .input_output_type(Type::Nothing, Type::record())
15 .optional(
16 "message",
17 SyntaxShape::String,
18 "Help message to include with deprecation warning.",
19 )
20 .named(
21 "flag",
22 SyntaxShape::String,
23 "Mark a flag as deprecated rather than the command",
24 None,
25 )
26 .named(
27 "since",
28 SyntaxShape::String,
29 "Denote a version when this item was deprecated",
30 Some('s'),
31 )
32 .named(
33 "remove",
34 SyntaxShape::String,
35 "Denote a version when this item will be removed",
36 Some('r'),
37 )
38 .param(
39 Flag::new("report")
40 .arg(SyntaxShape::String)
41 .desc("How to warn about this item. One of: first (default), every")
42 .completion(Completion::new_list(&["first", "every"])),
43 )
44 .category(Category::Core)
45 }
46
47 fn description(&self) -> &str {
48 "Attribute for marking a command or flag as deprecated."
49 }
50
51 fn extra_description(&self) -> &str {
52 "\
53 Mark a command (default) or flag/switch (--flag) as deprecated. \
54 By default, only the first usage will trigger a deprecation warning.\n\
55 \n\
56 A help message can be included to provide more context for the deprecation, \
57 such as what to use as a replacement.\n\
58 \n\
59 Also consider setting the category to deprecated with @category deprecated\
60 "
61 }
62
63 fn run(
64 &self,
65 engine_state: &EngineState,
66 stack: &mut Stack,
67 call: &Call,
68 _input: PipelineData,
69 ) -> Result<PipelineData, ShellError> {
70 let call = WrapCall::Eval(engine_state, stack, call);
71 Ok(deprecated_record(call)?.into_pipeline_data())
72 }
73
74 fn run_const(
75 &self,
76 working_set: &StateWorkingSet,
77 call: &Call,
78 _input: PipelineData,
79 ) -> Result<PipelineData, ShellError> {
80 let call = WrapCall::ConstEval(working_set, call);
81 Ok(deprecated_record(call)?.into_pipeline_data())
82 }
83
84 fn is_const(&self) -> bool {
85 true
86 }
87
88 fn examples(&self) -> Vec<Example<'_>> {
89 vec![
90 Example {
91 description: "Add a deprecation warning to a custom command",
92 example: r###"@deprecated
93 def outdated [] {}"###,
94 result: Some(Value::nothing(Span::test_data())),
95 },
96 Example {
97 description: "Add a deprecation warning with a custom message",
98 example: r###"@deprecated "Use my-new-command instead."
99 @category deprecated
100 def my-old-command [] {}"###,
101 result: Some(Value::string(
102 "Use my-new-command instead.",
103 Span::test_data(),
104 )),
105 },
106 ]
107 }
108}
109
110fn deprecated_record(call: WrapCall) -> Result<Value, ShellError> {
111 let (call, message): (_, Option<Spanned<String>>) = call.opt(0)?;
112 let (call, flag): (_, Option<Spanned<String>>) = call.get_flag("flag")?;
113 let (call, since): (_, Option<Spanned<String>>) = call.get_flag("since")?;
114 let (call, remove): (_, Option<Spanned<String>>) = call.get_flag("remove")?;
115 let (call, report): (_, Option<Spanned<String>>) = call.get_flag("report")?;
116
117 let mut record = Record::new();
118 if let Some(message) = message {
119 record.push("help", Value::string(message.item, message.span))
120 }
121 if let Some(flag) = flag {
122 record.push("flag", Value::string(flag.item, flag.span))
123 }
124 if let Some(since) = since {
125 record.push("since", Value::string(since.item, since.span))
126 }
127 if let Some(remove) = remove {
128 record.push("expected_removal", Value::string(remove.item, remove.span))
129 }
130
131 let report = if let Some(Spanned { item, span }) = report {
132 match item.as_str() {
133 "every" => Value::string(item, span),
134 "first" => Value::string(item, span),
135 _ => {
136 return Err(ShellError::IncorrectValue {
137 msg: "The report mode must be one of: every, first".into(),
138 val_span: span,
139 call_span: call.head(),
140 });
141 }
142 }
143 } else {
144 Value::string("first", call.head())
145 };
146 record.push("report", report);
147
148 Ok(Value::record(record, call.head()))
149}