From 6051927c8fa32cfffa102d2a170c5a6cf747a1b9 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 9 Aug 2026 11:19:03 +0900 Subject: refactor(symfony-console): extract symfony/console into the shirabe-symfony-console crate Move `Symfony\Component\Console` out of shirabe-external-packages and into its own crate, so the path is `shirabe_symfony_console::application::Application` instead of `shirabe_external_packages::symfony::console::application::Application`. The `delegate_to_inner!` and `delegate_command_trait_impls_to_inner!` macros move with it. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/symfony/console/input/array_input.rs | 386 --------------------- 1 file changed, 386 deletions(-) delete mode 100644 crates/shirabe-external-packages/src/symfony/console/input/array_input.rs (limited to 'crates/shirabe-external-packages/src/symfony/console/input/array_input.rs') diff --git a/crates/shirabe-external-packages/src/symfony/console/input/array_input.rs b/crates/shirabe-external-packages/src/symfony/console/input/array_input.rs deleted file mode 100644 index de89a340..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/input/array_input.rs +++ /dev/null @@ -1,386 +0,0 @@ -//! ref: composer/vendor/symfony/console/Input/ArrayInput.php - -use crate::symfony::console::exception::invalid_argument_exception::InvalidArgumentException; -use crate::symfony::console::exception::invalid_option_exception::InvalidOptionException; -use crate::symfony::console::input::input::Input; -use crate::symfony::console::input::input_definition::InputDefinition; -use crate::symfony::console::input::input_interface::InputInterface; -use crate::symfony::console::input::streamable_input_interface::StreamableInputInterface; -use indexmap::IndexMap; -use shirabe_php_shim::PhpMixed; - -/// ArrayInput represents an input provided as an array. -/// -/// Usage: -/// -/// ```php -/// $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']); -/// ``` -/// -/// PHP arrays can mix integer and string keys; `parameters` preserves both the -/// key type (`PhpMixed::Int` / `PhpMixed::String`) and the insertion order. -#[derive(Debug, Clone)] -pub struct ArrayInput { - pub(crate) inner: Input, - parameters: Vec<(PhpMixed, PhpMixed)>, -} - -impl ArrayInput { - pub fn new( - parameters: Vec<(PhpMixed, PhpMixed)>, - definition: Option, - ) -> anyhow::Result { - let mut array_input = ArrayInput { - inner: Input::new(None)?, - parameters, - }; - - // parent::__construct($definition) - match definition { - None => {} - Some(definition) => { - array_input.bind(&definition)?; - array_input.inner.validate()?; - } - } - - Ok(array_input) - } - - pub fn bind(&mut self, definition: &InputDefinition) -> anyhow::Result<()> { - self.inner.arguments = IndexMap::new(); - self.inner.options = IndexMap::new(); - self.inner.definition = definition.clone(); - - self.parse()?; - - Ok(()) - } - - pub fn get_first_argument(&self) -> Option { - for (param, value) in &self.parameters { - // $param && \is_string($param) && '-' === $param[0] - if let PhpMixed::String(param) = param - && !param.is_empty() - && param.as_bytes()[0] == b'-' - { - continue; - } - - return Some(value.clone()); - } - - None - } - - pub fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool { - let values = to_array(values); - - for (k, v) in &self.parameters { - // if (!\is_int($k)) { $v = $k; } - let v: PhpMixed = match k { - PhpMixed::Int(_) => v.clone(), - _ => k.clone(), - }; - - if only_params && matches!(&v, PhpMixed::String(s) if s == "--") { - return false; - } - - if values.iter().any(|x| x == &v) { - return true; - } - } - - false - } - - pub fn get_parameter_option( - &self, - values: PhpMixed, - default: PhpMixed, - only_params: bool, - ) -> PhpMixed { - let values = to_array(values); - - 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 int_v_double_dash = - matches!(k, PhpMixed::Int(_)) && matches!(v, PhpMixed::String(s) if s == "--"); - 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); - } - } - _ => { - if values.iter().any(|x| x == k) { - return v.clone(); - } - } - } - } - - default - } - - fn parse(&mut self) -> anyhow::Result<()> { - // 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 == "--" { - return Ok(()); - } - if shirabe_php_shim::str_starts_with(&key, "--") { - self.add_long_option(&shirabe_php_shim::substr(&key, 2, None), value)?; - } else if shirabe_php_shim::str_starts_with(&key, "-") { - self.add_short_option(&shirabe_php_shim::substr(&key, 1, None), value)?; - } else { - self.add_argument(&PhpMixed::String(key), value)?; - } - } - - Ok(()) - } - - /// Adds a short option value. - fn add_short_option(&mut self, shortcut: &str, value: PhpMixed) -> anyhow::Result<()> { - if !self.inner.definition.has_shortcut(shortcut) { - return Err(InvalidOptionException::new(format!( - "The \"-{}\" option does not exist.", - shortcut - )) - .into()); - } - - self.add_long_option( - self.inner - .definition - .get_option_for_shortcut(shortcut)? - .get_name(), - value, - ) - } - - /// Adds a long option value. - fn add_long_option(&mut self, name: &str, mut value: PhpMixed) -> anyhow::Result<()> { - if !self.inner.definition.has_option(name) { - if !self.inner.definition.has_negation(name) { - return Err(InvalidOptionException::new(format!( - "The \"--{}\" option does not exist.", - name - )) - .into()); - } - - let option_name = self.inner.definition.negation_to_name(name)?; - self.inner - .options - .insert(option_name, PhpMixed::Bool(false)); - - return Ok(()); - } - - let option = self.inner.definition.get_option(name)?; - - if matches!(value, PhpMixed::Null) { - if option.is_value_required() { - return Err(InvalidOptionException::new(format!( - "The \"--{}\" option requires a value.", - name - )) - .into()); - } - - if !option.is_value_optional() { - value = PhpMixed::Bool(true); - } - } - - self.inner.options.insert(name.to_string(), value); - - Ok(()) - } - - /// Adds an argument value. - fn add_argument(&mut self, name: &PhpMixed, value: PhpMixed) -> anyhow::Result<()> { - if !self.inner.definition.has_argument(name) { - return Err(InvalidArgumentException::new(format!( - "The \"{}\" argument does not exist.", - name.clone() - )) - .into()); - } - - self.inner - .arguments - .insert(shirabe_php_shim::php_to_string(name), value); - - Ok(()) - } -} - -/// Returns a stringified representation of the args passed to the command. -impl std::fmt::Display for ArrayInput { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut params: Vec = 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(); - let glue = if param.as_bytes().get(1) == Some(&b'-') { - "=" - } else { - " " - }; - if let PhpMixed::List(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)) - } else { - String::new() - } - )); - } - } else { - let val = shirabe_php_shim::php_to_string(val); - params.push(format!( - "{}{}", - param, - if !val.is_empty() { - format!("{}{}", glue, self.inner.escape_token(&val)) - } else { - String::new() - } - )); - } - } else if let PhpMixed::List(list) = val { - let escaped: Vec = list - .iter() - .map(|v| self.inner.escape_token(&shirabe_php_shim::php_to_string(v))) - .collect(); - params.push(shirabe_php_shim::implode(" ", &escaped)); - } else { - params.push( - self.inner - .escape_token(&shirabe_php_shim::php_to_string(val)), - ); - } - } - - write!(f, "{}", shirabe_php_shim::implode(" ", ¶ms)) - } -} - -impl InputInterface for ArrayInput { - fn dup(&self) -> std::rc::Rc> { - std::rc::Rc::new(std::cell::RefCell::new(self.clone())) - } - - fn get_first_argument(&self) -> Option { - ArrayInput::get_first_argument(self).map(|v| shirabe_php_shim::php_to_string(&v)) - } - - fn has_parameter_option(&self, values: PhpMixed, only_params: bool) -> bool { - ArrayInput::has_parameter_option(self, values, only_params) - } - - fn get_parameter_option( - &self, - values: PhpMixed, - default: PhpMixed, - only_params: bool, - ) -> PhpMixed { - ArrayInput::get_parameter_option(self, values, default, only_params) - } - - fn bind(&mut self, definition: &InputDefinition) -> anyhow::Result<()> { - ArrayInput::bind(self, definition) - } - - fn validate(&mut self) -> anyhow::Result<()> { - self.inner.validate() - } - - fn get_arguments(&self) -> IndexMap { - self.inner.get_arguments() - } - - fn get_argument(&self, name: &str) -> anyhow::Result { - self.inner.get_argument(name) - } - - fn set_argument(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> { - self.inner.set_argument(name, value) - } - - fn has_argument(&self, name: &str) -> bool { - self.inner.has_argument(name) - } - - fn get_options(&self) -> IndexMap { - self.inner.get_options() - } - - fn get_option(&self, name: &str) -> anyhow::Result { - self.inner.get_option(name) - } - - fn set_option(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()> { - self.inner.set_option(name, value) - } - - fn has_option(&self, name: &str) -> bool { - self.inner.has_option(name) - } - - fn is_interactive(&self) -> bool { - self.inner.is_interactive() - } - - fn set_interactive(&mut self, interactive: bool) { - self.inner.set_interactive(interactive) - } - - fn __to_string(&self) -> String { - self.to_string() - } - - fn as_streamable(&self) -> Option<&dyn StreamableInputInterface> { - Some(self) - } -} - -impl StreamableInputInterface for ArrayInput { - fn set_stream(&mut self, stream: shirabe_php_shim::PhpResource) { - self.inner.set_stream(stream) - } - - fn get_stream(&self) -> Option { - self.inner.get_stream() - } -} - -/// PHP `(array) $values` cast: a string becomes a single-element array. -fn to_array(values: PhpMixed) -> Vec { - 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], - } -} -- cgit v1.3.1-4-g156e