aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-external-packages/src/symfony/console/descriptor/xml_descriptor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe-external-packages/src/symfony/console/descriptor/xml_descriptor.rs')
-rw-r--r--crates/shirabe-external-packages/src/symfony/console/descriptor/xml_descriptor.rs428
1 files changed, 428 insertions, 0 deletions
diff --git a/crates/shirabe-external-packages/src/symfony/console/descriptor/xml_descriptor.rs b/crates/shirabe-external-packages/src/symfony/console/descriptor/xml_descriptor.rs
new file mode 100644
index 0000000..209964a
--- /dev/null
+++ b/crates/shirabe-external-packages/src/symfony/console/descriptor/xml_descriptor.rs
@@ -0,0 +1,428 @@
+use crate::symfony::console::application::Application;
+use crate::symfony::console::command::command::Command;
+use crate::symfony::console::descriptor::application_description::ApplicationDescription;
+use crate::symfony::console::descriptor::descriptor::Descriptor;
+use crate::symfony::console::descriptor::descriptor_interface::DescriptorInterface;
+use crate::symfony::console::input::input_argument::InputArgument;
+use crate::symfony::console::input::input_definition::InputDefinition;
+use crate::symfony::console::input::input_option::InputOption;
+use crate::symfony::console::output::output_interface::OutputInterface;
+use indexmap::IndexMap;
+use shirabe_php_shim::PhpMixed;
+
+// NOTE: This descriptor relies on the PHP standard classes \DOMDocument and \DOMNode.
+// No equivalent has been introduced into the project yet, so every DOM operation is left
+// as todo!() pending a decision on how to model the DOM types. The type `DOMDocument` /
+// `DOMNode` placeholders below stand in for those PHP classes.
+
+/// Placeholder for the PHP standard class \DOMDocument.
+#[derive(Debug)]
+pub struct DOMDocument;
+
+/// Placeholder for the PHP standard class \DOMNode.
+#[derive(Debug)]
+pub struct DOMNode;
+
+/// XML descriptor.
+///
+/// @internal
+#[derive(Debug, Default)]
+pub struct XmlDescriptor {
+ output: Option<std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>>,
+}
+
+impl XmlDescriptor {
+ pub fn get_input_definition_document(&self, definition: &InputDefinition) -> DOMDocument {
+ let dom: DOMDocument = todo!("new \\DOMDocument('1.0', 'UTF-8')");
+ let definition_xml: DOMNode = todo!("$dom->createElement('definition')");
+ // $dom->appendChild($definitionXML)
+
+ let arguments_xml: DOMNode = todo!("$dom->createElement('arguments')");
+ // $definitionXML->appendChild($argumentsXML)
+ for argument in definition.get_arguments().values() {
+ self.append_document(&arguments_xml, &self.get_input_argument_document(argument));
+ }
+
+ let options_xml: DOMNode = todo!("$dom->createElement('options')");
+ // $definitionXML->appendChild($optionsXML)
+ for option in definition.get_options().values() {
+ self.append_document(&options_xml, &self.get_input_option_document(option));
+ }
+
+ dom
+ }
+
+ pub fn get_command_document(&self, command: &mut dyn Command, short: bool) -> DOMDocument {
+ let dom: DOMDocument = todo!("new \\DOMDocument('1.0', 'UTF-8')");
+ let command_xml: DOMNode = todo!("$dom->createElement('command')");
+ // $dom->appendChild($commandXML)
+
+ // $commandXML->setAttribute('id', $command->getName())
+ let _ = command.get_name();
+ // $commandXML->setAttribute('name', $command->getName())
+ // $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0)
+ let _ = command.is_hidden();
+
+ let usages_xml: DOMNode = todo!("$dom->createElement('usages'); appendChild");
+
+ let _description_xml: DOMNode = todo!("$dom->createElement('description'); appendChild");
+ // $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())))
+ let _ = shirabe_php_shim::str_replace("\n", "\n ", &command.get_description());
+
+ if short {
+ for usage in command.get_aliases() {
+ let _ = usage;
+ // $usagesXML->appendChild($dom->createElement('usage', $usage))
+ let _ = &usages_xml;
+ todo!("createElement('usage', $usage) and append");
+ }
+ } else {
+ command.merge_application_definition(false);
+
+ let mut usages = vec![command.get_synopsis(false)];
+ usages.extend(command.get_aliases());
+ usages.extend(command.get_usages());
+ for usage in usages {
+ let _ = usage;
+ todo!("createElement('usage', $usage) and append");
+ }
+
+ let _help_xml: DOMNode = todo!("$dom->createElement('help'); appendChild");
+ // $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())))
+ let _ = shirabe_php_shim::str_replace("\n", "\n ", &command.get_processed_help());
+
+ let command_definition = command.get_definition().clone();
+ let definition_xml = self.get_input_definition_document(&command_definition);
+ let _ = definition_xml;
+ // $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0))
+ self.append_document(
+ &command_xml,
+ todo!("$definitionXML->getElementsByTagName('definition')->item(0)"),
+ );
+ }
+
+ dom
+ }
+
+ pub fn get_application_document(
+ &self,
+ application: std::rc::Rc<std::cell::RefCell<Application>>,
+ namespace: Option<String>,
+ short: bool,
+ ) -> DOMDocument {
+ let dom: DOMDocument = todo!("new \\DOMDocument('1.0', 'UTF-8')");
+ let root_xml: DOMNode = todo!("$dom->createElement('symfony'); appendChild");
+
+ if "UNKNOWN" != application.borrow().get_name() {
+ // $rootXml->setAttribute('name', $application->getName())
+ if "UNKNOWN" != application.borrow().get_version() {
+ // $rootXml->setAttribute('version', $application->getVersion())
+ }
+ }
+
+ let commands_xml: DOMNode =
+ todo!("$dom->createElement('commands'); appendChild to rootXml");
+
+ let mut description =
+ ApplicationDescription::new(application.clone(), namespace.clone(), true);
+
+ if let Some(ref namespace) = namespace {
+ let _ = namespace;
+ // $commandsXML->setAttribute('namespace', $namespace)
+ }
+
+ let command_list: Vec<_> = description
+ .get_commands()
+ .values()
+ .map(|c| c.borrow().clone_box())
+ .collect();
+ for mut command in command_list {
+ self.append_document(
+ &commands_xml,
+ &self.get_command_document(command.as_mut(), short),
+ );
+ }
+
+ if namespace.is_none() {
+ let _namespaces_xml: DOMNode =
+ todo!("$dom->createElement('namespaces'); appendChild to rootXml");
+ let _ = &root_xml;
+
+ for namespace_description in description.get_namespaces().values() {
+ let _namespace_array_xml: DOMNode =
+ todo!("$dom->createElement('namespace'); append; setAttribute('id', ...)");
+ let _ = match namespace_description.get("id") {
+ Some(PhpMixed::String(s)) => s.clone(),
+ _ => String::new(),
+ };
+
+ if let Some(PhpMixed::List(names)) = namespace_description.get("commands") {
+ for name in names {
+ let _ = name.as_string();
+ // $commandXML = $dom->createElement('command'); append;
+ // $commandXML->appendChild($dom->createTextNode($name))
+ todo!("create command element with text node $name");
+ }
+ }
+ }
+ }
+
+ dom
+ }
+
+ fn describe_input_argument(
+ &mut self,
+ argument: &InputArgument,
+ _options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ self.write_document(self.get_input_argument_document(argument));
+ Ok(())
+ }
+
+ fn describe_input_option(
+ &mut self,
+ option: &InputOption,
+ _options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ self.write_document(self.get_input_option_document(option));
+ Ok(())
+ }
+
+ fn describe_input_definition(
+ &mut self,
+ definition: &InputDefinition,
+ _options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ self.write_document(self.get_input_definition_document(definition));
+ Ok(())
+ }
+
+ fn describe_command(
+ &mut self,
+ command: &mut dyn Command,
+ options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ let short = matches!(options.get("short"), Some(PhpMixed::Bool(true)));
+ self.write_document(self.get_command_document(command, short));
+ Ok(())
+ }
+
+ fn describe_application(
+ &mut self,
+ application: std::rc::Rc<std::cell::RefCell<Application>>,
+ options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ let namespace = match options.get("namespace") {
+ Some(PhpMixed::String(s)) => Some(s.clone()),
+ _ => None,
+ };
+ let short = matches!(options.get("short"), Some(PhpMixed::Bool(true)));
+ self.write_document(self.get_application_document(application, namespace, short));
+ Ok(())
+ }
+
+ /// Appends document children to parent node.
+ ///
+ /// In PHP `DOMDocument` extends `DOMNode`; the placeholder model accepts a
+ /// `DOMDocument` for `imported_parent` to match the call sites.
+ fn append_document(&self, parent_node: &DOMNode, imported_parent: &DOMDocument) {
+ let _ = (parent_node, imported_parent);
+ // foreach ($importedParent->childNodes as $childNode) {
+ // $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
+ // }
+ todo!("DOM import/append of child nodes");
+ }
+
+ /// Writes DOM document.
+ fn write_document(&self, dom: DOMDocument) {
+ // $dom->formatOutput = true;
+ // $this->write($dom->saveXML());
+ let xml: String = todo!("$dom->saveXML() with formatOutput = true");
+ let _ = dom;
+ self.write(&xml, false);
+ }
+
+ fn get_input_argument_document(&self, argument: &InputArgument) -> DOMDocument {
+ let dom: DOMDocument = todo!("new \\DOMDocument('1.0', 'UTF-8')");
+
+ // $objectXML = $dom->createElement('argument'); appendChild
+ // $objectXML->setAttribute('name', $argument->getName())
+ let _ = argument.get_name();
+ // $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0)
+ let _ = argument.is_required();
+ // $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0)
+ let _ = argument.is_array();
+ // $descriptionXML = $dom->createElement('description'); append;
+ // $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()))
+ let _ = argument.get_description();
+
+ // $defaultsXML = $dom->createElement('defaults'); append
+ let defaults: Vec<String> = match argument.get_default() {
+ PhpMixed::List(_) | PhpMixed::Array(_) => {
+ self.default_values_as_strings(argument.get_default())
+ }
+ PhpMixed::Bool(_) => vec![shirabe_php_shim::var_export(argument.get_default(), true)],
+ d if shirabe_php_shim::php_truthy(d) => {
+ vec![shirabe_php_shim::php_to_string(argument.get_default())]
+ }
+ _ => vec![],
+ };
+ for default in defaults {
+ let _ = default;
+ // $defaultXML = $dom->createElement('default'); append;
+ // $defaultXML->appendChild($dom->createTextNode($default))
+ todo!("create default element with text node");
+ }
+
+ dom
+ }
+
+ fn get_input_option_document(&self, option: &InputOption) -> DOMDocument {
+ let dom: DOMDocument = todo!("new \\DOMDocument('1.0', 'UTF-8')");
+
+ // $objectXML = $dom->createElement('option'); appendChild
+ // $objectXML->setAttribute('name', '--'.$option->getName())
+ let _ = format!("--{}", option.get_name());
+ let pos = shirabe_php_shim::strpos(option.get_shortcut().unwrap_or(""), "|");
+ if let Some(pos) = pos {
+ // $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos))
+ let _ = format!(
+ "-{}",
+ shirabe_php_shim::substr(option.get_shortcut().unwrap(), 0, Some(pos as i64))
+ );
+ // $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()))
+ let _ = format!(
+ "-{}",
+ shirabe_php_shim::str_replace("|", "|-", option.get_shortcut().unwrap())
+ );
+ } else {
+ // $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '')
+ let _ = match option.get_shortcut() {
+ Some(s) => format!("-{}", s),
+ None => String::new(),
+ };
+ }
+ // $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0)
+ let _ = option.accept_value();
+ // $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0)
+ let _ = option.is_value_required();
+ // $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0)
+ let _ = option.is_array();
+ // $descriptionXML = $dom->createElement('description'); append;
+ // $descriptionXML->appendChild($dom->createTextNode($option->getDescription()))
+ let _ = option.get_description();
+
+ if option.accept_value() {
+ let defaults: Vec<String> = match option.get_default() {
+ PhpMixed::List(_) | PhpMixed::Array(_) => {
+ self.default_values_as_strings(option.get_default())
+ }
+ PhpMixed::Bool(_) => vec![shirabe_php_shim::var_export(option.get_default(), true)],
+ d if shirabe_php_shim::php_truthy(d) => {
+ vec![shirabe_php_shim::php_to_string(option.get_default())]
+ }
+ _ => vec![],
+ };
+ // $defaultsXML = $dom->createElement('defaults'); append
+
+ if !defaults.is_empty() {
+ for default in defaults {
+ let _ = default;
+ // $defaultXML = $dom->createElement('default'); append;
+ // $defaultXML->appendChild($dom->createTextNode($default))
+ todo!("create default element with text node");
+ }
+ }
+ }
+
+ if option.is_negatable() {
+ // $objectXML = $dom->createElement('option'); $dom->appendChild
+ // $objectXML->setAttribute('name', '--no-'.$option->getName())
+ let _ = format!("--no-{}", option.get_name());
+ // setAttribute('shortcut', ''); setAttribute('accept_value', 0);
+ // setAttribute('is_value_required', 0); setAttribute('is_multiple', 0);
+ // $descriptionXML = $dom->createElement('description'); append;
+ // $descriptionXML->appendChild($dom->createTextNode('Negate the "--'.$option->getName().'" option'))
+ let _ = format!("Negate the \"--{}\" option", option.get_name());
+ }
+
+ dom
+ }
+
+ /// Helper used by the default-value branches of getInputArgumentDocument /
+ /// getInputOptionDocument when the default is an array (returns it verbatim).
+ fn default_values_as_strings(&self, default: &PhpMixed) -> Vec<String> {
+ match default {
+ PhpMixed::List(list) => list
+ .iter()
+ .map(|v| shirabe_php_shim::php_to_string(v))
+ .collect(),
+ PhpMixed::Array(arr) => arr
+ .values()
+ .map(|v| shirabe_php_shim::php_to_string(v))
+ .collect(),
+ _ => vec![],
+ }
+ }
+}
+
+impl DescriptorInterface for XmlDescriptor {
+ fn describe(
+ &mut self,
+ output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
+ object: PhpMixed,
+ options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ Descriptor::describe(self, output, object, options)
+ }
+}
+
+impl Descriptor for XmlDescriptor {
+ fn output(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputInterface>> {
+ self.output.clone().unwrap()
+ }
+
+ fn set_output(&mut self, output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>) {
+ self.output = Some(output);
+ }
+
+ fn describe_input_argument(
+ &mut self,
+ argument: &InputArgument,
+ options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ XmlDescriptor::describe_input_argument(self, argument, options)
+ }
+
+ fn describe_input_option(
+ &mut self,
+ option: &InputOption,
+ options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ XmlDescriptor::describe_input_option(self, option, options)
+ }
+
+ fn describe_input_definition(
+ &mut self,
+ definition: &InputDefinition,
+ options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ XmlDescriptor::describe_input_definition(self, definition, options)
+ }
+
+ fn describe_command(
+ &mut self,
+ command: &mut dyn Command,
+ options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ XmlDescriptor::describe_command(self, command, options)
+ }
+
+ fn describe_application(
+ &mut self,
+ application: std::rc::Rc<std::cell::RefCell<Application>>,
+ options: IndexMap<String, PhpMixed>,
+ ) -> anyhow::Result<()> {
+ XmlDescriptor::describe_application(self, application, options)
+ }
+}