/** * {@inheritdoc} */ public function determine() { // Where are we? SystemStore::add('_.current', preg_replace('/\\[@([^\\]]*)\\]/', ' [@' . $this->tag->getName() . ']', SystemStore::get('_.current'))); $tag = strtolower($this->tag->getName()); $this->triggerEvent("vanity.parse.user.description.{$tag}.pre", new EventStore(array('tag' => &$tag, 'ancestry' => $this->ancestry))); switch ($tag) { case 'example': $processed = new ExampleHandler($this->tag, $this->ancestry); break; case 'inheritdoc': $processed = new InheritdocHandler($this->tag, $this->ancestry); break; case 'internal': $processed = new InternalHandler($this->tag, $this->ancestry); break; case 'link': $processed = new LinkHandler($this->tag, $this->ancestry); break; case 'see': $processed = new SeeHandler($this->tag, $this->ancestry); break; default: $processed = new DefaultHandler($this->tag, $this->ancestry); break; } $this->triggerEvent("vanity.parse.user.description.{$tag}.post", new EventStore(array('tag' => &$tag, 'ancestry' => $this->ancestry))); return $processed; }
/** * {@inheritdoc} */ public function process($elongate = false) { $return = parent::process(true); if (isset($return['type'])) { $return['entity'] = $return['type']; unset($return['type']); } // Property if (preg_match('/(\\w+::)?\\$\\w+/', $return['entity'])) { $return['entity_hint'] = 'property'; } elseif (preg_match('/(\\w+::)?[\\w_]+(\\(\\))/', $return['entity'])) { $return['entity_hint'] = 'method'; } elseif (preg_match('/[\\w_]+/', $return['entity'])) { $return['entity_hint'] = 'class'; } elseif (preg_match('/https?:/', $return['entity'])) { // Used @see when @link was more appropriate $formatter = ConsoleUtil::formatters(); Inconsistency::add('Used @' . $this->tag . ' when @link was more appropriate. => ' . $formatter->gold->apply(SystemStore::get('_.current'))); $return['entity_hint'] = 'uri'; } // Do we need to resolve? if (strpos($return['entity'], '::') !== false) { list($class, $entity) = explode('::', $return['entity']); $class = $this->ancestry->resolveNamespace($class); $return['entity'] = implode('::', array($class, $entity)); } elseif ($return['entity_hint'] === 'method' || $return['entity_hint'] === 'property') { $class = $this->ancestry->getClass(); $return['entity'] = implode('::', array($class, $return['entity'])); } return $return; }
/** * {@inheritdoc} */ public function process($elongate = false) { // Used @var, which is deprecated if (strtolower($this->tag) === 'var') { $formatter = ConsoleUtil::formatters(); Inconsistency::add('The @var keyword is deprecated. Use @type instead. => ' . $formatter->gold->apply(SystemStore::get('_.current'))); } return parent::process(true); }
/** * {@inheritdoc} */ public function determine() { // Where are we? SystemStore::add('_.current', preg_replace('/\\[@([^\\]]*)\\]/', ' [@' . $this->tag->getName() . ']', SystemStore::get('_.current'))); $tag = strtolower($this->tag->getName()); $this->triggerEvent("vanity.parse.user.tag.{$tag}.pre", new EventStore(array('tag' => &$tag, 'ancestry' => $this->ancestry))); switch ($tag) { case 'api': $processed = new ApiHandler($this->tag, $this->ancestry); break; case 'author': $processed = new AuthorHandler($this->tag, $this->ancestry); break; case 'copyright': $processed = new CopyrightHandler($this->tag, $this->ancestry); break; case 'deprecated': case 'depreciated': $processed = new DeprecatedHandler($this->tag, $this->ancestry); break; case 'dispatches': case 'event': $processed = new EventHandler($this->tag, $this->ancestry); break; case 'example': $processed = new ExampleHandler($this->tag, $this->ancestry); break; case 'global': $processed = new GlobalHandler($this->tag, $this->ancestry); break; case 'internal': $processed = new InternalHandler($this->tag, $this->ancestry); break; case 'license': $processed = new LicenseHandler($this->tag, $this->ancestry); break; case 'link': $processed = new LinkHandler($this->tag, $this->ancestry); break; case 'method': $processed = new MethodHandler($this->tag, $this->ancestry); break; case 'package': $processed = new PackageHandler($this->tag, $this->ancestry); break; case 'param': $processed = new ParamHandler($this->tag, $this->ancestry); break; case 'property': case 'property-read': case 'property-write': $processed = new PropertyHandler($this->tag, $this->ancestry); break; case 'return': case 'returns': $processed = new ReturnHandler($this->tag, $this->ancestry); break; case 'alias': case 'see': $processed = new SeeHandler($this->tag, $this->ancestry); break; case 'since': case 'available': $processed = new SinceHandler($this->tag, $this->ancestry); break; case 'throw': case 'throws': $processed = new ThrowHandler($this->tag, $this->ancestry); break; case 'todo': case 'fixme': $processed = new TodoHandler($this->tag, $this->ancestry); break; case 'type': case 'var': $processed = new TypeHandler($this->tag, $this->ancestry); break; case 'uses': case 'used-by': $processed = new UsesHandler($this->tag, $this->ancestry); break; case 'version': $processed = new VersionHandler($this->tag, $this->ancestry); break; default: $processed = new DefaultHandler($this->tag, $this->ancestry); break; } $this->triggerEvent("vanity.parse.user.tag.{$tag}.post", new EventStore(array('tag' => &$tag, 'ancestry' => $this->ancestry))); return $processed; }
public static function resolve($reflected) { $is_method = false; $is_property = false; // Are we working with a property or a method? if ($reflected instanceof ReflectionMethod) { $is_method = true; } elseif ($reflected instanceof ReflectionProperty) { $is_property = true; } else { throw new Exception('Only methods and properties can be reflected with ' . get_called_class()); } // Parse the docblock $docblock = new DocBlock($reflected->getDocComment()); $found_description = false; $return = $reflected; // Save these for messaging $__class = $reflected->getDeclaringClass()->getName(); $__kind = $reflected->getName(); // Can we just do a straight-up inherit? // @todo: Do a better job of handling {@inheritdoc} according to the spec. try { while (!$found_description && strpos($docblock->getShortDescription(), '{@inheritdoc}') !== false) { // Start over... $found_description = false; // Log that we're starting... Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Starting resolution:', array(sprintf("{$__class}%s{$__kind}%s", $is_method ? '::' : '::$', $is_method ? '()' : ''))); // Grab a reference to the class containing the entity with the {@inheritdoc} tag $klass = $reflected->getDeclaringClass(); // Is this an Interface? if ($klass->isInterface()) { throw new InheritdocInInterfaceException('The {@inheritdoc} tag is not resolvable from within Interfaces. Methods and properties should ' . 'be fully-documented.'); } elseif (SystemStore::get('_.php54') && $klass->isTrait()) { throw new InheritdocInTraitException('The {@inheritdoc} tag is not resolvable from within Traits. Methods and properties should ' . 'be fully-documented.'); } // Are we using Interfaces? if (!$found_description && ($interface_count = count($klass->getInterfaces())) > 0) { $count = 1; foreach ($klass->getInterfaces() as $rinterface) { Logger::get()->{ConfigStore::get('log.info')}("{@inheritdoc} Checking Interface {$count}/{$interface_count}:", array($rinterface->getName())); try { $return = $rinterface->getMethod($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($rinterface->getName(), $reflected->getName(), 'Method')); $found_description = true; break 2; } catch (Exception $e) { try { $return = $rinterface->getProperty($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($rinterface->getName(), $reflected->getName(), 'Property')); $found_description = true; break 2; } catch (Exception $e) { Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} No match. Will keep looking...', array($rinterface->getName(), $reflected->getName())); } } $count++; } } // Are we using Traits? if (!$found_description && SystemStore::get('_.php54') && ($trait_count = count($klass->getTraits())) > 0) { $count = 1; foreach ($klass->getTraits() as $rtrait) { Logger::get()->{ConfigStore::get('log.info')}("{@inheritdoc} Checking Trait {$count}/{$trait_count}:", array($rtrait->getName())); try { $return = $rtrait->getMethod($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($rtrait->getName(), $reflected->getName(), 'Method')); $found_description = true; break 2; } catch (Exception $e) { try { $return = $rtrait->getProperty($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($rtrait->getName(), $reflected->getName(), 'Property')); $found_description = true; break 2; } catch (Exception $e) { Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} No match. Will keep looking...', array($rtrait->getName(), $reflected->getName())); } } $count++; } } // Are we extending a class? if ($klass->getParentClass()) { // Continue climbing up the ancestry as necessary while (!$found_description && $klass->getParentClass()) { // Rewrite the reference to $klass $klass = $klass->getParentClass(); Logger::get()->{ConfigStore::get('log.info')}("{@inheritdoc} Checking the parent class:", array($klass->getName())); try { $return = $klass->getMethod($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($klass->getName(), $reflected->getName(), 'Method')); $found_description = true; break 2; } catch (Exception $e) { try { $return = $klass->getProperty($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($klass->getName(), $reflected->getName(), 'Property')); $found_description = true; break 2; } catch (Exception $e) { Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} No match. Will keep looking...', array($klass->getName(), $reflected->getName())); } } } } // We couldn't find anything throw new CouldNotResolveInheritdocException('Leaving as-is. The tag will be viewable in the ' . 'resulting documentation.'); } } catch (InheritdocInInterfaceException $e) { $message = sprintf("{$__class}%s{$__kind}%s", $is_method ? '::' : '::$', $is_method ? '()' : ''); // Log that we're starting... Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} ' . $e->getMessage(), array($message)); $formatter = ConsoleUtil::formatters(); Inconsistency::add($message . $formatter->gold->apply(' => Could not resolve {@inheritdoc}. ' . $e->getMessage())); } catch (InheritdocInTraitException $e) { $message = sprintf("{$__class}%s{$__kind}%s", $is_method ? '::' : '::$', $is_method ? '()' : ''); // Log that we're starting... Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} ' . $e->getMessage(), array($message)); $formatter = ConsoleUtil::formatters(); Inconsistency::add($message . $formatter->gold->apply(' => Could not resolve {@inheritdoc}. ' . $e->getMessage())); } catch (CouldNotResolveInheritdocException $e) { $message = sprintf("{$__class}%s{$__kind}%s", $is_method ? '::' : '::$', $is_method ? '()' : ''); // Log that we're starting... Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} ' . $e->getMessage(), array($message)); $formatter = ConsoleUtil::formatters(); Inconsistency::add($message . $formatter->gold->apply(' => Could not resolve {@inheritdoc}. ' . $e->getMessage())); } catch (VanityException $e) { } catch (Exception $e) { } return $return; }
/** * Copyright (c) 2009-2012 [Ryan Parman](http://ryanparman.com) * Copyright (c) 2011-2012 [Amazon Web Services, Inc.](http://aws.amazon.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * <http://www.opensource.org/licenses/mit-license.php> */ /********************************************************/ // AVAILABLE CONFIGURATION-RELATED OPTIONS use Symfony\Component\Console\Input\InputOption; use Vanity\System\Store as SystemStore; return array('vanity' => array('view_config' => array(InputOption::VALUE_NONE, 'Display Vanity\'s configuration settings, and stop.', null), 'config_dir' => array(InputOption::VALUE_OPTIONAL, 'The directory which contains the project\'s Vanity configuration. Vanity will use this for resolving default paths.', SystemStore::get('_.project_config_dir')), 'bootstrap' => array(InputOption::VALUE_OPTIONAL, 'This file is loaded first. Useful for telling Vanity how to load project classes, settings constants, or other things.', '%VANITY.CONFIG_DIR%/bootstrap.php'), 'name' => array(InputOption::VALUE_OPTIONAL, 'The name of the product.', pathinfo(VANITY_PROJECT_WORKING_DIR, PATHINFO_FILENAME)), 'stage' => array(InputOption::VALUE_OPTIONAL, 'The stage that the project is currently in. Can be any ASCII value. (e.g., development, alpha, beta, rc, production).', 'development'), 'version' => array(InputOption::VALUE_OPTIONAL, 'The version number we should use.', 'latest'), 'reports' => array(InputOption::VALUE_OPTIONAL, 'The location to use for writing various reports that have been enabled.', '%VANITY.CONFIG_DIR%/reports')), 'log' => array('aliases' => array(InputOption::VALUE_OPTIONAL, 'Which severity should Alias/Ancestry Resolution messages have?', 'debug'), 'commands' => array(InputOption::VALUE_OPTIONAL, 'Which severity should Command begin/end messages have?', 'debug'), 'error' => array(InputOption::VALUE_OPTIONAL, 'Which severity should Error messages have?', 'error'), 'events' => array(InputOption::VALUE_OPTIONAL, 'Which severity should Event Trigger messages have?', 'debug'), 'info' => array(InputOption::VALUE_OPTIONAL, 'Which severity should Notice messages have?', 'info'), 'warn' => array(InputOption::VALUE_OPTIONAL, 'Which severity should Warning messages have?', 'warn')), 'report' => array('dependencies' => array(InputOption::VALUE_OPTIONAL, 'Write a report if there are environment dependencies for the project.', false), 'inconsistencies' => array(InputOption::VALUE_OPTIONAL, 'Write a report if there are documentation inconsistencies.', false), 'todo' => array(InputOption::VALUE_OPTIONAL, 'Write a report if there are TODOs.', false), 'ungrouped' => array(InputOption::VALUE_OPTIONAL, 'Write a report if there are ungrouped methods.', false)), 'warn' => array('dependencies' => array(InputOption::VALUE_OPTIONAL, 'Warn on the console if there are environment dependencies for the project.', false), 'inconsistencies' => array(InputOption::VALUE_OPTIONAL, 'Warn on the console if there are documentation inconsistencies.', false), 'todo' => array(InputOption::VALUE_OPTIONAL, 'Warn on the console if there are TODOs.', false), 'ungrouped' => array(InputOption::VALUE_OPTIONAL, 'Warn on the console if there are ungrouped methods.', false)));
/** * Resolves a namespace alias into a fully-qualified namespace. * * @param string $short A shortened namespace alias. * @return string The fully-qualified namespace, if available. */ public function resolveNamespace($short) { if (isset($this->aliases[$short])) { Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: Matched in the list of known aliases.', array($short, $this->aliases[$short])); return $this->aliases[$short]; } else { // Handle implicit aliases in the same namespace. try { $namespace = $this->class->getNamespaceName() . '\\' . $short; new ReflectionClass($namespace); Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: Matched in the current namespace.', array($short, $namespace)); // If we didn't throw an exception, we're good. return $namespace; } catch (ReflectionException $e) { // Handle implicit namespaces in an extended/implemented namespace. try { foreach ($this->namespaces as $ns) { try { $namespace = $ns . '\\' . $short; new ReflectionClass($namespace); Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: Matched in an extended/implemented namespace.', array($short, $namespace)); // If we didn't throw an exception, we're good. return $namespace; } catch (ReflectionException $e) { } } throw new ReflectionException(); } catch (ReflectionException $e) { // Try removing the beginning '\' to see if we find a match. try { $class = preg_replace('/^\\\\/', '', $short); new ReflectionClass($class); Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: Matched by stripping the \\ prefix.', array($short, $class)); // If we didn't throw an exception, we're good. return $class; } catch (ReflectionException $e) { $formatter = ConsoleUtil::formatters(); Inconsistency::add($class . $formatter->gold->apply(' => No match found for ' . $short . ' (' . SystemStore::get('_.current') . ')')); Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: No match found.', array($short)); // No match. Return it as-is (without any starting backslash). return $class; } } } } }
/** * An array of file paths retrieved from {@see files()}. * * @param array $files A list of file paths. * @return array A list of classes. */ public static function classes(array $files) { $loader = new UniversalClassLoader(); // Support PSR-0 autoloading with a composer.json file // @todo: Add support for Composer's classmap autoloading. if (file_exists(VANITY_PROJECT_WORKING_DIR . '/vendor/composer/autoload_namespaces.php')) { // Register namespaces with the class loader $loader->registerNamespaces(include VANITY_PROJECT_WORKING_DIR . '/vendor/composer/autoload_namespaces.php'); } elseif (file_exists(VANITY_PROJECT_WORKING_DIR . '/composer.json')) { // Register namespaces with the class loader $composer = json_decode(file_get_contents(VANITY_PROJECT_WORKING_DIR . '/composer.json'), true); if (isset($composer['autoload']) && isset($composer['autoload']['psr-0'])) { $loader->registerNamespaces($composer['autoload']['psr-0']); } } $loader->register(); $class_list = array(); // Collect all current classes, interfaces and traits if (SystemStore::get('_.php54')) { $before = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits()); } else { $before = array_merge(get_declared_classes(), get_declared_interfaces()); } foreach ($files as $file) { include_once $file; } // Handle traits if this version of PHP supports them. if (SystemStore::get('_.php54')) { $after = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits()); } else { $after = array_merge(get_declared_classes(), get_declared_interfaces()); } // We should be able to document ourselves if (defined('VANITY_AM_I')) { $after = array_filter($after, function ($class) { return substr($class, 0, 7) !== 'Vanity\\'; }); } $class_list = array_values(array_unique(array_diff($after, $before))); sort($class_list); return $class_list; }
/** * Trigger an event containing the log path. * * @return void */ public function triggerLogMessageEvent() { $this->triggerEvent('vanity.command.log_path', new EventStore(array('log_path' => SystemStore::get('_.log_dir'), 'time' => SystemStore::get('_.run_time')))); }
/** * Reflects over the given class and produces an associative array * containing all relevant class data. * * @event EventStore vanity.parse.user.reflect.pre * @event EventStore vanity.parse.user.reflect.post * @return array An associative array containing all relevant class data. */ public function process() { // REFLECT ALL THE THINGS! $rclass_methods = $this->rclass->getMethods(); $long_filename = $this->rclass->getFileName(); $short_filename = str_replace(array(VANITY_SYSTEM . '/', VANITY_PROJECT_WORKING_DIR . '/'), '', $long_filename); $this->triggerEvent("vanity.parse.user.reflect.pre", new EventStore(array('data' => &$this->data))); $this->data['name'] = $this->rclass->getShortName(); $this->data['namespace'] = $this->rclass->getNamespaceName(); $this->data['full_name'] = $this->class_name; $this->data['namespace_as_path'] = str_replace('\\', '/', $this->class_name); $this->data['path'] = $short_filename; if (SystemStore::get('_.php54') && $this->rclass->isTrait()) { $this->data['kind'] = 'Trait'; } elseif ($this->rclass->isInterface()) { $this->data['kind'] = 'Interface'; } elseif ($this->rclass->isSubClassOf('Exception')) { $this->data['kind'] = 'Exception'; } else { $this->data['kind'] = 'Class'; } SystemStore::add('_.current', $this->class_name); #--------------------------------------------------------------------------# // Enable GitHub lookups for author data if (ConfigStore::get('source.github.user') && ConfigStore::get('source.github.pass')) { $github = new GitHub(ConfigStore::get('source.github.user'), ConfigStore::get('source.github.pass')); $github->setRepository(ConfigStore::get('source.github.repo_owner'), ConfigStore::get('source.github.repo_name')); $this->data['github'] = $github->getAuthorsForFile($this->data['path']); } #--------------------------------------------------------------------------# // Add description if ($description = $this->class_tags->getDescription()) { $this->data['description'] = $description; } // Add inheritance chain if ($this->inheritance) { $this->data['inheritance'] = $this->inheritance; } // Add implemented interfaces if ($this->implements) { $this->data['implements'] = $this->implements; } // Add used traits if ($this->traits) { $this->data['traits'] = $this->traits; } // Add class tags if ($tags = $this->class_tags->getTags()) { $this->data['metadata'] = $tags; } // Add constants if ($constants = $this->constants->getConstants()) { $this->data['constants'] = $constants; } // Add properties if ($properties = $this->properties->getProperties()) { $this->data['properties'] = $properties; } // Add meta-properties if (isset($this->data['metadata']) && isset($this->data['properties'])) { $new = $this->formatMetaProperties($this->data['metadata']); $this->data['properties']['property'] = array_merge($this->data['properties']['property'], $new); $this->data['properties']['count'] += count($new); } elseif (isset($this->data['metadata'])) { $new = $this->formatMetaProperties($this->data['metadata']); $this->data['properties']['property'] = $new; $this->data['properties']['count'] = count($new); } // Sort the properties alphabetically if (isset($this->data['properties']) && isset($this->data['properties']['property']) && is_array($this->data['properties']['property'])) { usort($this->data['properties']['property'], function ($a, $b) { $a = $a['name']; $b = $b['name']; if ($a === $b) { return 0; } return $a < $b ? -1 : 1; }); } // Add methods if ($methods = $this->methods->getMethods()) { $this->data['methods'] = $methods; } // Add meta-methods if (isset($this->data['metadata']) && isset($this->data['methods'])) { $new = $this->formatMetaMethods($this->data['metadata']); $this->data['methods']['method'] = array_merge($this->data['methods']['method'], $new); $this->data['methods']['count'] += count($new); } elseif (isset($this->data['metadata'])) { $new = $this->formatMetaMethods($this->data['metadata']); $this->data['methods']['method'] = $new; $this->data['methods']['count'] = count($new); } // Sort the methods alphabetically if (isset($this->data['methods']) && isset($this->data['methods']['method']) && is_array($this->data['methods']['method'])) { usort($this->data['methods']['method'], function ($a, $b) { $a = $a['name']; $b = $b['name']; if ($a === $b) { return 0; } return $a < $b ? -1 : 1; }); } // Sort the metadata tags, post-edit from @method, @property and @return if (isset($this->data['metadata'])) { $this->data['metadata']['tag'] = array_values($this->data['metadata']['tag']); // Sort the tags alphabetically usort($this->data['metadata']['tag'], function ($a, $b) { $a = $a['name']; $b = $b['name']; if ($a === $b) { return 0; } return $a < $b ? -1 : 1; }); } // Handle alias tags $this->triggerEvent("vanity.parse.user.reflect.post", new EventStore(array('data' => &$this->data))); }
/** * Return the config values passed in the config.yml file. * * @return array The config values passed in the config.yml file. */ private function fileValues() { // Use the config directory passed to the CLI $config_dir = $this->cliValues(true) ?: SystemStore::get('_.project_config_dir'); if (file_exists($config_dir . '/config.yml')) { ConfigStore::$messages[] = 'Merged configuration options from ' . $this->formatter->info->apply(' ' . $config_dir . '/config.yml '); $options = YAML::parse($config_dir . '/config.yml'); $config = ConfigStore::convert($options); $config = array_filter($config); return $config; } return array(); }