aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-external-packages/src/symfony/console/input/input_definition.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-09 11:19:03 +0900
committernsfisis <nsfisis@gmail.com>2026-08-09 11:19:03 +0900
commit6051927c8fa32cfffa102d2a170c5a6cf747a1b9 (patch)
tree3fe6769c90cb03ca8f1b9b825e38ad459182361e /crates/shirabe-external-packages/src/symfony/console/input/input_definition.rs
parente3e8806aec771e482899ed3470e920f7b291fa95 (diff)
downloadphp-shirabe-6051927c8fa32cfffa102d2a170c5a6cf747a1b9.tar.gz
php-shirabe-6051927c8fa32cfffa102d2a170c5a6cf747a1b9.tar.zst
php-shirabe-6051927c8fa32cfffa102d2a170c5a6cf747a1b9.zip
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) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-external-packages/src/symfony/console/input/input_definition.rs')
-rw-r--r--crates/shirabe-external-packages/src/symfony/console/input/input_definition.rs450
1 files changed, 0 insertions, 450 deletions
diff --git a/crates/shirabe-external-packages/src/symfony/console/input/input_definition.rs b/crates/shirabe-external-packages/src/symfony/console/input/input_definition.rs
deleted file mode 100644
index bd32a8f9..00000000
--- a/crates/shirabe-external-packages/src/symfony/console/input/input_definition.rs
+++ /dev/null
@@ -1,450 +0,0 @@
-//! ref: composer/vendor/symfony/console/Input/InputDefinition.php
-
-use crate::symfony::console::exception::invalid_argument_exception::InvalidArgumentException;
-use crate::symfony::console::exception::logic_exception::LogicException;
-use crate::symfony::console::input::input_argument::InputArgument;
-use crate::symfony::console::input::input_option::InputOption;
-use indexmap::IndexMap;
-use shirabe_php_shim::PhpMixed;
-
-/// A InputDefinition represents a set of valid command line arguments and options.
-///
-/// `InputArgument` and `InputOption` are stored behind `Rc` to model PHP's
-/// shared object references; this also lets the definition be cloned cheaply
-/// (PHP `bind` assigns the definition by reference).
-#[derive(Debug, Clone)]
-pub struct InputDefinition {
- arguments: IndexMap<String, std::rc::Rc<InputArgument>>,
- required_count: i64,
- last_array_argument: Option<std::rc::Rc<InputArgument>>,
- last_optional_argument: Option<std::rc::Rc<InputArgument>>,
- options: IndexMap<String, std::rc::Rc<InputOption>>,
- negations: IndexMap<String, String>,
- shortcuts: IndexMap<String, String>,
-}
-
-/// A definition entry is either an InputArgument or an InputOption.
-#[derive(Debug)]
-pub enum DefinitionItem {
- InputArgument(InputArgument),
- InputOption(InputOption),
-}
-
-impl InputDefinition {
- pub fn new(definition: Vec<DefinitionItem>) -> anyhow::Result<Self> {
- let mut input_definition = InputDefinition {
- arguments: IndexMap::new(),
- required_count: 0,
- last_array_argument: None,
- last_optional_argument: None,
- options: IndexMap::new(),
- negations: IndexMap::new(),
- shortcuts: IndexMap::new(),
- };
- input_definition.set_definition(definition)?;
- Ok(input_definition)
- }
-
- /// Builds an option-only definition that shares the given options by
- /// reference, mirroring `new InputDefinition($definition->getOptions())`.
- /// `InputOption` is not `Clone` and lives behind `Rc`, so the options are
- /// reused rather than reconstructed by value.
- pub fn from_options(options: Vec<std::rc::Rc<InputOption>>) -> anyhow::Result<Self> {
- let mut input_definition = InputDefinition {
- arguments: IndexMap::new(),
- required_count: 0,
- last_array_argument: None,
- last_optional_argument: None,
- options: IndexMap::new(),
- negations: IndexMap::new(),
- shortcuts: IndexMap::new(),
- };
- for option in options {
- input_definition.add_option_rc(option)?;
- }
- Ok(input_definition)
- }
-
- /// Sets the definition of the input.
- pub fn set_definition(&mut self, definition: Vec<DefinitionItem>) -> anyhow::Result<()> {
- let mut arguments = vec![];
- let mut options = vec![];
- for item in definition {
- match item {
- DefinitionItem::InputOption(option) => {
- options.push(option);
- }
- DefinitionItem::InputArgument(argument) => {
- arguments.push(argument);
- }
- }
- }
-
- self.set_arguments(arguments)?;
- self.set_options(options)?;
-
- Ok(())
- }
-
- /// Sets the InputArgument objects.
- pub fn set_arguments(&mut self, arguments: Vec<InputArgument>) -> anyhow::Result<()> {
- self.arguments = IndexMap::new();
- self.required_count = 0;
- self.last_optional_argument = None;
- self.last_array_argument = None;
- self.add_arguments(Some(arguments))?;
- Ok(())
- }
-
- /// Adds an array of InputArgument objects.
- pub fn add_arguments(&mut self, arguments: Option<Vec<InputArgument>>) -> anyhow::Result<()> {
- if let Some(arguments) = arguments {
- for argument in arguments {
- self.add_argument(argument)?;
- }
- }
- Ok(())
- }
-
- pub fn add_argument(&mut self, argument: InputArgument) -> anyhow::Result<()> {
- let argument = std::rc::Rc::new(argument);
-
- if self.arguments.contains_key(argument.get_name()) {
- return Err(LogicException::new(format!(
- "An argument with name \"{}\" already exists.",
- argument.get_name(),
- ))
- .into());
- }
-
- if let Some(last_array_argument) = &self.last_array_argument {
- return Err(LogicException::new(format!(
- "Cannot add a required argument \"{}\" after an array argument \"{}\".",
- argument.get_name(),
- last_array_argument.get_name(),
- ))
- .into());
- }
-
- if argument.is_required()
- && let Some(last_optional_argument) = &self.last_optional_argument
- {
- return Err(LogicException::new(format!(
- "Cannot add a required argument \"{}\" after an optional one \"{}\".",
- argument.get_name(),
- last_optional_argument.get_name(),
- ))
- .into());
- }
-
- if argument.is_array() {
- self.last_array_argument = Some(std::rc::Rc::clone(&argument));
- }
-
- if argument.is_required() {
- self.required_count += 1;
- } else {
- self.last_optional_argument = Some(std::rc::Rc::clone(&argument));
- }
-
- self.arguments
- .insert(argument.get_name().to_string(), argument);
-
- Ok(())
- }
-
- /// Returns an InputArgument by name or by position.
- pub fn get_argument(&self, name: &PhpMixed) -> anyhow::Result<std::rc::Rc<InputArgument>> {
- if !self.has_argument(name) {
- return Err(InvalidArgumentException::new(format!(
- "The \"{}\" argument does not exist.",
- name.clone()
- ))
- .into());
- }
-
- match name {
- PhpMixed::Int(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]))
- }
- }
- }
-
- /// Returns true if an InputArgument object exists by name or position.
- pub fn has_argument(&self, name: &PhpMixed) -> 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)
- }
- }
- }
-
- /// Gets the array of InputArgument objects.
- pub fn get_arguments(&self) -> &IndexMap<String, std::rc::Rc<InputArgument>> {
- &self.arguments
- }
-
- /// Returns the number of InputArguments.
- pub fn get_argument_count(&self) -> i64 {
- if self.last_array_argument.is_some() {
- i64::MAX
- } else {
- self.arguments.len() as i64
- }
- }
-
- /// Returns the number of required InputArguments.
- pub fn get_argument_required_count(&self) -> i64 {
- self.required_count
- }
-
- pub fn get_argument_defaults(&self) -> IndexMap<String, PhpMixed> {
- let mut values = IndexMap::new();
- for argument in self.arguments.values() {
- values.insert(
- argument.get_name().to_string(),
- argument.get_default().clone(),
- );
- }
-
- values
- }
-
- /// Sets the InputOption objects.
- pub fn set_options(&mut self, options: Vec<InputOption>) -> anyhow::Result<()> {
- self.options = IndexMap::new();
- self.shortcuts = IndexMap::new();
- self.negations = IndexMap::new();
- self.add_options(options)?;
- Ok(())
- }
-
- /// Adds an array of InputOption objects.
- pub fn add_options(&mut self, options: Vec<InputOption>) -> anyhow::Result<()> {
- for option in options {
- self.add_option(option)?;
- }
- Ok(())
- }
-
- pub fn add_option(&mut self, option: InputOption) -> anyhow::Result<()> {
- self.add_option_rc(std::rc::Rc::new(option))
- }
-
- /// Adds an option that is already shared behind `Rc`, mirroring PHP passing
- /// `InputOption` objects by reference.
- pub fn add_option_rc(&mut self, option: std::rc::Rc<InputOption>) -> anyhow::Result<()> {
- if let Some(existing) = self.options.get(option.get_name())
- && !option.equals(existing)
- {
- return Err(LogicException::new(format!(
- "An option named \"{}\" already exists.",
- option.get_name()
- ))
- .into());
- }
- if self.negations.contains_key(option.get_name()) {
- return Err(LogicException::new(format!(
- "An option named \"{}\" already exists.",
- option.get_name()
- ))
- .into());
- }
-
- if let Some(shortcut) = option.get_shortcut() {
- for shortcut in shirabe_php_shim::explode("|", shortcut) {
- if let Some(existing_name) = self.shortcuts.get(&shortcut)
- && !option.equals(&self.options[existing_name])
- {
- return Err(LogicException::new(format!(
- "An option with shortcut \"{}\" already exists.",
- shortcut.clone(),
- ))
- .into());
- }
- }
- }
-
- self.options
- .insert(option.get_name().to_string(), std::rc::Rc::clone(&option));
- if let Some(shortcut) = option.get_shortcut() {
- for shortcut in shirabe_php_shim::explode("|", shortcut) {
- self.shortcuts
- .insert(shortcut, option.get_name().to_string());
- }
- }
-
- if option.is_negatable() {
- let negated_name = format!("no-{}", option.get_name());
- if self.options.contains_key(&negated_name) {
- return Err(LogicException::new(format!(
- "An option named \"{}\" already exists.",
- negated_name
- ))
- .into());
- }
- self.negations
- .insert(negated_name, option.get_name().to_string());
- }
-
- Ok(())
- }
-
- /// Returns an InputOption by name.
- pub fn get_option(&self, name: &str) -> anyhow::Result<std::rc::Rc<InputOption>> {
- if !self.has_option(name) {
- return Err(InvalidArgumentException::new(format!(
- "The \"--{}\" option does not exist.",
- name
- ))
- .into());
- }
-
- Ok(std::rc::Rc::clone(&self.options[name]))
- }
-
- /// Returns true if an InputOption object exists by name.
- ///
- /// This method can't be used to check if the user included the option when
- /// executing the command (use getOption() instead).
- pub fn has_option(&self, name: &str) -> bool {
- self.options.contains_key(name)
- }
-
- /// Gets the array of InputOption objects.
- pub fn get_options(&self) -> &IndexMap<String, std::rc::Rc<InputOption>> {
- &self.options
- }
-
- /// Returns true if an InputOption object exists by shortcut.
- pub fn has_shortcut(&self, name: &str) -> bool {
- self.shortcuts.contains_key(name)
- }
-
- /// Returns true if an InputOption object exists by negated name.
- pub fn has_negation(&self, name: &str) -> bool {
- self.negations.contains_key(name)
- }
-
- /// Gets an InputOption by shortcut.
- pub fn get_option_for_shortcut(
- &self,
- shortcut: &str,
- ) -> anyhow::Result<std::rc::Rc<InputOption>> {
- self.get_option(&self.shortcut_to_name(shortcut)?)
- }
-
- pub fn get_option_defaults(&self) -> IndexMap<String, PhpMixed> {
- let mut values = IndexMap::new();
- for option in self.options.values() {
- values.insert(option.get_name().to_string(), option.get_default().clone());
- }
-
- values
- }
-
- /// Returns the InputOption name given a shortcut.
- pub fn shortcut_to_name(&self, shortcut: &str) -> anyhow::Result<String> {
- match self.shortcuts.get(shortcut) {
- None => Err(InvalidArgumentException::new(format!(
- "The \"-{}\" option does not exist.",
- shortcut
- ))
- .into()),
- Some(name) => Ok(name.clone()),
- }
- }
-
- /// Returns the InputOption name given a negation.
- pub fn negation_to_name(&self, negation: &str) -> anyhow::Result<String> {
- match self.negations.get(negation) {
- None => Err(InvalidArgumentException::new(format!(
- "The \"--{}\" option does not exist.",
- negation
- ))
- .into()),
- Some(name) => Ok(name.clone()),
- }
- }
-
- /// Gets the synopsis.
- pub fn get_synopsis(&self, short: bool) -> String {
- let mut elements: Vec<String> = vec![];
-
- if short && !self.get_options().is_empty() {
- elements.push("[options]".to_string());
- } else if !short {
- for option in self.get_options().values() {
- let mut value = String::new();
- if option.accept_value() {
- value = format!(
- " {}{}{}",
- if option.is_value_optional() {
- "[".to_string()
- } else {
- String::new()
- },
- shirabe_php_shim::strtoupper(option.get_name()),
- if option.is_value_optional() {
- "]".to_string()
- } else {
- String::new()
- },
- );
- }
-
- let shortcut = match option.get_shortcut() {
- Some(shortcut) => {
- format!("-{}|", shortcut)
- }
- None => String::new(),
- };
- let negation = if option.is_negatable() {
- format!("|--no-{}", option.get_name())
- } else {
- String::new()
- };
- elements.push(format!(
- "[{}--{}{}{}]",
- shortcut,
- option.get_name(),
- value,
- negation,
- ));
- }
- }
-
- if !elements.is_empty() && !self.get_arguments().is_empty() {
- elements.push("[--]".to_string());
- }
-
- let mut tail = String::new();
- for argument in self.get_arguments().values() {
- let mut element = format!("<{}>", argument.get_name());
- if argument.is_array() {
- element.push_str("...");
- }
-
- if !argument.is_required() {
- element = format!("[{}", element);
- tail.push(']');
- }
-
- elements.push(element);
- }
-
- format!("{}{}", shirabe_php_shim::implode(" ", &elements), tail)
- }
-}