Initial Commit

This commit is contained in:
2018-10-15 00:37:28 -05:00
commit b0bd5569c0
7508 changed files with 849336 additions and 0 deletions

21
vendor/nunomaduro/collision/LICENSE.md vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Nuno Maduro <enunomaduro@gmail.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.

66
vendor/nunomaduro/collision/README.md vendored Normal file
View File

@@ -0,0 +1,66 @@
<p align="center">
<img src="https://raw.githubusercontent.com/nunomaduro/collision/stable/docs/logo.png" alt="Collision logo" width="480">
<br>
<img src="https://raw.githubusercontent.com/nunomaduro/collision/stable/docs/example.png" alt="Collision code example" height="300">
</p>
<p align="center">
<a href="https://travis-ci.org/nunomaduro/collision"><img src="https://img.shields.io/travis/nunomaduro/collision/stable.svg" alt="Build Status"></img></a>
<a href="https://scrutinizer-ci.com/g/nunomaduro/collision"><img src="https://img.shields.io/scrutinizer/g/nunomaduro/collision.svg" alt="Quality Score"></img></a>
<a href="https://scrutinizer-ci.com/g/nunomaduro/collision"><img src="https://img.shields.io/scrutinizer/coverage/g/nunomaduro/collision.svg" alt="Coverage"></img></a>
<a href="https://packagist.org/packages/nunomaduro/collision"><img src="https://poser.pugx.org/nunomaduro/collision/d/total.svg" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/nunomaduro/collision"><img src="https://poser.pugx.org/nunomaduro/collision/v/stable.svg" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/nunomaduro/collision"><img src="https://poser.pugx.org/nunomaduro/collision/license.svg" alt="License"></a>
</p>
## About Collision
Collision was created by, and is maintained by [Nuno Maduro](https://github.com/nunomaduro), and is an error handler framework for console/command-line PHP applications.
- Build on top of [Whoops](https://github.com/filp/whoops).
- Supports [Laravel](https://github.com/laravel/laravel) Artisan & [PHPUnit](https://github.com/sebastianbergmann/phpunit).
- Built with [PHP 7](https://php.net) using modern coding standards.
## Installation & Usage
> **Requires [PHP 7.1+](https://php.net/releases/)**
Require Collision using [Composer](https://getcomposer.org):
```bash
composer require nunomaduro/collision --dev
```
If you are not using Laravel, you need to register the handler in your code:
```php
(new \NunoMaduro\Collision\Provider)->register();
```
## Phpunit adapter
Phpunit must be 7.0 or higher.
Add the following configuration to your `phpunit.xml`:
```xml
<listeners>
<listener class="NunoMaduro\Collision\Adapters\Phpunit\Listener" />
</listeners>
```
## Contributing
Thank you for considering to contribute to Collision. All the contribution guidelines are mentioned [here](CONTRIBUTING.md).
You can have a look at the [CHANGELOG](CHANGELOG.md) for constant updates & detailed information about the changes. You can also follow the twitter account for latest announcements or just come say hi!: [@enunomaduro](https://twitter.com/enunomaduro)
## Support the development
**Do you like this project? Support it by donating**
- PayPal: [Donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L)
- Patreon: [Donate](https://www.patreon.com/nunomaduro)
## License
Collision is an open-sourced software licensed under the [MIT license](LICENSE.md).

View File

@@ -0,0 +1,50 @@
{
"name": "nunomaduro/collision",
"description": "Cli error handling for console/command-line PHP applications.",
"keywords": ["console", "command-line", "php", "cli", "error", "handling", "laravel-zero", "laravel", "artisan", "symfony"],
"license": "MIT",
"support": {
"issues": "https://github.com/nunomaduro/collision/issues",
"source": "https://github.com/nunomaduro/collision"
},
"authors": [
{
"name": "Nuno Maduro",
"email": "enunomaduro@gmail.com"
}
],
"require": {
"php": "^7.1",
"filp/whoops": "^2.1.4",
"symfony/console": "~2.8|~3.3|~4.0",
"jakub-onderka/php-console-highlighter": "0.3.*"
},
"require-dev": {
"phpunit/phpunit": "~7.3",
"phpstan/phpstan": "^0.10",
"laravel/framework": "5.7.*"
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"NunoMaduro\\Collision\\": "src/"
}
},
"config": {
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"laravel": {
"providers": [
"NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider"
]
}
}
}

View File

@@ -0,0 +1,8 @@
parameters:
level: max
paths:
- src
reportUnmatchedIgnoredErrors: false
ignoreErrors:
- '#Call to an undefined method Illuminate\\Contracts\\Debug\\ExceptionHandler::shouldReport().#'
- '#Parameter \#1 \$input of function str_pad expects string, int given.#'

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
failOnRisky="true"
failOnWarning="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
verbose="true"
>
<testsuites>
<testsuite name="Collision Test Suite">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -0,0 +1,62 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Adapters\Laravel;
use NunoMaduro\Collision\Provider;
use Illuminate\Support\ServiceProvider;
use NunoMaduro\Collision\Adapters\Phpunit\Listener;
use NunoMaduro\Collision\Contracts\Provider as ProviderContract;
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract;
use NunoMaduro\Collision\Contracts\Adapters\Phpunit\Listener as ListenerContract;
/**
* This is an Collision Laravel Adapter Service Provider implementation.
*
* Registers the Error Handler on Laravel.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class CollisionServiceProvider extends ServiceProvider
{
/**
* {@inheritdoc}
*/
protected $defer = true;
/**
* {@inheritdoc}
*/
public function register()
{
if ($this->app->runningInConsole() && ! $this->app->runningUnitTests()) {
$this->app->singleton(ListenerContract::class, Listener::class);
$this->app->bind(ProviderContract::class, Provider::class);
$appExceptionHandler = $this->app->make(ExceptionHandlerContract::class);
$this->app->singleton(
ExceptionHandlerContract::class,
function ($app) use ($appExceptionHandler) {
return new ExceptionHandler($app, $appExceptionHandler);
}
);
}
}
/**
* {@inheritdoc}
*/
public function provides()
{
return [ProviderContract::class];
}
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Adapters\Laravel;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use NunoMaduro\Collision\Contracts\Provider as ProviderContract;
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract;
use Symfony\Component\Console\Exception\ExceptionInterface as SymfonyConsoleExceptionInterface;
/**
* This is an Collision Laravel Adapter ExceptionHandler implementation.
*
* Registers the Error Handler on Laravel.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class ExceptionHandler implements ExceptionHandlerContract
{
/**
* Holds an instance of the application exception handler.
*
* @var \Illuminate\Contracts\Debug\ExceptionHandler
*/
protected $appExceptionHandler;
/**
* Holds an instance of the application.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* Creates a new instance of the ExceptionHandler.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Contracts\Debug\ExceptionHandler $appExceptionHandler
*/
public function __construct(Application $app, ExceptionHandlerContract $appExceptionHandler)
{
$this->app = $app;
$this->appExceptionHandler = $appExceptionHandler;
}
/**
* {@inheritdoc}
*/
public function report(Exception $e)
{
$this->appExceptionHandler->report($e);
}
/**
* {@inheritdoc}
*/
public function render($request, Exception $e)
{
return $this->appExceptionHandler->render($request, $e);
}
/**
* {@inheritdoc}
*/
public function renderForConsole($output, Exception $e)
{
if ($e instanceof SymfonyConsoleExceptionInterface) {
$this->appExceptionHandler->renderForConsole($output, $e);
} else {
$handler = $this->app->make(ProviderContract::class)
->register()
->getHandler()
->setOutput($output);
$handler->setInspector((new Inspector($e)));
$handler->handle();
}
}
/**
* Determine if the exception should be reported.
*
* @param \Exception $e
* @return bool
*/
public function shouldReport(Exception $e)
{
return $this->appExceptionHandler->shouldReport($e);
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Adapters\Laravel;
use Whoops\Exception\Inspector as BaseInspector;
/**
* This is an Collision Laravel Adapter Inspector implementation.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class Inspector extends BaseInspector
{
/**
* {@inheritdoc}
*/
protected function getTrace($e)
{
return $e->getTrace();
}
}

View File

@@ -0,0 +1,177 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Adapters\Phpunit;
use ReflectionObject;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\Warning;
use Whoops\Exception\Inspector;
use NunoMaduro\Collision\Writer;
use PHPUnit\Framework\TestSuite;
use Symfony\Component\Console\Application;
use PHPUnit\Framework\AssertionFailedError;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use NunoMaduro\Collision\Contracts\Writer as WriterContract;
use NunoMaduro\Collision\Contracts\Adapters\Phpunit\Listener as ListenerContract;
if (class_exists(\PHPUnit\Runner\Version::class) && substr(\PHPUnit\Runner\Version::id(), 0, 2) === '7.') {
/**
* This is an Collision Phpunit Adapter implementation.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class Listener implements ListenerContract
{
/**
* Holds an instance of the writer.
*
* @var \NunoMaduro\Collision\Contracts\Writer
*/
protected $writer;
/**
* Holds the exception found, if any.
*
* @var \Throwable|null
*/
protected $exceptionFound;
/**
* Creates a new instance of the class.
*
* @param \NunoMaduro\Collision\Contracts\Writer|null $writer
*/
public function __construct(WriterContract $writer = null)
{
$this->writer = $writer ?: $this->buildWriter();
}
/**
* {@inheritdoc}
*/
public function render(\Throwable $t)
{
$inspector = new Inspector($t);
$this->writer->write($inspector);
}
/**
* {@inheritdoc}
*/
public function addError(Test $test, \Throwable $t, float $time): void
{
if ($this->exceptionFound === null) {
$this->exceptionFound = $t;
}
}
/**
* {@inheritdoc}
*/
public function addWarning(Test $test, Warning $t, float $time): void
{
}
/**
* {@inheritdoc}
*/
public function addFailure(Test $test, AssertionFailedError $t, float $time): void
{
$this->writer->ignoreFilesIn(['/vendor/'])
->showTrace(false);
if ($this->exceptionFound === null) {
$this->exceptionFound = $t;
}
}
/**
* {@inheritdoc}
*/
public function addIncompleteTest(Test $test, \Throwable $t, float $time): void
{
}
/**
* {@inheritdoc}
*/
public function addRiskyTest(Test $test, \Throwable $t, float $time): void
{
}
/**
* {@inheritdoc}
*/
public function addSkippedTest(Test $test, \Throwable $t, float $time): void
{
}
/**
* {@inheritdoc}
*/
public function startTestSuite(TestSuite $suite): void
{
}
/**
* {@inheritdoc}
*/
public function endTestSuite(TestSuite $suite): void
{
}
/**
* {@inheritdoc}
*/
public function startTest(Test $test): void
{
}
/**
* {@inheritdoc}
*/
public function endTest(Test $test, float $time): void
{
}
/**
* {@inheritdoc}
*/
public function __destruct()
{
if ($this->exceptionFound !== null) {
$this->render($this->exceptionFound);
}
}
/**
* Builds an Writer.
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
protected function buildWriter(): WriterContract
{
$writer = new Writer;
$application = new Application();
$reflector = new ReflectionObject($application);
$method = $reflector->getMethod('configureIO');
$method->setAccessible(true);
$method->invoke($application, new ArgvInput, $output = new ConsoleOutput);
return $writer->setOutput($output);
}
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision;
use NunoMaduro\Collision\Contracts\ArgumentFormatter as ArgumentFormatterContract;
/**
* This is an Collision Argument Formatter implementation.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class ArgumentFormatter implements ArgumentFormatterContract
{
/**
* {@inheritdoc}
*/
public function format(array $arguments, bool $recursive = true): string
{
$result = [];
foreach ($arguments as $argument) {
switch (true) {
case is_string($argument):
$result[] = '"'.$argument.'"';
break;
case is_array($argument):
$associative = array_keys($argument) !== range(0, count($argument) - 1);
if ($recursive && $associative && count($argument) <= 5) {
$result[] = '['.$this->format($argument, false).']';
}
break;
case is_object($argument):
$class = get_class($argument);
$result[] = "Object($class)";
break;
}
}
return implode(', ', $result);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Contracts\Adapters\Phpunit;
use PHPUnit\Framework\TestListener;
/**
* This is an Collision Phpunit Adapter contract.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
interface Listener extends TestListener
{
/**
* Renders the provided error
* on the console.
*
* @param \Throwable $t
*
* @return void
*/
public function render(\Throwable $t);
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Contracts;
/**
* This is an Collision Argument Formatter contract.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
interface ArgumentFormatter
{
/**
* Formats the provided array of arguments into
* an understandable description.
*
* @param array $arguments
* @param bool $recursive
*
* @return string
*/
public function format(array $arguments, bool $recursive = true): string;
}

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Contracts;
use Whoops\Handler\HandlerInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* This is an Collision Handler contract.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
interface Handler extends HandlerInterface
{
/**
* Sets the output.
*
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return \NunoMaduro\Collision\Contracts\Handler
*/
public function setOutput(OutputInterface $output): Handler;
/**
* Returns the writer.
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
public function getWriter(): Writer;
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Contracts;
/**
* This is the Collision Highlighter contract.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
interface Highlighter
{
/**
* Highlights the provided content.
*
* @param string $content
* @param int $line
*
* @return string
*/
public function highlight(string $content, int $line): string;
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Contracts;
/**
* This is an Collision Provider contract.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
interface Provider
{
/**
* Registers the current Handler as Error Handler.
*
* @return \NunoMaduro\Collision\Contracts\Provider
*/
public function register(): Provider;
/**
* Returns the handler.
*
* @return \NunoMaduro\Collision\Contracts\Handler
*/
public function getHandler(): Handler;
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision\Contracts;
use Whoops\Exception\Inspector;
use Symfony\Component\Console\Output\OutputInterface;
/**
* This is the Collision Writer contract.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
interface Writer
{
/**
* Ignores traces where the file string matches one
* of the provided regex expressions.
*
* @param string[] $ignore The regex expressions.
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
public function ignoreFilesIn(array $ignore): Writer;
/**
* Declares whether or not the Writer should show the trace.
*
* @param bool $show
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
public function showTrace(bool $show): Writer;
/**
* Declares whether or not the Writer should show the editor.
*
* @param bool $show
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
public function showEditor(bool $show): Writer;
/**
* Writes the details of the exception on the console.
*
* @param \Whoops\Exception\Inspector $inspector
*/
public function write(Inspector $inspector): void;
/**
* Sets the output.
*
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
public function setOutput(OutputInterface $output): Writer;
/**
* Gets the output.
*
* @return \Symfony\Component\Console\Output\OutputInterface
*/
public function getOutput(): OutputInterface;
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision;
use Whoops\Handler\Handler as AbstractHandler;
use Symfony\Component\Console\Output\OutputInterface;
use NunoMaduro\Collision\Contracts\Writer as WriterContract;
use NunoMaduro\Collision\Contracts\Handler as HandlerContract;
/**
* This is an Collision Handler implementation.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class Handler extends AbstractHandler implements HandlerContract
{
/**
* Holds an instance of the writer.
*
* @var \NunoMaduro\Collision\Contracts\Writer
*/
protected $writer;
/**
* Creates an instance of the Handler.
*
* @param \NunoMaduro\Collision\Contracts\Writer|null $writer
*/
public function __construct(WriterContract $writer = null)
{
$this->writer = $writer ?: new Writer;
}
/**
* {@inheritdoc}
*/
public function handle()
{
$this->writer->write($this->getInspector());
return static::QUIT;
}
/**
* {@inheritdoc}
*/
public function setOutput(OutputInterface $output): HandlerContract
{
$this->writer->setOutput($output);
return $this;
}
/**
* {@inheritdoc}
*/
public function getWriter(): WriterContract
{
return $this->writer;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision;
use JakubOnderka\PhpConsoleColor\ConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter as BaseHighlighter;
use NunoMaduro\Collision\Contracts\Highlighter as HighlighterContract;
/**
* This is an Collision Highlighter implementation.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class Highlighter extends BaseHighlighter implements HighlighterContract
{
/**
* Holds the theme.
*
* @var array
*/
protected $theme = [
BaseHighlighter::TOKEN_STRING => ['light_gray'],
BaseHighlighter::TOKEN_COMMENT => ['dark_gray', 'italic'],
BaseHighlighter::TOKEN_KEYWORD => ['yellow'],
BaseHighlighter::TOKEN_DEFAULT => ['default', 'bold'],
BaseHighlighter::TOKEN_HTML => ['blue', 'bold'],
BaseHighlighter::ACTUAL_LINE_MARK => ['bg_red', 'bold'],
BaseHighlighter::LINE_NUMBER => ['dark_gray', 'italic'],
];
/**
* Creates an instance of the Highlighter.
*
* @param \JakubOnderka\PhpConsoleColor\ConsoleColor|null $color
*/
public function __construct(ConsoleColor $color = null)
{
parent::__construct($color = $color ?: new ConsoleColor);
foreach ($this->theme as $name => $styles) {
$color->addTheme($name, $styles);
}
}
/**
* {@inheritdoc}
*/
public function highlight(string $content, int $line): string
{
return rtrim($this->getCodeSnippet($content, $line, 4, 4));
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision;
use Whoops\Run;
use Whoops\RunInterface;
use NunoMaduro\Collision\Contracts\Handler as HandlerContract;
use NunoMaduro\Collision\Contracts\Provider as ProviderContract;
/**
* This is an Collision Provider implementation.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class Provider implements ProviderContract
{
/**
* Holds an instance of the Run.
*
* @var \Whoops\RunInterface
*/
protected $run;
/**
* Holds an instance of the handler.
*
* @var \NunoMaduro\Collision\Contracts\Handler
*/
protected $handler;
/**
* Creates a new instance of the Provider.
*
* @param \Whoops\RunInterface|null $run
* @param \NunoMaduro\Collision\Contracts\Handler|null $handler
*/
public function __construct(RunInterface $run = null, HandlerContract $handler = null)
{
$this->run = $run ?: new Run;
$this->handler = $handler ?: new Handler;
}
/**
* {@inheritdoc}
*/
public function register(): ProviderContract
{
$this->run->pushHandler($this->handler)
->register();
return $this;
}
/**
* {@inheritdoc}
*/
public function getHandler(): HandlerContract
{
return $this->handler;
}
}

View File

@@ -0,0 +1,273 @@
<?php
/**
* This file is part of Collision.
*
* (c) Nuno Maduro <enunomaduro@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NunoMaduro\Collision;
use Whoops\Exception\Frame;
use Whoops\Exception\Inspector;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use NunoMaduro\Collision\Contracts\Writer as WriterContract;
use NunoMaduro\Collision\Contracts\Highlighter as HighlighterContract;
use NunoMaduro\Collision\Contracts\ArgumentFormatter as ArgumentFormatterContract;
/**
* This is an Collision Writer implementation.
*
* @author Nuno Maduro <enunomaduro@gmail.com>
*/
class Writer implements WriterContract
{
/**
* The number of frames if no verbosity is specified.
*/
const VERBOSITY_NORMAL_FRAMES = 1;
/**
* Holds an instance of the Output.
*
* @var \Symfony\Component\Console\Output\OutputInterface
*/
protected $output;
/**
* Holds an instance of the Argument Formatter.
*
* @var \NunoMaduro\Collision\Contracts\ArgumentFormatter
*/
protected $argumentFormatter;
/**
* Holds an instance of the Highlighter.
*
* @var \NunoMaduro\Collision\Contracts\Highlighter
*/
protected $highlighter;
/**
* Ignores traces where the file string matches one
* of the provided regex expressions.
*
* @var string[]
*/
protected $ignore = [];
/**
* Declares whether or not the trace should appear.
*
* @var bool
*/
protected $showTrace = true;
/**
* Declares whether or not the editor should appear.
*
* @var bool
*/
protected $showEditor = true;
/**
* Creates an instance of the writer.
*
* @param \Symfony\Component\Console\Output\OutputInterface|null $output
* @param \NunoMaduro\Collision\Contracts\ArgumentFormatter|null $argumentFormatter
* @param \NunoMaduro\Collision\Contracts\Highlighter|null $highlighter
*/
public function __construct(
OutputInterface $output = null,
ArgumentFormatterContract $argumentFormatter = null,
HighlighterContract $highlighter = null
) {
$this->output = $output ?: new ConsoleOutput;
$this->argumentFormatter = $argumentFormatter ?: new ArgumentFormatter;
$this->highlighter = $highlighter ?: new Highlighter;
}
/**
* {@inheritdoc}
*/
public function write(Inspector $inspector): void
{
$this->renderTitle($inspector);
$frames = $this->getFrames($inspector);
$editorFrame = array_shift($frames);
if ($this->showEditor && $editorFrame !== null) {
$this->renderEditor($editorFrame);
}
if ($this->showTrace && ! empty($frames)) {
$this->renderTrace($frames);
} else {
$this->output->writeln('');
}
}
/**
* {@inheritdoc}
*/
public function ignoreFilesIn(array $ignore): WriterContract
{
$this->ignore = $ignore;
return $this;
}
/**
* {@inheritdoc}
*/
public function showTrace(bool $show): WriterContract
{
$this->showTrace = $show;
return $this;
}
/**
* {@inheritdoc}
*/
public function showEditor(bool $show): WriterContract
{
$this->showEditor = $show;
return $this;
}
/**
* {@inheritdoc}
*/
public function setOutput(OutputInterface $output): WriterContract
{
$this->output = $output;
return $this;
}
/**
* {@inheritdoc}
*/
public function getOutput(): OutputInterface
{
return $this->output;
}
/**
* Returns pertinent frames.
*
* @param \Whoops\Exception\Inspector $inspector
*
* @return array
*/
protected function getFrames(Inspector $inspector): array
{
return $inspector->getFrames()
->filter(
function ($frame) {
foreach ($this->ignore as $ignore) {
if (preg_match($ignore, $frame->getFile())) {
return false;
}
}
return true;
}
)
->getArray();
}
/**
* Renders the title of the exception.
*
* @param \Whoops\Exception\Inspector $inspector
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
protected function renderTitle(Inspector $inspector): WriterContract
{
$exception = $inspector->getException();
$message = $exception->getMessage();
$class = $inspector->getExceptionName();
$this->render("<bg=red;options=bold> $class </> : <comment>$message</>");
return $this;
}
/**
* Renders the editor containing the code that was the
* origin of the exception.
*
* @param \Whoops\Exception\Frame $frame
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
protected function renderEditor(Frame $frame): WriterContract
{
$this->render('at <fg=green>'.$frame->getFile().'</>'.':<fg=green>'.$frame->getLine().'</>');
$content = $this->highlighter->highlight((string) $frame->getFileContents(), (int) $frame->getLine());
$this->output->writeln($content);
return $this;
}
/**
* Renders the trace of the exception.
*
* @param array $frames
*
* @return \NunoMaduro\Collision\Contracts\Writer
*/
protected function renderTrace(array $frames): WriterContract
{
$this->render('<comment>Exception trace:</comment>');
foreach ($frames as $i => $frame) {
if ($i > static::VERBOSITY_NORMAL_FRAMES && $this->output->getVerbosity(
) < OutputInterface::VERBOSITY_VERBOSE) {
$this->render('<info>Please use the argument <fg=red>-v</> to see more details.</info>');
break;
}
$file = $frame->getFile();
$line = $frame->getLine();
$class = empty($frame->getClass()) ? '' : $frame->getClass().'::';
$function = $frame->getFunction();
$args = $this->argumentFormatter->format($frame->getArgs());
$pos = str_pad($i + 1, 4, ' ');
$this->render("<comment><fg=cyan>$pos</>$class$function($args)</comment>");
$this->render(" <fg=green>$file</>:<fg=green>$line</>", false);
}
return $this;
}
/**
* Renders an message into the console.
*
* @param string $message
* @param bool $break
*
* @return $this
*/
protected function render(string $message, bool $break = true): WriterContract
{
if ($break) {
$this->output->writeln('');
}
$this->output->writeln(" $message");
return $this;
}
}