aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-symfony-console
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe-symfony-console')
-rw-r--r--crates/shirabe-symfony-console/src/command/command.rs13
-rw-r--r--crates/shirabe-symfony-console/src/command/complete_command.rs17
-rw-r--r--crates/shirabe-symfony-console/src/command/dump_completion_command.rs7
-rw-r--r--crates/shirabe-symfony-console/src/command/help_command.rs15
-rw-r--r--crates/shirabe-symfony-console/src/command/list_command.rs19
-rw-r--r--crates/shirabe-symfony-console/src/completion/completion_input.rs34
-rw-r--r--crates/shirabe-symfony-console/src/descriptor/json_descriptor.rs23
-rw-r--r--crates/shirabe-symfony-console/src/descriptor/markdown_descriptor.rs4
-rw-r--r--crates/shirabe-symfony-console/src/descriptor/text_descriptor.rs20
-rw-r--r--crates/shirabe-symfony-console/src/descriptor/xml_descriptor.rs18
-rw-r--r--crates/shirabe-symfony-console/src/input.rs2
-rw-r--r--crates/shirabe-symfony-console/src/input/argv_input.rs153
-rw-r--r--crates/shirabe-symfony-console/src/input/array_input.rs167
-rw-r--r--crates/shirabe-symfony-console/src/input/input.rs47
-rw-r--r--crates/shirabe-symfony-console/src/input/input_argument.rs18
-rw-r--r--crates/shirabe-symfony-console/src/input/input_definition.rs53
-rw-r--r--crates/shirabe-symfony-console/src/input/input_interface.rs23
-rw-r--r--crates/shirabe-symfony-console/src/input/input_option.rs138
-rw-r--r--crates/shirabe-symfony-console/src/input/input_value.rs146
-rw-r--r--crates/shirabe-symfony-console/src/input/string_input.rs24
20 files changed, 496 insertions, 445 deletions
diff --git a/crates/shirabe-symfony-console/src/command/command.rs b/crates/shirabe-symfony-console/src/command/command.rs
index 27966ec1..3fd39bc4 100644
--- a/crates/shirabe-symfony-console/src/command/command.rs
+++ b/crates/shirabe-symfony-console/src/command/command.rs
@@ -9,6 +9,7 @@ use crate::input::InputArgument;
use crate::input::InputDefinition;
use crate::input::InputInterface;
use crate::input::InputOption;
+use crate::input::InputValue;
use crate::output::OutputInterface;
use indexmap::IndexMap;
use shirabe_php_shim::{PhpMixed, php_regex, preg_is_match};
@@ -148,7 +149,7 @@ impl CommandData {
name: &str,
mode: Option<i64>,
description: &str,
- default: PhpMixed,
+ default: InputValue,
) -> anyhow::Result<&Self> {
self.definition
.borrow_mut()
@@ -178,10 +179,10 @@ impl CommandData {
pub fn add_option(
&self,
name: &str,
- shortcut: PhpMixed,
+ shortcut: Option<&str>,
mode: Option<i64>,
description: &str,
- default: PhpMixed,
+ default: InputValue,
) -> anyhow::Result<&Self> {
self.definition
.borrow_mut()
@@ -189,7 +190,7 @@ impl CommandData {
.unwrap()
.add_option(InputOption::new(
name,
- shortcut.clone(),
+ shortcut,
mode,
description.to_string(),
default.clone(),
@@ -403,12 +404,12 @@ pub trait Command: std::fmt::Debug + shirabe_php_shim::AsAny + shirabe_php_shim:
// It would fail the validation if we didn't make sure the command argument is present,
// since it's required by the application.
if input.borrow().has_argument("command")
- && matches!(input.borrow().get_argument("command")?, PhpMixed::Null)
+ && input.borrow().get_argument("command")?.is_null()
{
let name = self.get_name();
input
.borrow_mut()
- .set_argument("command", PhpMixed::from(name))?;
+ .set_argument("command", InputValue::from(name))?;
}
input.borrow_mut().validate()?;
diff --git a/crates/shirabe-symfony-console/src/command/complete_command.rs b/crates/shirabe-symfony-console/src/command/complete_command.rs
index 432888b6..2f540f42 100644
--- a/crates/shirabe-symfony-console/src/command/complete_command.rs
+++ b/crates/shirabe-symfony-console/src/command/complete_command.rs
@@ -7,6 +7,7 @@ use crate::completion::CompletionOutputInterface;
use crate::completion::{CompletionSuggestions, StringOrSuggestion};
use crate::input::InputInterface;
use crate::input::InputOption;
+use crate::input::InputValue;
use crate::output::OutputInterface;
use indexmap::IndexMap;
use shirabe_php_shim::{PhpMixed, impl_php_class};
@@ -191,31 +192,31 @@ impl Command for CompleteCommand {
self.inner
.add_option(
"shell",
- PhpMixed::from("s".to_string()),
+ Some("s"),
Some(InputOption::VALUE_REQUIRED),
&format!("The shell type (\"{}\")", shells),
- PhpMixed::Null,
+ InputValue::Null,
)?
.add_option(
"input",
- PhpMixed::from("i".to_string()),
+ Some("i"),
Some(InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY),
"An array of input tokens (e.g. COMP_WORDS or argv)",
- PhpMixed::Null,
+ InputValue::Null,
)?
.add_option(
"current",
- PhpMixed::from("c".to_string()),
+ Some("c"),
Some(InputOption::VALUE_REQUIRED),
"The index of the \"input\" array that the cursor is in (e.g. COMP_CWORD)",
- PhpMixed::Null,
+ InputValue::Null,
)?
.add_option(
"symfony",
- PhpMixed::from("S".to_string()),
+ Some("S"),
Some(InputOption::VALUE_REQUIRED),
"The version of the completion script",
- PhpMixed::Null,
+ InputValue::Null,
)?;
Ok(())
diff --git a/crates/shirabe-symfony-console/src/command/dump_completion_command.rs b/crates/shirabe-symfony-console/src/command/dump_completion_command.rs
index 4db6c233..49a66f6d 100644
--- a/crates/shirabe-symfony-console/src/command/dump_completion_command.rs
+++ b/crates/shirabe-symfony-console/src/command/dump_completion_command.rs
@@ -6,6 +6,7 @@ use crate::completion::{CompletionSuggestions, StringOrSuggestion};
use crate::input::InputArgument;
use crate::input::InputInterface;
use crate::input::InputOption;
+use crate::input::InputValue;
use crate::output::OutputInterface;
use crate::output::output_interface;
use shirabe_php_shim::{PhpMixed, impl_php_class};
@@ -189,14 +190,14 @@ impl Command for DumpCompletionCommand {
"shell",
Some(InputArgument::OPTIONAL),
"The shell type (e.g. \"bash\"), the value of the \"$SHELL\" env var will be used if this is not given",
- PhpMixed::Null,
+ InputValue::Null,
)?;
self.inner.add_option(
"debug",
- PhpMixed::Null,
+ None,
Some(InputOption::VALUE_NONE),
"Tail the completion debug log",
- PhpMixed::Null,
+ InputValue::Null,
)?;
Ok(())
diff --git a/crates/shirabe-symfony-console/src/command/help_command.rs b/crates/shirabe-symfony-console/src/command/help_command.rs
index 2081e0e1..4d8f7dbd 100644
--- a/crates/shirabe-symfony-console/src/command/help_command.rs
+++ b/crates/shirabe-symfony-console/src/command/help_command.rs
@@ -10,8 +10,9 @@ use crate::input::DefinitionItem;
use crate::input::InputArgument;
use crate::input::InputInterface;
use crate::input::InputOption;
+use crate::input::InputValue;
use crate::output::OutputInterface;
-use shirabe_php_shim::{PhpMixed, impl_php_class};
+use shirabe_php_shim::impl_php_class;
use std::ops::{Deref, DerefMut};
/// HelpCommand displays the help for a given command.
@@ -101,21 +102,21 @@ impl Command for HelpCommand {
"command_name".to_string(),
Some(InputArgument::OPTIONAL),
"The command name".to_string(),
- PhpMixed::from("help".to_string()),
+ InputValue::from("help".to_string()),
)?),
DefinitionItem::InputOption(InputOption::new(
"format",
- PhpMixed::Null,
+ None,
Some(InputOption::VALUE_REQUIRED),
"The output format (txt, xml, json, or md)".to_string(),
- PhpMixed::from("txt".to_string()),
+ InputValue::from("txt".to_string()),
)?),
DefinitionItem::InputOption(InputOption::new(
"raw",
- PhpMixed::Null,
+ None,
Some(InputOption::VALUE_NONE),
"To output raw command help".to_string(),
- PhpMixed::Null,
+ InputValue::Null,
)?),
]));
self.inner.set_description("Display help for a command");
@@ -141,7 +142,7 @@ impl Command for HelpCommand {
) -> anyhow::Result<i64> {
if self.command.borrow().is_none() {
let application = self.get_application().unwrap();
- let command_name = input.borrow().get_argument("command_name")?.to_string();
+ let command_name = input.borrow().get_argument("command_name")?.to_php_string();
let found = application.borrow_mut().find(&command_name)?;
*self.command.borrow_mut() = Some(found);
}
diff --git a/crates/shirabe-symfony-console/src/command/list_command.rs b/crates/shirabe-symfony-console/src/command/list_command.rs
index 6074b49a..08faea71 100644
--- a/crates/shirabe-symfony-console/src/command/list_command.rs
+++ b/crates/shirabe-symfony-console/src/command/list_command.rs
@@ -10,8 +10,9 @@ use crate::input::DefinitionItem;
use crate::input::InputArgument;
use crate::input::InputInterface;
use crate::input::InputOption;
+use crate::input::InputValue;
use crate::output::OutputInterface;
-use shirabe_php_shim::{PhpMixed, impl_php_class};
+use shirabe_php_shim::impl_php_class;
use std::ops::{Deref, DerefMut};
/// ListCommand displays the list of all available commands for the application.
@@ -93,28 +94,28 @@ impl Command for ListCommand {
"namespace".to_string(),
Some(InputArgument::OPTIONAL),
"The namespace name".to_string(),
- PhpMixed::Null,
+ InputValue::Null,
)?),
DefinitionItem::InputOption(InputOption::new(
"raw",
- PhpMixed::Null,
+ None,
Some(InputOption::VALUE_NONE),
"To output raw command list".to_string(),
- PhpMixed::Null,
+ InputValue::Null,
)?),
DefinitionItem::InputOption(InputOption::new(
"format",
- PhpMixed::Null,
+ None,
Some(InputOption::VALUE_REQUIRED),
"The output format (txt, xml, json, or md)".to_string(),
- PhpMixed::from("txt".to_string()),
+ InputValue::from("txt".to_string()),
)?),
DefinitionItem::InputOption(InputOption::new(
"short",
- PhpMixed::Null,
+ None,
Some(InputOption::VALUE_NONE),
"To skip describing commands' arguments".to_string(),
- PhpMixed::Null,
+ InputValue::Null,
)?),
]));
self.inner.set_description("List commands");
@@ -157,7 +158,7 @@ impl Command for ListCommand {
);
options.insert(
"namespace".to_string(),
- input.borrow().get_argument("namespace")?,
+ input.borrow().get_argument("namespace")?.into(),
);
options.insert(
"short".to_string(),
diff --git a/crates/shirabe-symfony-console/src/completion/completion_input.rs b/crates/shirabe-symfony-console/src/completion/completion_input.rs
index c667ef60..419e6e80 100644
--- a/crates/shirabe-symfony-console/src/completion/completion_input.rs
+++ b/crates/shirabe-symfony-console/src/completion/completion_input.rs
@@ -3,7 +3,8 @@
use crate::input::ArgvInput;
use crate::input::InputDefinition;
use crate::input::InputOption;
-use shirabe_php_shim::{PhpMixed, php_regex, preg_match_all};
+use crate::input::InputValue;
+use shirabe_php_shim::{php_regex, preg_match_all};
/// An input specialized for shell completion.
///
@@ -148,13 +149,10 @@ impl CompletionInput {
let argument_value = self.inner.inner.arguments[&current_argument_name].clone();
self.completion_name = Some(current_argument_name.clone());
- if let PhpMixed::List(argument_value) = &argument_value {
- self.completion_value = argument_value
- .last()
- .map(|v| v.to_string())
- .unwrap_or_default();
+ if let InputValue::Array(argument_value) = &argument_value {
+ self.completion_value = argument_value.last().cloned().unwrap_or_default();
} else {
- self.completion_value = argument_value.to_string();
+ self.completion_value = argument_value.to_php_string();
}
}
@@ -165,7 +163,7 @@ impl CompletionInput {
.inner
.inner
.definition
- .get_argument(&PhpMixed::String(argument_name.clone()))
+ .get_argument(&crate::input::ArgumentName::of(&argument_name))
.unwrap()
.is_array()
{
@@ -304,16 +302,16 @@ impl crate::input::InputInterface for CompletionInput {
self.to_string()
}
- fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool {
+ fn has_parameter_option(&self, values: &[&str], only_params: bool) -> bool {
crate::input::InputInterface::has_parameter_option(&self.inner, values, only_params)
}
fn get_parameter_option(
&self,
- values: PhpMixed,
- default: PhpMixed,
+ values: &[&str],
+ default: InputValue,
only_params: bool,
- ) -> PhpMixed {
+ ) -> InputValue {
crate::input::InputInterface::get_parameter_option(
&self.inner,
values,
@@ -330,15 +328,15 @@ impl crate::input::InputInterface for CompletionInput {
crate::input::InputInterface::validate(&mut self.inner)
}
- fn get_arguments(&self) -> indexmap::IndexMap<String, PhpMixed> {
+ fn get_arguments(&self) -> indexmap::IndexMap<String, InputValue> {
crate::input::InputInterface::get_arguments(&self.inner)
}
- fn get_argument(&self, name: &str) -> anyhow::Result<PhpMixed> {
+ fn get_argument(&self, name: &str) -> anyhow::Result<InputValue> {
crate::input::InputInterface::get_argument(&self.inner, name)
}
- fn set_argument(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn set_argument(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
crate::input::InputInterface::set_argument(&mut self.inner, name, value)
}
@@ -346,15 +344,15 @@ impl crate::input::InputInterface for CompletionInput {
crate::input::InputInterface::has_argument(&self.inner, name)
}
- fn get_options(&self) -> indexmap::IndexMap<String, PhpMixed> {
+ fn get_options(&self) -> indexmap::IndexMap<String, InputValue> {
crate::input::InputInterface::get_options(&self.inner)
}
- fn get_option(&self, name: &str) -> anyhow::Result<crate::input::InputOptionValue> {
+ fn get_option(&self, name: &str) -> anyhow::Result<InputValue> {
crate::input::InputInterface::get_option(&self.inner, name)
}
- fn set_option(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn set_option(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
crate::input::InputInterface::set_option(&mut self.inner, name, value)
}
diff --git a/crates/shirabe-symfony-console/src/descriptor/json_descriptor.rs b/crates/shirabe-symfony-console/src/descriptor/json_descriptor.rs
index 53941663..97c1c4f1 100644
--- a/crates/shirabe-symfony-console/src/descriptor/json_descriptor.rs
+++ b/crates/shirabe-symfony-console/src/descriptor/json_descriptor.rs
@@ -165,14 +165,9 @@ impl JsonDescriptor {
argument.get_description(),
)),
);
- data.insert(
- "default".to_string(),
- if matches!(argument.get_default(), PhpMixed::Float(f) if f.is_infinite() && *f > 0.0) {
- PhpMixed::String("INF".to_string())
- } else {
- argument.get_default().clone()
- },
- );
+ // TODO(type-model): PHP compares the default against `INF` and serializes it as the
+ // string "INF"; `InputValue` has no float variant to hold one.
+ data.insert("default".to_string(), argument.get_default().clone().into());
Ok(data)
}
@@ -226,15 +221,9 @@ impl JsonDescriptor {
option.get_description(),
)),
);
- data.insert(
- "default".to_string(),
- if matches!(option.get_default(), PhpMixed::Float(f) if f.is_infinite() && *f > 0.0)
- {
- PhpMixed::String("INF".to_string())
- } else {
- option.get_default().clone()
- },
- );
+ // TODO(type-model): PHP compares the default against `INF` and serializes it as the
+ // string "INF"; `InputValue` has no float variant to hold one.
+ data.insert("default".to_string(), option.get_default().clone().into());
}
Ok(data)
}
diff --git a/crates/shirabe-symfony-console/src/descriptor/markdown_descriptor.rs b/crates/shirabe-symfony-console/src/descriptor/markdown_descriptor.rs
index d6285468..f7b3cd71 100644
--- a/crates/shirabe-symfony-console/src/descriptor/markdown_descriptor.rs
+++ b/crates/shirabe-symfony-console/src/descriptor/markdown_descriptor.rs
@@ -64,7 +64,7 @@ impl MarkdownDescriptor {
shirabe_php_shim::str_replace(
"\n",
"",
- &shirabe_php_shim::var_export(argument.get_default(), true),
+ &shirabe_php_shim::var_export(&argument.get_default().to_php_mixed(), true),
),
),
true,
@@ -104,7 +104,7 @@ impl MarkdownDescriptor {
shirabe_php_shim::str_replace(
"\n",
"",
- &shirabe_php_shim::var_export(option.get_default(), true),
+ &shirabe_php_shim::var_export(&option.get_default().to_php_mixed(), true),
),
),
true,
diff --git a/crates/shirabe-symfony-console/src/descriptor/text_descriptor.rs b/crates/shirabe-symfony-console/src/descriptor/text_descriptor.rs
index 8783ef5e..c15cdebb 100644
--- a/crates/shirabe-symfony-console/src/descriptor/text_descriptor.rs
+++ b/crates/shirabe-symfony-console/src/descriptor/text_descriptor.rs
@@ -36,15 +36,14 @@ impl TextDescriptor {
argument: &InputArgument,
options: IndexMap<String, PhpMixed>,
) -> anyhow::Result<()> {
- let default = if !argument.get_default().is_null()
- && (!matches!(
- argument.get_default(),
- PhpMixed::List(_) | PhpMixed::Array(_)
- ) || shirabe_php_shim::count(argument.get_default()) != 0)
+ let default_value = argument.get_default().to_php_mixed();
+ let default = if !default_value.is_null()
+ && (!matches!(default_value, PhpMixed::List(_) | PhpMixed::Array(_))
+ || shirabe_php_shim::count(&default_value) != 0)
{
format!(
"<comment> [default: {}]</comment>",
- self.format_default_value(argument.get_default())?
+ self.format_default_value(&default_value)?
)
} else {
String::new()
@@ -82,14 +81,15 @@ impl TextDescriptor {
option: &InputOption,
options: IndexMap<String, PhpMixed>,
) -> anyhow::Result<()> {
+ let default_value = option.get_default().to_php_mixed();
let default = if option.accept_value()
- && !option.get_default().is_null()
- && (!matches!(option.get_default(), PhpMixed::List(_) | PhpMixed::Array(_))
- || shirabe_php_shim::count(option.get_default()) != 0)
+ && !default_value.is_null()
+ && (!matches!(default_value, PhpMixed::List(_) | PhpMixed::Array(_))
+ || shirabe_php_shim::count(&default_value) != 0)
{
format!(
"<comment> [default: {}]</comment>",
- self.format_default_value(option.get_default())?
+ self.format_default_value(&default_value)?
)
} else {
String::new()
diff --git a/crates/shirabe-symfony-console/src/descriptor/xml_descriptor.rs b/crates/shirabe-symfony-console/src/descriptor/xml_descriptor.rs
index 1a001b22..0b74fe3a 100644
--- a/crates/shirabe-symfony-console/src/descriptor/xml_descriptor.rs
+++ b/crates/shirabe-symfony-console/src/descriptor/xml_descriptor.rs
@@ -233,13 +233,14 @@ impl XmlDescriptor {
description_xml.append_child(dom.create_text_node(argument.get_description()));
let defaults_xml = object_xml.append_child(dom.create_element("defaults"));
- let defaults: Vec<String> = match argument.get_default() {
+ let default_value = argument.get_default().to_php_mixed();
+ let defaults: Vec<String> = match &default_value {
PhpMixed::List(_) | PhpMixed::Array(_) => {
- self.default_values_as_strings(argument.get_default())
+ self.default_values_as_strings(&default_value)
}
- PhpMixed::Bool(_) => vec![shirabe_php_shim::var_export(argument.get_default(), true)],
+ PhpMixed::Bool(_) => vec![shirabe_php_shim::var_export(&default_value, true)],
d if shirabe_php_shim::php_truthy(d) => {
- vec![shirabe_php_shim::php_to_string(argument.get_default())]
+ vec![shirabe_php_shim::php_to_string(&default_value)]
}
_ => vec![],
};
@@ -294,13 +295,14 @@ impl XmlDescriptor {
description_xml.append_child(dom.create_text_node(option.get_description()));
if option.accept_value() {
- let defaults: Vec<String> = match option.get_default() {
+ let default_value = option.get_default().to_php_mixed();
+ let defaults: Vec<String> = match &default_value {
PhpMixed::List(_) | PhpMixed::Array(_) => {
- self.default_values_as_strings(option.get_default())
+ self.default_values_as_strings(&default_value)
}
- PhpMixed::Bool(_) => vec![shirabe_php_shim::var_export(option.get_default(), true)],
+ PhpMixed::Bool(_) => vec![shirabe_php_shim::var_export(&default_value, true)],
d if shirabe_php_shim::php_truthy(d) => {
- vec![shirabe_php_shim::php_to_string(option.get_default())]
+ vec![shirabe_php_shim::php_to_string(&default_value)]
}
_ => vec![],
};
diff --git a/crates/shirabe-symfony-console/src/input.rs b/crates/shirabe-symfony-console/src/input.rs
index f05188fe..c09e590f 100644
--- a/crates/shirabe-symfony-console/src/input.rs
+++ b/crates/shirabe-symfony-console/src/input.rs
@@ -6,6 +6,7 @@ mod input_aware_interface;
mod input_definition;
mod input_interface;
mod input_option;
+mod input_value;
mod streamable_input_interface;
mod string_input;
@@ -17,5 +18,6 @@ pub use input_aware_interface::*;
pub use input_definition::*;
pub use input_interface::*;
pub use input_option::*;
+pub use input_value::*;
pub use streamable_input_interface::*;
pub use string_input::*;
diff --git a/crates/shirabe-symfony-console/src/input/argv_input.rs b/crates/shirabe-symfony-console/src/input/argv_input.rs
index 6138c195..a0f1d4d3 100644
--- a/crates/shirabe-symfony-console/src/input/argv_input.rs
+++ b/crates/shirabe-symfony-console/src/input/argv_input.rs
@@ -1,13 +1,14 @@
//! ref: composer/vendor/symfony/console/Input/ArgvInput.php
use crate::exception::RuntimeException;
+use crate::input::ArgumentName;
use crate::input::Input;
use crate::input::InputDefinition;
use crate::input::InputInterface;
-use crate::input::InputOptionValue;
+use crate::input::InputValue;
use crate::input::StreamableInputInterface;
use indexmap::IndexMap;
-use shirabe_php_shim::{PhpMixed, php_regex, preg_match};
+use shirabe_php_shim::{php_regex, preg_match};
/// ArgvInput represents an input coming from the CLI arguments.
///
@@ -144,13 +145,13 @@ impl ArgvInput {
// an option with a value (with no space)
self.add_short_option(
&first,
- PhpMixed::String(shirabe_php_shim::substr(&name, 1, None)),
+ InputValue::String(shirabe_php_shim::substr(&name, 1, None)),
)?;
} else {
self.parse_short_option_set(&name)?;
}
} else {
- self.add_short_option(&name, PhpMixed::Null)?;
+ self.add_short_option(&name, InputValue::Null)?;
}
Ok(())
@@ -180,15 +181,15 @@ impl ArgvInput {
let option = self.inner.definition.get_option_for_shortcut(&name_i)?;
if option.accept_value() {
let value = if i == len - 1 {
- PhpMixed::Null
+ InputValue::Null
} else {
- PhpMixed::String(shirabe_php_shim::substr(name, i + 1, None))
+ InputValue::String(shirabe_php_shim::substr(name, i + 1, None))
};
self.add_long_option(option.get_name(), value)?;
break;
} else {
- self.add_long_option(option.get_name(), PhpMixed::Null)?;
+ self.add_long_option(option.get_name(), InputValue::Null)?;
}
i += 1;
}
@@ -209,11 +210,11 @@ impl ArgvInput {
}
self.add_long_option(
&shirabe_php_shim::substr(&name, 0, Some(pos)),
- PhpMixed::String(value),
+ InputValue::String(value),
)?;
}
None => {
- self.add_long_option(&name, PhpMixed::Null)?;
+ self.add_long_option(&name, InputValue::Null)?;
}
}
@@ -225,34 +226,47 @@ impl ArgvInput {
let c = self.inner.arguments.len() as i64;
// if input is expecting another argument, add it
- if self.inner.definition.has_argument(&PhpMixed::Int(c)) {
- let arg = self.inner.definition.get_argument(&PhpMixed::Int(c))?;
+ if self
+ .inner
+ .definition
+ .has_argument(&ArgumentName::Position(c))
+ {
+ let arg = self
+ .inner
+ .definition
+ .get_argument(&ArgumentName::Position(c))?;
let value = if arg.is_array() {
- PhpMixed::List(vec![PhpMixed::String(token.to_string())])
+ InputValue::Array(vec![token.to_string()])
} else {
- PhpMixed::String(token.to_string())
+ InputValue::String(token.to_string())
};
self.inner
.arguments
.insert(arg.get_name().to_string(), value);
// if last argument isArray(), append token to last argument
- } else if self.inner.definition.has_argument(&PhpMixed::Int(c - 1))
+ } else if self
+ .inner
+ .definition
+ .has_argument(&ArgumentName::Position(c - 1))
&& self
.inner
.definition
- .get_argument(&PhpMixed::Int(c - 1))?
+ .get_argument(&ArgumentName::Position(c - 1))?
.is_array()
{
- let arg = self.inner.definition.get_argument(&PhpMixed::Int(c - 1))?;
- if let Some(PhpMixed::List(list)) = self.inner.arguments.get_mut(arg.get_name()) {
- list.push(PhpMixed::String(token.to_string()));
+ let arg = self
+ .inner
+ .definition
+ .get_argument(&ArgumentName::Position(c - 1))?;
+ if let Some(InputValue::Array(list)) = self.inner.arguments.get_mut(arg.get_name()) {
+ list.push(token.to_string());
}
// unexpected argument
} else {
let mut all = self.inner.definition.get_arguments().clone();
- let mut symfony_command_name: Option<PhpMixed> = None;
+ let mut symfony_command_name: Option<InputValue> = None;
let first_key = all.keys().next().cloned();
if let Some(key) = &first_key {
let input_argument = &all[key];
@@ -265,12 +279,10 @@ impl ArgvInput {
let message = if !all.is_empty() {
let names: Vec<String> = all.keys().cloned().collect();
match &symfony_command_name {
- Some(symfony_command_name)
- if !matches!(symfony_command_name, PhpMixed::Null) =>
- {
+ Some(symfony_command_name) if !symfony_command_name.is_null() => {
format!(
"Too many arguments to \"{}\" command, expected arguments \"{}\".",
- symfony_command_name.clone(),
+ symfony_command_name.to_php_string(),
shirabe_php_shim::implode("\" \"", &names),
)
}
@@ -281,12 +293,12 @@ impl ArgvInput {
}
} else if symfony_command_name
.as_ref()
- .map(|n| !matches!(n, PhpMixed::Null))
+ .map(|n| !n.is_null())
.unwrap_or(false)
{
format!(
"No arguments expected for \"{}\" command, got \"{}\".",
- symfony_command_name.unwrap(),
+ symfony_command_name.unwrap().to_php_string(),
token,
)
} else {
@@ -300,7 +312,7 @@ impl ArgvInput {
}
/// Adds a short option value.
- fn add_short_option(&mut self, shortcut: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn add_short_option(&mut self, shortcut: &str, value: InputValue) -> anyhow::Result<()> {
if !self.inner.definition.has_shortcut(shortcut) {
return Err(RuntimeException::new(format!(
"The \"-{}\" option does not exist.",
@@ -319,7 +331,7 @@ impl ArgvInput {
}
/// Adds a long option value.
- fn add_long_option(&mut self, name: &str, mut value: PhpMixed) -> anyhow::Result<()> {
+ fn add_long_option(&mut self, name: &str, mut value: InputValue) -> anyhow::Result<()> {
if !self.inner.definition.has_option(name) {
if !self.inner.definition.has_negation(name) {
return Err(RuntimeException::new(format!(
@@ -330,7 +342,7 @@ impl ArgvInput {
}
let option_name = self.inner.definition.negation_to_name(name)?;
- if !matches!(value, PhpMixed::Null) {
+ if !value.is_null() {
return Err(RuntimeException::new(format!(
"The \"--{}\" option does not accept a value.",
name
@@ -339,14 +351,14 @@ impl ArgvInput {
}
self.inner
.options
- .insert(option_name, PhpMixed::Bool(false));
+ .insert(option_name, InputValue::Bool(false));
return Ok(());
}
let option = self.inner.definition.get_option(name)?;
- if !matches!(value, PhpMixed::Null) && !option.accept_value() {
+ if !value.is_null() && !option.accept_value() {
return Err(RuntimeException::new(format!(
"The \"--{}\" option does not accept a value.",
name
@@ -355,8 +367,8 @@ impl ArgvInput {
}
// in_array($value, ['', null], true)
- let value_is_empty_or_null = matches!(&value, PhpMixed::String(s) if s.is_empty())
- || matches!(value, PhpMixed::Null);
+ let value_is_empty_or_null =
+ matches!(&value, InputValue::String(s) if s.is_empty()) || value.is_null();
if value_is_empty_or_null && option.accept_value() && !self.parsed.is_empty() {
// if option accepts an optional or mandatory argument
// let's see if there is one provided
@@ -364,13 +376,13 @@ impl ArgvInput {
// (isset($next[0]) && '-' !== $next[0]) || in_array($next, ['', null], true)
let next_first = next.as_bytes().first().copied();
if (next_first.is_some() && next_first != Some(b'-')) || next.is_empty() {
- value = PhpMixed::String(next);
+ value = InputValue::String(next);
} else {
self.parsed.insert(0, next);
}
}
- if matches!(value, PhpMixed::Null) {
+ if value.is_null() {
if option.is_value_required() {
return Err(RuntimeException::new(format!(
"The \"--{}\" option requires a value.",
@@ -380,19 +392,25 @@ impl ArgvInput {
}
if !option.is_array() && !option.is_value_optional() {
- value = PhpMixed::Bool(true);
+ value = InputValue::Bool(true);
}
}
if option.is_array() {
+ // TODO(type-model): PHP appends the value as it stands, so a
+ // VALUE_OPTIONAL|VALUE_IS_ARRAY option given no value collects a null;
+ // `InputValue::Array` only holds strings.
+ let InputValue::String(value) = value else {
+ panic!("an array option cannot hold {:?}", value)
+ };
match self.inner.options.get_mut(name) {
- Some(PhpMixed::List(list)) => {
+ Some(InputValue::Array(list)) => {
list.push(value);
}
_ => {
self.inner
.options
- .insert(name.to_string(), PhpMixed::List(vec![value]));
+ .insert(name.to_string(), InputValue::Array(vec![value]));
}
}
} else {
@@ -448,21 +466,19 @@ impl ArgvInput {
None
}
- pub fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool {
- let values = to_array(values);
-
+ pub fn has_parameter_option(&self, values: &[&str], only_params: bool) -> bool {
for token in &self.tokens {
if only_params && token == "--" {
return false;
}
- for value in &values {
+ for value in values {
// Options with values:
// For long options, test for '--option=' at beginning
// For short options, test for '-o' at beginning
let leading = if value.starts_with("--") {
format!("{}=", value)
} else {
- value.clone()
+ value.to_string()
};
if token == value || (!leading.is_empty() && token.starts_with(&leading)) {
return true;
@@ -475,11 +491,10 @@ impl ArgvInput {
pub fn get_parameter_option(
&self,
- values: PhpMixed,
- default: PhpMixed,
+ values: &[&str],
+ default: InputValue,
only_params: bool,
- ) -> PhpMixed {
- let values = to_array(values);
+ ) -> InputValue {
let mut tokens = self.tokens.clone();
while !tokens.is_empty() {
@@ -488,11 +503,11 @@ impl ArgvInput {
return default;
}
- for value in &values {
+ for value in values {
if &token == value {
return match tokens.first() {
- Some(_) => PhpMixed::String(tokens.remove(0)),
- None => PhpMixed::Null,
+ Some(_) => InputValue::String(tokens.remove(0)),
+ None => InputValue::Null,
};
}
// Options with values:
@@ -501,10 +516,10 @@ impl ArgvInput {
let leading = if value.starts_with("--") {
format!("{}=", value)
} else {
- value.clone()
+ value.to_string()
};
if !leading.is_empty() && token.starts_with(&leading) {
- return PhpMixed::String(shirabe_php_shim::substr(
+ return InputValue::String(shirabe_php_shim::substr(
&token,
shirabe_php_shim::strlen(&leading),
None,
@@ -553,16 +568,16 @@ impl InputInterface for ArgvInput {
ArgvInput::get_first_argument(self)
}
- fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool {
+ fn has_parameter_option(&self, values: &[&str], only_params: bool) -> bool {
ArgvInput::has_parameter_option(self, values, only_params)
}
fn get_parameter_option(
&self,
- values: PhpMixed,
- default: PhpMixed,
+ values: &[&str],
+ default: InputValue,
only_params: bool,
- ) -> PhpMixed {
+ ) -> InputValue {
ArgvInput::get_parameter_option(self, values, default, only_params)
}
@@ -574,15 +589,15 @@ impl InputInterface for ArgvInput {
self.inner.validate()
}
- fn get_arguments(&self) -> IndexMap<String, PhpMixed> {
+ fn get_arguments(&self) -> IndexMap<String, InputValue> {
self.inner.get_arguments()
}
- fn get_argument(&self, name: &str) -> anyhow::Result<PhpMixed> {
+ fn get_argument(&self, name: &str) -> anyhow::Result<InputValue> {
self.inner.get_argument(name)
}
- fn set_argument(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn set_argument(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
self.inner.set_argument(name, value)
}
@@ -590,15 +605,15 @@ impl InputInterface for ArgvInput {
self.inner.has_argument(name)
}
- fn get_options(&self) -> IndexMap<String, PhpMixed> {
+ fn get_options(&self) -> IndexMap<String, InputValue> {
self.inner.get_options()
}
- fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue> {
+ fn get_option(&self, name: &str) -> anyhow::Result<InputValue> {
self.inner.get_option(name)
}
- fn set_option(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn set_option(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
self.inner.set_option(name, value)
}
@@ -636,19 +651,3 @@ impl StreamableInputInterface for ArgvInput {
self.inner.get_stream()
}
}
-
-/// PHP `(array) $values` cast: a string becomes a single-element array.
-fn to_array(values: PhpMixed) -> Vec<String> {
- match values {
- PhpMixed::List(list) => list
- .into_iter()
- .map(|v| shirabe_php_shim::php_to_string(&v))
- .collect(),
- PhpMixed::Array(array) => array
- .into_iter()
- .map(|(_, v)| shirabe_php_shim::php_to_string(&v))
- .collect(),
- PhpMixed::Null => vec![],
- other => vec![shirabe_php_shim::php_to_string(&other)],
- }
-}
diff --git a/crates/shirabe-symfony-console/src/input/array_input.rs b/crates/shirabe-symfony-console/src/input/array_input.rs
index c9bc9dce..437bdde2 100644
--- a/crates/shirabe-symfony-console/src/input/array_input.rs
+++ b/crates/shirabe-symfony-console/src/input/array_input.rs
@@ -2,13 +2,13 @@
use crate::exception::InvalidArgumentException;
use crate::exception::InvalidOptionException;
+use crate::input::ArgumentName;
use crate::input::Input;
use crate::input::InputDefinition;
use crate::input::InputInterface;
-use crate::input::InputOptionValue;
+use crate::input::InputValue;
use crate::input::StreamableInputInterface;
use indexmap::IndexMap;
-use shirabe_php_shim::PhpMixed;
/// ArrayInput represents an input provided as an array.
///
@@ -19,16 +19,16 @@ use shirabe_php_shim::PhpMixed;
/// ```
///
/// PHP arrays can mix integer and string keys; `parameters` preserves both the
-/// key type (`PhpMixed::Int` / `PhpMixed::String`) and the insertion order.
+/// key type and the insertion order.
#[derive(Debug, Clone)]
pub struct ArrayInput {
inner: Input,
- parameters: Vec<(PhpMixed, PhpMixed)>,
+ parameters: Vec<(ParameterName, InputValue)>,
}
impl ArrayInput {
pub fn new(
- parameters: Vec<(PhpMixed, PhpMixed)>,
+ parameters: Vec<(ParameterName, InputValue)>,
definition: Option<InputDefinition>,
) -> anyhow::Result<Self> {
let mut array_input = ArrayInput {
@@ -58,10 +58,10 @@ impl ArrayInput {
Ok(())
}
- pub fn get_first_argument(&self) -> Option<PhpMixed> {
+ pub fn get_first_argument(&self) -> Option<InputValue> {
for (param, value) in &self.parameters {
// $param && \is_string($param) && '-' === $param[0]
- if let PhpMixed::String(param) = param
+ if let ParameterName::Name(param) = param
&& !param.is_empty()
&& param.as_bytes()[0] == b'-'
{
@@ -74,21 +74,19 @@ impl ArrayInput {
None
}
- pub fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool {
- let values = to_array(values);
-
+ pub fn has_parameter_option(&self, values: &[&str], only_params: bool) -> bool {
for (k, v) in &self.parameters {
// if (!\is_int($k)) { $v = $k; }
- let v: PhpMixed = match k {
- PhpMixed::Int(_) => v.clone(),
- _ => k.clone(),
+ let v = match k {
+ ParameterName::Index(_) => v.as_string(),
+ ParameterName::Name(k) => Some(k.as_str()),
};
- if only_params && matches!(&v, PhpMixed::String(s) if s == "--") {
+ if only_params && v == Some("--") {
return false;
}
- if values.iter().any(|x| x == &v) {
+ if v.is_some_and(|v| values.contains(&v)) {
return true;
}
}
@@ -98,31 +96,29 @@ impl ArrayInput {
pub fn get_parameter_option(
&self,
- values: PhpMixed,
- default: PhpMixed,
+ values: &[&str],
+ default: InputValue,
only_params: bool,
- ) -> PhpMixed {
- let values = to_array(values);
-
+ ) -> InputValue {
for (k, v) in &self.parameters {
// $onlyParams && ('--' === $k || (\is_int($k) && '--' === $v))
if only_params {
- let k_is_double_dash = matches!(k, PhpMixed::String(s) if s == "--");
+ let k_is_double_dash = matches!(k, ParameterName::Name(k) if k == "--");
let int_v_double_dash =
- matches!(k, PhpMixed::Int(_)) && matches!(v, PhpMixed::String(s) if s == "--");
+ matches!(k, ParameterName::Index(_)) && v.as_string() == Some("--");
if k_is_double_dash || int_v_double_dash {
return default;
}
}
match k {
- PhpMixed::Int(_) => {
- if values.iter().any(|x| x == v) {
- return PhpMixed::Bool(true);
+ ParameterName::Index(_) => {
+ if v.as_string().is_some_and(|v| values.contains(&v)) {
+ return InputValue::Bool(true);
}
}
- _ => {
- if values.iter().any(|x| x == k) {
+ ParameterName::Name(k) => {
+ if values.contains(&k.as_str()) {
return v.clone();
}
}
@@ -136,16 +132,17 @@ impl ArrayInput {
// Clone to avoid borrowing self while mutating; PHP iterates over a copy semantically.
let parameters = self.parameters.clone();
for (key, value) in parameters {
- let key = shirabe_php_shim::php_to_string(&key);
- if key == "--" {
+ // PHP compares the key as a string even when it is an int.
+ let key_string = key.to_string();
+ if key_string == "--" {
return Ok(());
}
- if key.starts_with("--") {
- self.add_long_option(&shirabe_php_shim::substr(&key, 2, None), value)?;
- } else if key.starts_with("-") {
- self.add_short_option(&shirabe_php_shim::substr(&key, 1, None), value)?;
+ if key_string.starts_with("--") {
+ self.add_long_option(&shirabe_php_shim::substr(&key_string, 2, None), value)?;
+ } else if key_string.starts_with("-") {
+ self.add_short_option(&shirabe_php_shim::substr(&key_string, 1, None), value)?;
} else {
- self.add_argument(&PhpMixed::String(key), value)?;
+ self.add_argument(&key.to_argument_name(), value)?;
}
}
@@ -153,7 +150,7 @@ impl ArrayInput {
}
/// Adds a short option value.
- fn add_short_option(&mut self, shortcut: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn add_short_option(&mut self, shortcut: &str, value: InputValue) -> anyhow::Result<()> {
if !self.inner.definition.has_shortcut(shortcut) {
return Err(InvalidOptionException::new(format!(
"The \"-{}\" option does not exist.",
@@ -172,7 +169,7 @@ impl ArrayInput {
}
/// Adds a long option value.
- fn add_long_option(&mut self, name: &str, mut value: PhpMixed) -> anyhow::Result<()> {
+ fn add_long_option(&mut self, name: &str, mut value: InputValue) -> anyhow::Result<()> {
if !self.inner.definition.has_option(name) {
if !self.inner.definition.has_negation(name) {
return Err(InvalidOptionException::new(format!(
@@ -185,14 +182,14 @@ impl ArrayInput {
let option_name = self.inner.definition.negation_to_name(name)?;
self.inner
.options
- .insert(option_name, PhpMixed::Bool(false));
+ .insert(option_name, InputValue::Bool(false));
return Ok(());
}
let option = self.inner.definition.get_option(name)?;
- if matches!(value, PhpMixed::Null) {
+ if value.is_null() {
if option.is_value_required() {
return Err(InvalidOptionException::new(format!(
"The \"--{}\" option requires a value.",
@@ -202,7 +199,7 @@ impl ArrayInput {
}
if !option.is_value_optional() {
- value = PhpMixed::Bool(true);
+ value = InputValue::Bool(true);
}
}
@@ -212,18 +209,16 @@ impl ArrayInput {
}
/// Adds an argument value.
- fn add_argument(&mut self, name: &PhpMixed, value: PhpMixed) -> anyhow::Result<()> {
+ fn add_argument(&mut self, name: &ArgumentName, value: InputValue) -> anyhow::Result<()> {
if !self.inner.definition.has_argument(name) {
return Err(InvalidArgumentException::new(format!(
"The \"{}\" argument does not exist.",
- name.clone()
+ name
))
.into());
}
- self.inner
- .arguments
- .insert(shirabe_php_shim::php_to_string(name), value);
+ self.inner.arguments.insert(name.to_string(), value);
Ok(())
}
@@ -235,30 +230,29 @@ impl std::fmt::Display for ArrayInput {
let mut params: Vec<String> = vec![];
for (param, val) in &self.parameters {
// $param && \is_string($param) && '-' === $param[0]
- let is_option_key =
- matches!(param, PhpMixed::String(s) if !s.is_empty() && s.as_bytes()[0] == b'-');
- if is_option_key {
- let param = param.as_string().unwrap();
+ if let ParameterName::Name(param) = param
+ && !param.is_empty()
+ && param.as_bytes()[0] == b'-'
+ {
let glue = if param.as_bytes().get(1) == Some(&b'-') {
"="
} else {
" "
};
- if let PhpMixed::List(list) = val {
+ if let InputValue::Array(list) = val {
for v in list {
- let v = shirabe_php_shim::php_to_string(v);
params.push(format!(
"{}{}",
param,
if !v.is_empty() {
- format!("{}{}", glue, self.inner.escape_token(&v))
+ format!("{}{}", glue, self.inner.escape_token(v))
} else {
String::new()
}
));
}
} else {
- let val = shirabe_php_shim::php_to_string(val);
+ let val = val.to_php_string();
params.push(format!(
"{}{}",
param,
@@ -269,17 +263,12 @@ impl std::fmt::Display for ArrayInput {
}
));
}
- } else if let PhpMixed::List(list) = val {
- let escaped: Vec<String> = list
- .iter()
- .map(|v| self.inner.escape_token(&shirabe_php_shim::php_to_string(v)))
- .collect();
+ } else if let InputValue::Array(list) = val {
+ let escaped: Vec<String> =
+ list.iter().map(|v| self.inner.escape_token(v)).collect();
params.push(shirabe_php_shim::implode(" ", &escaped));
} else {
- params.push(
- self.inner
- .escape_token(&shirabe_php_shim::php_to_string(val)),
- );
+ params.push(self.inner.escape_token(&val.to_php_string()));
}
}
@@ -293,19 +282,19 @@ impl InputInterface for ArrayInput {
}
fn get_first_argument(&self) -> Option<String> {
- ArrayInput::get_first_argument(self).map(|v| shirabe_php_shim::php_to_string(&v))
+ ArrayInput::get_first_argument(self).map(|v| v.to_php_string())
}
- fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool {
+ fn has_parameter_option(&self, values: &[&str], only_params: bool) -> bool {
ArrayInput::has_parameter_option(self, values, only_params)
}
fn get_parameter_option(
&self,
- values: PhpMixed,
- default: PhpMixed,
+ values: &[&str],
+ default: InputValue,
only_params: bool,
- ) -> PhpMixed {
+ ) -> InputValue {
ArrayInput::get_parameter_option(self, values, default, only_params)
}
@@ -317,15 +306,15 @@ impl InputInterface for ArrayInput {
self.inner.validate()
}
- fn get_arguments(&self) -> IndexMap<String, PhpMixed> {
+ fn get_arguments(&self) -> IndexMap<String, InputValue> {
self.inner.get_arguments()
}
- fn get_argument(&self, name: &str) -> anyhow::Result<PhpMixed> {
+ fn get_argument(&self, name: &str) -> anyhow::Result<InputValue> {
self.inner.get_argument(name)
}
- fn set_argument(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn set_argument(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
self.inner.set_argument(name, value)
}
@@ -333,15 +322,15 @@ impl InputInterface for ArrayInput {
self.inner.has_argument(name)
}
- fn get_options(&self) -> IndexMap<String, PhpMixed> {
+ fn get_options(&self) -> IndexMap<String, InputValue> {
self.inner.get_options()
}
- fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue> {
+ fn get_option(&self, name: &str) -> anyhow::Result<InputValue> {
self.inner.get_option(name)
}
- fn set_option(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn set_option(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
self.inner.set_option(name, value)
}
@@ -376,12 +365,32 @@ impl StreamableInputInterface for ArrayInput {
}
}
-/// PHP `(array) $values` cast: a string becomes a single-element array.
-fn to_array(values: PhpMixed) -> Vec<PhpMixed> {
- match values {
- PhpMixed::List(list) => list.into_iter().collect(),
- PhpMixed::Array(array) => array.into_iter().map(|(_, v)| v).collect(),
- PhpMixed::Null => vec![],
- other => vec![other],
+/// The `string|int` key of an [`ArrayInput`] parameter: a named argument, a named option
+/// (`--foo` / `-f`), or the position of a bare token.
+#[derive(Debug, Clone, PartialEq)]
+pub enum ParameterName {
+ Name(String),
+ Index(i64),
+}
+
+impl ParameterName {
+ pub fn of(name: &str) -> Self {
+ Self::Name(name.to_string())
+ }
+
+ fn to_argument_name(&self) -> ArgumentName {
+ match self {
+ Self::Name(name) => ArgumentName::Name(name.clone()),
+ Self::Index(index) => ArgumentName::Position(*index),
+ }
+ }
+}
+
+impl std::fmt::Display for ParameterName {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Name(name) => write!(f, "{}", name),
+ Self::Index(index) => write!(f, "{}", index),
+ }
}
}
diff --git a/crates/shirabe-symfony-console/src/input/input.rs b/crates/shirabe-symfony-console/src/input/input.rs
index 795e9c81..44519698 100644
--- a/crates/shirabe-symfony-console/src/input/input.rs
+++ b/crates/shirabe-symfony-console/src/input/input.rs
@@ -2,10 +2,11 @@
use crate::exception::InvalidArgumentException;
use crate::exception::RuntimeException;
+use crate::input::ArgumentName;
use crate::input::InputDefinition;
-use crate::input::InputOptionValue;
+use crate::input::InputValue;
use indexmap::IndexMap;
-use shirabe_php_shim::{PhpMixed, PhpResource, php_regex, preg_is_match};
+use shirabe_php_shim::{PhpResource, php_regex, preg_is_match};
/// Input is the base class for all concrete Input classes.
///
@@ -18,8 +19,8 @@ use shirabe_php_shim::{PhpMixed, PhpResource, php_regex, preg_is_match};
pub struct Input {
pub(crate) definition: InputDefinition,
stream: Option<PhpResource>,
- pub(crate) options: IndexMap<String, PhpMixed>,
- pub(crate) arguments: IndexMap<String, PhpMixed>,
+ pub(crate) options: IndexMap<String, InputValue>,
+ pub(crate) arguments: IndexMap<String, InputValue>,
interactive: bool,
}
@@ -74,7 +75,7 @@ impl Input {
|argument: &String| {
!given_arguments.contains_key(argument)
&& definition
- .get_argument(&PhpMixed::String(argument.clone()))
+ .get_argument(&ArgumentName::of(argument))
.map(|a| a.is_required())
.unwrap_or(false)
},
@@ -99,18 +100,15 @@ impl Input {
self.interactive = interactive;
}
- pub fn get_arguments(&self) -> IndexMap<String, PhpMixed> {
+ pub fn get_arguments(&self) -> IndexMap<String, InputValue> {
shirabe_php_shim::array_merge_map(
self.definition.get_argument_defaults(),
self.arguments.clone(),
)
}
- pub fn get_argument(&self, name: &str) -> anyhow::Result<PhpMixed> {
- if !self
- .definition
- .has_argument(&PhpMixed::String(name.to_string()))
- {
+ pub fn get_argument(&self, name: &str) -> anyhow::Result<InputValue> {
+ if !self.definition.has_argument(&ArgumentName::of(name)) {
return Err(InvalidArgumentException::new(format!(
"The \"{}\" argument does not exist.",
name
@@ -122,17 +120,14 @@ impl Input {
Some(value) => value.clone(),
None => self
.definition
- .get_argument(&PhpMixed::String(name.to_string()))?
+ .get_argument(&ArgumentName::of(name))?
.get_default()
.clone(),
})
}
- pub fn set_argument(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
- if !self
- .definition
- .has_argument(&PhpMixed::String(name.to_string()))
- {
+ pub fn set_argument(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
+ if !self.definition.has_argument(&ArgumentName::of(name)) {
return Err(InvalidArgumentException::new(format!(
"The \"{}\" argument does not exist.",
name
@@ -146,25 +141,24 @@ impl Input {
}
pub fn has_argument(&self, name: &str) -> bool {
- self.definition
- .has_argument(&PhpMixed::String(name.to_string()))
+ self.definition.has_argument(&ArgumentName::of(name))
}
- pub fn get_options(&self) -> IndexMap<String, PhpMixed> {
+ pub fn get_options(&self) -> IndexMap<String, InputValue> {
shirabe_php_shim::array_merge_map(
self.definition.get_option_defaults(),
self.options.clone(),
)
}
- pub fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue> {
+ pub fn get_option(&self, name: &str) -> anyhow::Result<InputValue> {
if self.definition.has_negation(name) {
let value = self.get_option(&self.definition.negation_to_name(name)?)?;
if value.is_null() {
return Ok(value);
}
- return Ok(InputOptionValue::Bool(!value.to_bool()));
+ return Ok(InputValue::Bool(!value.to_bool()));
}
if !self.definition.has_option(name) {
@@ -176,18 +170,17 @@ impl Input {
}
Ok(if let Some(value) = self.options.get(name) {
- InputOptionValue::from_php_mixed(value)
+ value.clone()
} else {
- let option = self.definition.get_option(name)?;
- InputOptionValue::from_php_mixed(option.get_default())
+ self.definition.get_option(name)?.get_default().clone()
})
}
- pub fn set_option(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ pub fn set_option(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
if self.definition.has_negation(name) {
let negated = self.definition.negation_to_name(name)?;
self.options
- .insert(negated, PhpMixed::Bool(!value.as_bool().unwrap_or(false)));
+ .insert(negated, InputValue::Bool(!value.to_bool()));
return Ok(());
} else if !self.definition.has_option(name) {
diff --git a/crates/shirabe-symfony-console/src/input/input_argument.rs b/crates/shirabe-symfony-console/src/input/input_argument.rs
index 5ca91a6b..ef07af0e 100644
--- a/crates/shirabe-symfony-console/src/input/input_argument.rs
+++ b/crates/shirabe-symfony-console/src/input/input_argument.rs
@@ -2,13 +2,13 @@
use crate::exception::InvalidArgumentException;
use crate::exception::LogicException;
-use shirabe_php_shim::PhpMixed;
+use crate::input::InputValue;
#[derive(Debug, Clone)]
pub struct InputArgument {
name: String,
mode: i64,
- default: PhpMixed,
+ default: InputValue,
description: String,
}
@@ -21,7 +21,7 @@ impl InputArgument {
name: String,
mode: Option<i64>,
description: String,
- default: PhpMixed,
+ default: InputValue,
) -> anyhow::Result<Self> {
let mode = match mode {
None => Self::OPTIONAL,
@@ -39,7 +39,7 @@ impl InputArgument {
name,
mode,
description,
- default: PhpMixed::Null,
+ default: InputValue::Null,
};
argument.set_default(default)?;
@@ -59,8 +59,8 @@ impl InputArgument {
Self::IS_ARRAY == (Self::IS_ARRAY & self.mode)
}
- pub fn set_default(&mut self, default: PhpMixed) -> anyhow::Result<()> {
- if self.is_required() && !matches!(default, PhpMixed::Null) {
+ pub fn set_default(&mut self, default: InputValue) -> anyhow::Result<()> {
+ if self.is_required() && !default.is_null() {
return Err(LogicException::new(
"Cannot set a default value except for InputArgument::OPTIONAL mode.".to_string(),
)
@@ -69,8 +69,8 @@ impl InputArgument {
let default = if self.is_array() {
match default {
- PhpMixed::Null => PhpMixed::List(vec![]),
- PhpMixed::List(_) => default,
+ InputValue::Null => InputValue::Array(vec![]),
+ InputValue::Array(_) => default,
_ => {
return Err(LogicException::new(
"A default value for an array argument must be an array.".to_string(),
@@ -86,7 +86,7 @@ impl InputArgument {
Ok(())
}
- pub fn get_default(&self) -> &PhpMixed {
+ pub fn get_default(&self) -> &InputValue {
&self.default
}
diff --git a/crates/shirabe-symfony-console/src/input/input_definition.rs b/crates/shirabe-symfony-console/src/input/input_definition.rs
index 8d116bc1..35fa4e52 100644
--- a/crates/shirabe-symfony-console/src/input/input_definition.rs
+++ b/crates/shirabe-symfony-console/src/input/input_definition.rs
@@ -4,8 +4,8 @@ use crate::exception::InvalidArgumentException;
use crate::exception::LogicException;
use crate::input::InputArgument;
use crate::input::InputOption;
+use crate::input::InputValue;
use indexmap::IndexMap;
-use shirabe_php_shim::PhpMixed;
/// A InputDefinition represents a set of valid command line arguments and options.
///
@@ -154,40 +154,32 @@ impl InputDefinition {
}
/// Returns an InputArgument by name or by position.
- pub fn get_argument(&self, name: &PhpMixed) -> anyhow::Result<std::rc::Rc<InputArgument>> {
+ pub fn get_argument(&self, name: &ArgumentName) -> anyhow::Result<std::rc::Rc<InputArgument>> {
if !self.has_argument(name) {
return Err(InvalidArgumentException::new(format!(
"The \"{}\" argument does not exist.",
- name.clone()
+ name
))
.into());
}
match name {
- PhpMixed::Int(index) => {
+ ArgumentName::Position(index) => {
let arguments: Vec<std::rc::Rc<InputArgument>> =
self.arguments.values().cloned().collect();
Ok(std::rc::Rc::clone(&arguments[*index as usize]))
}
- _ => {
- let key = shirabe_php_shim::php_to_string(name);
- Ok(std::rc::Rc::clone(&self.arguments[&key]))
- }
+ ArgumentName::Name(name) => Ok(std::rc::Rc::clone(&self.arguments[name])),
}
}
/// Returns true if an InputArgument object exists by name or position.
- pub fn has_argument(&self, name: &PhpMixed) -> bool {
+ pub fn has_argument(&self, name: &ArgumentName) -> bool {
match name {
- PhpMixed::Int(index) => {
- let arguments: Vec<std::rc::Rc<InputArgument>> =
- self.arguments.values().cloned().collect();
- *index >= 0 && (*index as usize) < arguments.len()
- }
- _ => {
- let key = shirabe_php_shim::php_to_string(name);
- self.arguments.contains_key(&key)
+ ArgumentName::Position(index) => {
+ *index >= 0 && (*index as usize) < self.arguments.len()
}
+ ArgumentName::Name(name) => self.arguments.contains_key(name),
}
}
@@ -210,7 +202,7 @@ impl InputDefinition {
self.required_count
}
- pub fn get_argument_defaults(&self) -> IndexMap<String, PhpMixed> {
+ pub fn get_argument_defaults(&self) -> IndexMap<String, InputValue> {
let mut values = IndexMap::new();
for argument in self.arguments.values() {
values.insert(
@@ -346,7 +338,7 @@ impl InputDefinition {
self.get_option(&self.shortcut_to_name(shortcut)?)
}
- pub fn get_option_defaults(&self) -> IndexMap<String, PhpMixed> {
+ pub fn get_option_defaults(&self) -> IndexMap<String, InputValue> {
let mut values = IndexMap::new();
for option in self.options.values() {
values.insert(option.get_name().to_string(), option.get_default().clone());
@@ -448,3 +440,26 @@ impl InputDefinition {
format!("{}{}", shirabe_php_shim::implode(" ", &elements), tail)
}
}
+
+/// The `string|int` selector [`InputDefinition::get_argument`] and
+/// [`InputDefinition::has_argument`] accept.
+#[derive(Debug, Clone)]
+pub enum ArgumentName {
+ Name(String),
+ Position(i64),
+}
+
+impl ArgumentName {
+ pub fn of(name: &str) -> Self {
+ Self::Name(name.to_string())
+ }
+}
+
+impl std::fmt::Display for ArgumentName {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Name(name) => write!(f, "{}", name),
+ Self::Position(index) => write!(f, "{}", index),
+ }
+ }
+}
diff --git a/crates/shirabe-symfony-console/src/input/input_interface.rs b/crates/shirabe-symfony-console/src/input/input_interface.rs
index 3c3ec2d5..85cd5e7f 100644
--- a/crates/shirabe-symfony-console/src/input/input_interface.rs
+++ b/crates/shirabe-symfony-console/src/input/input_interface.rs
@@ -1,9 +1,8 @@
//! ref: composer/vendor/symfony/console/Input/InputInterface.php
use crate::input::InputDefinition;
-use crate::input::InputOptionValue;
+use crate::input::InputValue;
use crate::input::StreamableInputInterface;
-use shirabe_php_shim::PhpMixed;
pub trait InputInterface: std::fmt::Debug + shirabe_php_shim::AsAny {
/// Models PHP's `clone` operatior.
@@ -11,32 +10,32 @@ pub trait InputInterface: std::fmt::Debug + shirabe_php_shim::AsAny {
fn get_first_argument(&self) -> Option<String>;
- fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool;
+ fn has_parameter_option(&self, values: &[&str], only_params: bool) -> bool;
fn get_parameter_option(
&self,
- values: PhpMixed,
- default: PhpMixed,
+ values: &[&str],
+ default: InputValue,
only_params: bool,
- ) -> PhpMixed;
+ ) -> InputValue;
fn bind(&mut self, definition: &InputDefinition) -> anyhow::Result<()>;
fn validate(&mut self) -> anyhow::Result<()>;
- fn get_arguments(&self) -> indexmap::IndexMap<String, PhpMixed>;
+ fn get_arguments(&self) -> indexmap::IndexMap<String, InputValue>;
- fn get_argument(&self, name: &str) -> anyhow::Result<PhpMixed>;
+ fn get_argument(&self, name: &str) -> anyhow::Result<InputValue>;
- fn set_argument(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()>;
+ fn set_argument(&mut self, name: &str, value: InputValue) -> anyhow::Result<()>;
fn has_argument(&self, name: &str) -> bool;
- fn get_options(&self) -> indexmap::IndexMap<String, PhpMixed>;
+ fn get_options(&self) -> indexmap::IndexMap<String, InputValue>;
- fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue>;
+ fn get_option(&self, name: &str) -> anyhow::Result<InputValue>;
- fn set_option(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()>;
+ fn set_option(&mut self, name: &str, value: InputValue) -> anyhow::Result<()>;
fn has_option(&self, name: &str) -> bool;
diff --git a/crates/shirabe-symfony-console/src/input/input_option.rs b/crates/shirabe-symfony-console/src/input/input_option.rs
index d37e18ae..6484d832 100644
--- a/crates/shirabe-symfony-console/src/input/input_option.rs
+++ b/crates/shirabe-symfony-console/src/input/input_option.rs
@@ -2,14 +2,15 @@
use crate::exception::InvalidArgumentException;
use crate::exception::LogicException;
-use shirabe_php_shim::{PhpMixed, php_regex, preg_split};
+use crate::input::InputValue;
+use shirabe_php_shim::{php_regex, preg_split};
#[derive(Debug, Clone)]
pub struct InputOption {
name: String,
shortcut: Option<String>,
mode: i64,
- default: PhpMixed,
+ default: InputValue,
description: String,
}
@@ -22,10 +23,10 @@ impl InputOption {
pub fn new(
name: &str,
- shortcut: PhpMixed,
+ shortcut: Option<&str>,
mode: Option<i64>,
description: String,
- default: PhpMixed,
+ default: InputValue,
) -> anyhow::Result<Self> {
let name = if let Some(stripped) = name.strip_prefix("--") {
stripped.to_string()
@@ -41,26 +42,8 @@ impl InputOption {
}
let shortcut = match shortcut {
- PhpMixed::String(ref s) if s.is_empty() => None,
- PhpMixed::List(ref v) if v.is_empty() => None,
- PhpMixed::Bool(false) => None,
- PhpMixed::Null => None,
- PhpMixed::List(ref arr) => {
- let parts: Vec<String> = arr
- .iter()
- .filter_map(|v| {
- if let PhpMixed::String(s) = v {
- Some(s.clone())
- } else {
- None
- }
- })
- .collect();
- let joined = shirabe_php_shim::implode("|", &parts);
- Self::normalize_shortcut(joined)?
- }
- PhpMixed::String(s) => Self::normalize_shortcut(s)?,
- _ => None,
+ None | Some("") => None,
+ Some(shortcut) => Self::normalize_shortcut(shortcut)?,
};
let mode = match mode {
@@ -80,7 +63,7 @@ impl InputOption {
shortcut,
mode,
description,
- default: PhpMixed::Null,
+ default: InputValue::Null,
};
if option.is_array() && !option.accept_value() {
@@ -97,8 +80,8 @@ impl InputOption {
Ok(option)
}
- fn normalize_shortcut(s: String) -> anyhow::Result<Option<String>> {
- let stripped = shirabe_php_shim::ltrim(&s, Some("-"));
+ fn normalize_shortcut(s: &str) -> anyhow::Result<Option<String>> {
+ let stripped = shirabe_php_shim::ltrim(s, Some("-"));
let parts = preg_split(php_regex!(r"{(\|)-?}"), &stripped);
let filtered: Vec<String> =
shirabe_php_shim::array_filter(&parts, |s: &String| !s.is_empty());
@@ -140,9 +123,8 @@ impl InputOption {
Self::VALUE_NEGATABLE == (Self::VALUE_NEGATABLE & self.mode)
}
- pub fn set_default(&mut self, default: PhpMixed) -> anyhow::Result<()> {
- if Self::VALUE_NONE == (Self::VALUE_NONE & self.mode) && !matches!(default, PhpMixed::Null)
- {
+ pub fn set_default(&mut self, default: InputValue) -> anyhow::Result<()> {
+ if Self::VALUE_NONE == (Self::VALUE_NONE & self.mode) && !default.is_null() {
return Err(LogicException::new(
"Cannot set a default value when using InputOption::VALUE_NONE mode.".to_string(),
)
@@ -151,9 +133,8 @@ impl InputOption {
let default = if self.is_array() {
match default {
- PhpMixed::Null => PhpMixed::List(vec![]),
- // PHP `is_array()` accepts both list-style and associative arrays.
- PhpMixed::List(_) | PhpMixed::Array(_) => default,
+ InputValue::Null => InputValue::Array(vec![]),
+ InputValue::Array(_) => default,
_ => {
return Err(LogicException::new(
"A default value for an array option must be an array.".to_string(),
@@ -168,12 +149,12 @@ impl InputOption {
self.default = if self.accept_value() || self.is_negatable() {
default
} else {
- PhpMixed::Bool(false)
+ InputValue::Bool(false)
};
Ok(())
}
- pub fn get_default(&self) -> &PhpMixed {
+ pub fn get_default(&self) -> &InputValue {
&self.default
}
@@ -191,90 +172,3 @@ impl InputOption {
&& option.is_value_optional() == self.is_value_optional()
}
}
-
-/// The `bool|string|string[]|null` domain of a parsed option value, as returned by
-/// [`InputInterface::get_option`](crate::input::InputInterface::get_option).
-#[derive(Debug, Clone, PartialEq)]
-pub enum InputOptionValue {
- Null,
- Bool(bool),
- String(String),
- Array(Vec<String>),
-}
-
-impl InputOptionValue {
- /// Narrows a raw option value to this domain.
- ///
- /// TODO(type-model): `Input` keeps parsed options and `InputOption` defaults as `PhpMixed`, so
- /// a value outside this domain — an int, a float, or an array holding one — can only be
- /// rejected here.
- pub(crate) fn from_php_mixed(value: &PhpMixed) -> Self {
- match value {
- PhpMixed::Null => Self::Null,
- PhpMixed::Bool(b) => Self::Bool(*b),
- PhpMixed::String(s) => Self::String(s.clone()),
- PhpMixed::List(_) | PhpMixed::Array(_) => Self::Array(
- value
- .values()
- .into_iter()
- .map(|item| match item {
- PhpMixed::String(s) => s.clone(),
- other => panic!("an option array holds {:?}, not a string", other),
- })
- .collect(),
- ),
- other => panic!(
- "an option holds {:?}, not a bool, string, array or null",
- other
- ),
- }
- }
-
- pub fn is_null(&self) -> bool {
- matches!(self, Self::Null)
- }
-
- pub fn as_bool(&self) -> Option<bool> {
- match self {
- Self::Bool(b) => Some(*b),
- _ => None,
- }
- }
-
- pub fn as_string(&self) -> Option<&str> {
- match self {
- Self::String(s) => Some(s.as_str()),
- _ => None,
- }
- }
-
- pub fn as_array(&self) -> Option<&[String]> {
- match self {
- Self::Array(items) => Some(items),
- _ => None,
- }
- }
-
- /// PHP loose boolean cast `(bool) $value`.
- pub fn to_bool(&self) -> bool {
- match self {
- Self::Null => false,
- Self::Bool(b) => *b,
- Self::String(s) => !s.is_empty() && s != "0",
- Self::Array(items) => !items.is_empty(),
- }
- }
-}
-
-impl From<InputOptionValue> for PhpMixed {
- fn from(value: InputOptionValue) -> Self {
- match value {
- InputOptionValue::Null => PhpMixed::Null,
- InputOptionValue::Bool(b) => PhpMixed::Bool(b),
- InputOptionValue::String(s) => PhpMixed::String(s),
- InputOptionValue::Array(items) => {
- PhpMixed::List(items.into_iter().map(PhpMixed::String).collect())
- }
- }
- }
-}
diff --git a/crates/shirabe-symfony-console/src/input/input_value.rs b/crates/shirabe-symfony-console/src/input/input_value.rs
new file mode 100644
index 00000000..288c55d6
--- /dev/null
+++ b/crates/shirabe-symfony-console/src/input/input_value.rs
@@ -0,0 +1,146 @@
+//! ref: composer/vendor/symfony/console/Input/InputInterface.php
+
+/// The value an option or an argument can hold.
+///
+/// Symfony declares the domain as `string|bool|int|float|array|null` and only ever narrows it in
+/// PHPDoc; the arrays it stores are lists of strings.
+#[derive(Debug, Clone, PartialEq)]
+pub enum InputValue {
+ Null,
+ Bool(bool),
+ String(String),
+ Array(Vec<String>),
+}
+
+impl InputValue {
+ /// Narrows a PHP value to this domain.
+ ///
+ /// TODO(type-model): the question helpers and the plugin bridge still hand back a
+ /// `PhpMixed`, so a value outside this domain can only be rejected here.
+ pub fn from_php_mixed(value: &shirabe_php_shim::PhpMixed) -> Self {
+ use shirabe_php_shim::PhpMixed;
+ match value {
+ PhpMixed::Null => Self::Null,
+ PhpMixed::Bool(b) => Self::Bool(*b),
+ PhpMixed::String(s) => Self::String(s.clone()),
+ PhpMixed::List(_) | PhpMixed::Array(_) => Self::Array(
+ value
+ .values()
+ .into_iter()
+ .map(|item| match item {
+ PhpMixed::String(s) => s.clone(),
+ other => panic!("an input array holds {:?}, not a string", other),
+ })
+ .collect(),
+ ),
+ other => panic!(
+ "an input value holds {:?}, not a bool, string, array or null",
+ other
+ ),
+ }
+ }
+
+ pub fn is_null(&self) -> bool {
+ matches!(self, Self::Null)
+ }
+
+ pub fn is_array(&self) -> bool {
+ matches!(self, Self::Array(_))
+ }
+
+ pub fn as_bool(&self) -> Option<bool> {
+ match self {
+ Self::Bool(b) => Some(*b),
+ _ => None,
+ }
+ }
+
+ pub fn as_string(&self) -> Option<&str> {
+ match self {
+ Self::String(s) => Some(s.as_str()),
+ _ => None,
+ }
+ }
+
+ pub fn as_array(&self) -> Option<&[String]> {
+ match self {
+ Self::Array(items) => Some(items),
+ _ => None,
+ }
+ }
+
+ /// PHP's `(bool) $value`.
+ pub fn to_bool(&self) -> bool {
+ match self {
+ Self::Null => false,
+ Self::Bool(b) => *b,
+ Self::String(s) => !s.is_empty() && s != "0",
+ Self::Array(items) => !items.is_empty(),
+ }
+ }
+
+ /// The value as a PHP `mixed`, for the shim functions that take one.
+ pub fn to_php_mixed(&self) -> shirabe_php_shim::PhpMixed {
+ self.clone().into()
+ }
+
+ /// PHP's `(string) $value`, which is a fatal error for an array.
+ pub fn to_php_string(&self) -> String {
+ match self {
+ Self::Null => String::new(),
+ Self::Bool(b) => {
+ if *b {
+ "1".to_string()
+ } else {
+ String::new()
+ }
+ }
+ Self::String(s) => s.clone(),
+ Self::Array(_) => panic!("array to string conversion"),
+ }
+ }
+}
+
+impl From<InputValue> for shirabe_php_shim::PhpMixed {
+ fn from(value: InputValue) -> Self {
+ match value {
+ InputValue::Null => Self::Null,
+ InputValue::Bool(b) => Self::Bool(b),
+ InputValue::String(s) => Self::String(s),
+ InputValue::Array(items) => Self::List(items.into_iter().map(Self::String).collect()),
+ }
+ }
+}
+
+impl From<&str> for InputValue {
+ fn from(value: &str) -> Self {
+ Self::String(value.to_string())
+ }
+}
+
+impl From<String> for InputValue {
+ fn from(value: String) -> Self {
+ Self::String(value)
+ }
+}
+
+impl From<bool> for InputValue {
+ fn from(value: bool) -> Self {
+ Self::Bool(value)
+ }
+}
+
+impl From<Option<String>> for InputValue {
+ fn from(value: Option<String>) -> Self {
+ match value {
+ Some(value) => Self::String(value),
+ None => Self::Null,
+ }
+ }
+}
+
+impl From<Vec<String>> for InputValue {
+ fn from(value: Vec<String>) -> Self {
+ Self::Array(value)
+ }
+}
diff --git a/crates/shirabe-symfony-console/src/input/string_input.rs b/crates/shirabe-symfony-console/src/input/string_input.rs
index 9fcb3fc8..09cee120 100644
--- a/crates/shirabe-symfony-console/src/input/string_input.rs
+++ b/crates/shirabe-symfony-console/src/input/string_input.rs
@@ -4,10 +4,10 @@ use crate::exception::InvalidArgumentException;
use crate::input::ArgvInput;
use crate::input::InputDefinition;
use crate::input::InputInterface;
-use crate::input::InputOptionValue;
+use crate::input::InputValue;
use crate::input::StreamableInputInterface;
use indexmap::IndexMap;
-use shirabe_php_shim::{PhpMixed, php_regex, preg_match};
+use shirabe_php_shim::{php_regex, preg_match};
/// StringInput represents an input provided as a string.
///
@@ -137,16 +137,16 @@ impl InputInterface for StringInput {
self.inner.get_first_argument()
}
- fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool {
+ fn has_parameter_option(&self, values: &[&str], only_params: bool) -> bool {
InputInterface::has_parameter_option(&self.inner, values, only_params)
}
fn get_parameter_option(
&self,
- values: PhpMixed,
- default: PhpMixed,
+ values: &[&str],
+ default: InputValue,
only_params: bool,
- ) -> PhpMixed {
+ ) -> InputValue {
InputInterface::get_parameter_option(&self.inner, values, default, only_params)
}
@@ -158,15 +158,15 @@ impl InputInterface for StringInput {
self.inner.validate()
}
- fn get_arguments(&self) -> IndexMap<String, PhpMixed> {
+ fn get_arguments(&self) -> IndexMap<String, InputValue> {
InputInterface::get_arguments(&self.inner)
}
- fn get_argument(&self, name: &str) -> anyhow::Result<PhpMixed> {
+ fn get_argument(&self, name: &str) -> anyhow::Result<InputValue> {
self.inner.get_argument(name)
}
- fn set_argument(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn set_argument(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
self.inner.set_argument(name, value)
}
@@ -174,15 +174,15 @@ impl InputInterface for StringInput {
self.inner.has_argument(name)
}
- fn get_options(&self) -> IndexMap<String, PhpMixed> {
+ fn get_options(&self) -> IndexMap<String, InputValue> {
InputInterface::get_options(&self.inner)
}
- fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue> {
+ fn get_option(&self, name: &str) -> anyhow::Result<InputValue> {
self.inner.get_option(name)
}
- fn set_option(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> {
+ fn set_option(&mut self, name: &str, value: InputValue) -> anyhow::Result<()> {
self.inner.set_option(name, value)
}