upgraded dependencies
This commit is contained in:
15
vendor/psy/psysh/.editorconfig
vendored
15
vendor/psy/psysh/.editorconfig
vendored
@@ -1,15 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
9
vendor/psy/psysh/.github/CONTRIBUTING.md
vendored
9
vendor/psy/psysh/.github/CONTRIBUTING.md
vendored
@@ -1,9 +0,0 @@
|
||||
## Code style
|
||||
|
||||
Please make your code look like the other code in the project.
|
||||
|
||||
PsySH follows [PSR-1](http://php-fig.org/psr/psr-1/) and [PSR-2](http://php-fig.org/psr/psr-2/). The easiest way to do make sure you're following the coding standard is to [install `php-cs-fixer`](https://github.com/friendsofphp/php-cs-fixer) and run `php-cs-fixer fix` before committing.
|
||||
|
||||
## Branching model
|
||||
|
||||
Please branch off and send pull requests to the `develop` branch.
|
9
vendor/psy/psysh/.gitignore
vendored
9
vendor/psy/psysh/.gitignore
vendored
@@ -1,9 +0,0 @@
|
||||
/build/
|
||||
/dist/
|
||||
/composer.lock
|
||||
/manual/
|
||||
/psysh
|
||||
/__pycache__
|
||||
/.php_cs.cache
|
||||
/vendor/
|
||||
/vendor-bin/*/vendor/
|
46
vendor/psy/psysh/.phan/config.php
vendored
46
vendor/psy/psysh/.phan/config.php
vendored
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This configuration will be read and overlaid on top of the
|
||||
* default configuration. Command line arguments will be applied
|
||||
* after this file is read.
|
||||
*/
|
||||
return [
|
||||
|
||||
// A list of directories that should be parsed for class and
|
||||
// method information. After excluding the directories
|
||||
// defined in exclude_analysis_directory_list, the remaining
|
||||
// files will be statically analyzed for errors.
|
||||
//
|
||||
// Thus, both first-party and third-party code being used by
|
||||
// your application should be included in this list.
|
||||
'directory_list' => [
|
||||
'src/',
|
||||
'vendor/dnoegel/php-xdg-base-dir/src/',
|
||||
'vendor/doctrine/instantiator/src/',
|
||||
'vendor/hoa/console/',
|
||||
'vendor/jakub-onderka/php-console-color/src/',
|
||||
'vendor/jakub-onderka/php-console-highlighter/src/',
|
||||
'vendor/nikic/php-parser/lib/',
|
||||
'vendor/phpdocumentor/reflection-docblock/',
|
||||
'vendor/symfony/console/',
|
||||
'vendor/symfony/filesystem/',
|
||||
'vendor/symfony/finder/',
|
||||
'vendor/symfony/var-dumper/',
|
||||
],
|
||||
|
||||
// A directory list that defines files that will be excluded
|
||||
// from static analysis, but whose class and method
|
||||
// information should be included.
|
||||
//
|
||||
// Generally, you'll want to include the directories for
|
||||
// third-party code (such as "vendor/") in this list.
|
||||
//
|
||||
// n.b.: If you'd like to parse but not analyze 3rd
|
||||
// party code, directories containing that code
|
||||
// should be added to both the `directory_list`
|
||||
// and `exclude_analysis_directory_list` arrays.
|
||||
"exclude_analysis_directory_list" => [
|
||||
'vendor/'
|
||||
],
|
||||
];
|
32
vendor/psy/psysh/.php_cs
vendored
32
vendor/psy/psysh/.php_cs
vendored
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->in(__DIR__)
|
||||
->name('.php_cs')
|
||||
->name('build-manual')
|
||||
->name('build-phar')
|
||||
->exclude('build-vendor');
|
||||
|
||||
$header = <<<EOF
|
||||
This file is part of Psy Shell.
|
||||
|
||||
(c) 2012-2018 Justin Hileman
|
||||
|
||||
For the full copyright and license information, please view the LICENSE
|
||||
file that was distributed with this source code.
|
||||
EOF;
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRules(array(
|
||||
'@Symfony' => true,
|
||||
'array_syntax' => array('syntax' => 'short'),
|
||||
'binary_operator_spaces' => false,
|
||||
'concat_space' => array('spacing' => 'one'),
|
||||
'header_comment' => array('header' => $header),
|
||||
'increment_style' => array('style' => 'post'),
|
||||
'method_argument_space' => array('keep_multiple_spaces_after_comma' => true),
|
||||
'ordered_imports' => true,
|
||||
'pre_increment' => false,
|
||||
'yoda_style' => false,
|
||||
))
|
||||
->setFinder($finder);
|
29
vendor/psy/psysh/.styleci.yml
vendored
29
vendor/psy/psysh/.styleci.yml
vendored
@@ -1,29 +0,0 @@
|
||||
preset: symfony
|
||||
|
||||
enabled:
|
||||
- align_double_arrow
|
||||
- concat_with_spaces
|
||||
- short_array_syntax
|
||||
- ordered_use
|
||||
- strict
|
||||
|
||||
disabled:
|
||||
- blank_line_before_break
|
||||
- blank_line_before_continue
|
||||
- blank_line_before_throw
|
||||
- blank_line_before_try
|
||||
- concat_without_spaces
|
||||
- method_argument_space
|
||||
- pre_increment
|
||||
- unalign_double_arrow
|
||||
- unalign_equals
|
||||
- yoda_style
|
||||
- property_separation
|
||||
- const_separation
|
||||
|
||||
finder:
|
||||
name:
|
||||
- "*.php"
|
||||
- ".php_cs"
|
||||
- "build-manual"
|
||||
- "build-phar"
|
47
vendor/psy/psysh/.travis.yml
vendored
47
vendor/psy/psysh/.travis.yml
vendored
@@ -1,47 +0,0 @@
|
||||
language: php
|
||||
|
||||
sudo: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.4
|
||||
dist: trusty
|
||||
- php: 5.4
|
||||
env: 'COMPOSER_FLAGS="--prefer-lowest --prefer-stable"'
|
||||
dist: trusty
|
||||
- php: 5.5
|
||||
dist: trusty
|
||||
- php: 5.6
|
||||
- php: 7.0
|
||||
- php: 7.1
|
||||
- php: 7.2
|
||||
- php: hhvm
|
||||
dist: trusty
|
||||
allow_failures:
|
||||
- php: 5.4
|
||||
env: 'COMPOSER_FLAGS="--prefer-lowest --prefer-stable"'
|
||||
- php: hhvm
|
||||
fast_finish: true
|
||||
|
||||
install: travis_retry composer update --no-interaction $COMPOSER_FLAGS
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit --verbose --coverage-clover=coverage.xml
|
||||
- '[[ $TRAVIS_PHP_VERSION = 7.2* ]] && make build -j 4 || true'
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
before_deploy: make dist -j 4
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: LL8koDM1xDqzF9t0URHvmMPyWjojyd4PeZ7IW7XYgyvD6n1H6GYrVAeKCh5wfUKFbwHoa9s5AAn6pLzra00bODVkPTmUH+FSMWz9JKLw9ODAn8HvN7C+IooxmeClGHFZc0TfHfya8/D1E9C1iXtGGEoE/GqtaYq/z0C1DLpO0OU=
|
||||
file_glob: true
|
||||
file: dist/psysh-*.tar.gz
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
repo: bobthecow/psysh
|
||||
condition: $TRAVIS_PHP_VERSION = 7.2*
|
2
vendor/psy/psysh/LICENSE
vendored
2
vendor/psy/psysh/LICENSE
vendored
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2018 Justin Hileman
|
||||
Copyright (c) 2012-2022 Justin Hileman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
95
vendor/psy/psysh/Makefile
vendored
95
vendor/psy/psysh/Makefile
vendored
@@ -1,95 +0,0 @@
|
||||
PSYSH_SRC = bin src box.json.dist composer.json build/stub
|
||||
PSYSH_SRC_FILES = $(shell find src -type f -name "*.php")
|
||||
VERSION = $(shell git describe --tag --always --dirty=-dev)
|
||||
|
||||
COMPOSER_OPTS = --no-interaction --no-progress --verbose
|
||||
COMPOSER_REQUIRE_OPTS = $(COMPOSER_OPTS) --no-update
|
||||
COMPOSER_UPDATE_OPTS = $(COMPOSER_OPTS) --prefer-stable --no-dev --classmap-authoritative --prefer-dist
|
||||
|
||||
|
||||
# Commands
|
||||
|
||||
.PHONY: help clean build dist
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
help:
|
||||
@echo "\033[33mUsage:\033[0m\n make TARGET\n\n\033[33mTargets:\033[0m"
|
||||
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[32m%-7s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
clean: ## Clean all created artifacts
|
||||
rm -rf build/*
|
||||
rm -rf dist/*
|
||||
rm -rf vendor-bin/*/vendor/
|
||||
|
||||
build: ## Compile PHARs
|
||||
build: build/psysh/psysh build/psysh-compat/psysh build/psysh-php54/psysh build/psysh-php54-compat/psysh
|
||||
|
||||
dist: ## Build tarballs for distribution
|
||||
dist: dist/psysh-$(VERSION).tar.gz dist/psysh-$(VERSION)-compat.tar.gz dist/psysh-$(VERSION)-php54.tar.gz dist/psysh-$(VERSION)-php54-compat.tar.gz
|
||||
|
||||
|
||||
# All the composer stuffs
|
||||
|
||||
composer.lock: composer.json
|
||||
composer install
|
||||
touch $@
|
||||
|
||||
vendor/autoload.php: composer.lock
|
||||
composer install
|
||||
touch $@
|
||||
|
||||
vendor/bin/box: vendor/autoload.php
|
||||
composer bin box install
|
||||
touch $@
|
||||
|
||||
|
||||
# Lots of PHARs
|
||||
|
||||
build/stub: bin/build-stub bin/psysh LICENSE
|
||||
bin/build-stub
|
||||
|
||||
build/psysh: $(PSYSH_SRC) $(PSYSH_SRC_FILES)
|
||||
rm -rf $@ || true
|
||||
mkdir $@
|
||||
cp -R $(PSYSH_SRC) $@/
|
||||
composer config --working-dir $@ platform.php 7.0
|
||||
composer require --working-dir $@ $(COMPOSER_REQUIRE_OPTS) php:'>=7.0.0'
|
||||
composer update --working-dir $@ $(COMPOSER_UPDATE_OPTS)
|
||||
|
||||
build/psysh-compat: $(PSYSH_SRC) $(PSYSH_SRC_FILES)
|
||||
rm -rf $@ || true
|
||||
mkdir $@
|
||||
cp -R $(PSYSH_SRC) $@/
|
||||
composer config --working-dir $@ platform.php 7.0
|
||||
composer require --working-dir $@ $(COMPOSER_REQUIRE_OPTS) php:'>=7.0.0'
|
||||
composer require --working-dir $@ $(COMPOSER_REQUIRE_OPTS) symfony/polyfill-iconv symfony/polyfill-mbstring hoa/console
|
||||
composer update --working-dir $@ $(COMPOSER_UPDATE_OPTS)
|
||||
|
||||
build/psysh-php54: $(PSYSH_SRC) $(PSYSH_SRC_FILES)
|
||||
rm -rf $@ || true
|
||||
mkdir $@
|
||||
cp -R $(PSYSH_SRC) $@/
|
||||
composer config --working-dir $@ platform.php 5.4
|
||||
composer update --working-dir $@ $(COMPOSER_UPDATE_OPTS)
|
||||
|
||||
build/psysh-php54-compat: $(PSYSH_SRC) $(PSYSH_SRC_FILES)
|
||||
rm -rf $@ || true
|
||||
mkdir $@
|
||||
cp -R $(PSYSH_SRC) $@/
|
||||
composer config --working-dir $@ platform.php 5.4
|
||||
composer require --working-dir $@ $(COMPOSER_REQUIRE_OPTS) symfony/polyfill-iconv symfony/polyfill-mbstring hoa/console:^2.15
|
||||
composer update --working-dir $@ $(COMPOSER_UPDATE_OPTS)
|
||||
|
||||
build/%/psysh: vendor/bin/box build/%
|
||||
vendor/bin/box compile --working-dir $(dir $@)
|
||||
|
||||
|
||||
# Dist packages
|
||||
|
||||
dist/psysh-$(VERSION).tar.gz: build/psysh/psysh
|
||||
@mkdir -p $(@D)
|
||||
tar -C $(dir $<) -czf $@ $(notdir $<)
|
||||
|
||||
dist/psysh-$(VERSION)-%.tar.gz: build/psysh-%/psysh
|
||||
@mkdir -p $(@D)
|
||||
tar -C $(dir $<) -czf $@ $(notdir $<)
|
4
vendor/psy/psysh/README.md
vendored
4
vendor/psy/psysh/README.md
vendored
@@ -7,7 +7,7 @@ PsySH is a runtime developer console, interactive debugger and [REPL](https://en
|
||||
[](https://packagist.org/packages/psy/psysh)
|
||||
[](http://psysh.org)
|
||||
|
||||
[](http://travis-ci.org/bobthecow/psysh)
|
||||
[](https://github.com/bobthecow/psysh/actions?query=branch:main)
|
||||
[](https://styleci.io/repos/4549925)
|
||||
|
||||
|
||||
@@ -24,11 +24,13 @@ PsySH is a runtime developer console, interactive debugger and [REPL](https://en
|
||||
* [⏳ Managing history](https://github.com/bobthecow/psysh/wiki/History)
|
||||
* [💲 System shell integration](https://github.com/bobthecow/psysh/wiki/Shell-integration)
|
||||
* [🎥 Tutorials & guides](https://github.com/bobthecow/psysh/wiki/Tutorials)
|
||||
* [🐛 Troubleshooting](https://github.com/bobthecow/psysh/wiki/Troubleshooting)
|
||||
|
||||
### [📢 Commands](https://github.com/bobthecow/psysh/wiki/Commands)
|
||||
|
||||
### [🛠 Configuration](https://github.com/bobthecow/psysh/wiki/Configuration)
|
||||
* [🎛 Config options](https://github.com/bobthecow/psysh/wiki/Config-options)
|
||||
* [🎨 Themes](https://github.com/bobthecow/psysh/wiki/Themes)
|
||||
* [📄 Sample config file](https://github.com/bobthecow/psysh/wiki/Sample-config)
|
||||
|
||||
### [🔌 Integrations](https://github.com/bobthecow/psysh/wiki/Integrations)
|
||||
|
22
vendor/psy/psysh/bin/build-stub
vendored
22
vendor/psy/psysh/bin/build-stub
vendored
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
$license = file_get_contents(dirname(__DIR__) . '/LICENSE');
|
||||
$license = str_replace('The MIT License (MIT)', '', $license);
|
||||
$license = str_replace("\n", "\n * ", trim($license));
|
||||
|
||||
$autoload = <<<'EOS'
|
||||
Phar::mapPhar('psysh.phar');
|
||||
require 'phar://psysh.phar/.box/check_requirements.php';
|
||||
require 'phar://psysh.phar/vendor/autoload.php';
|
||||
EOS;
|
||||
|
||||
$content = file_get_contents(dirname(__DIR__) . '/bin/psysh');
|
||||
$content = preg_replace('{/\* <<<.*?>>> \*/}sm', $autoload, $content);
|
||||
$content = preg_replace('/\\(c\\) .*?with this source code./sm', $license, $content);
|
||||
|
||||
$content .= '__HALT_COMPILER();';
|
||||
|
||||
@mkdir(dirname(__DIR__) . '/build');
|
||||
|
||||
file_put_contents(dirname(__DIR__) . '/build/stub', $content);
|
42
vendor/psy/psysh/bin/psysh
vendored
42
vendor/psy/psysh/bin/psysh
vendored
@@ -4,7 +4,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2017 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -20,7 +20,7 @@ call_user_func(function () {
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--cwd') {
|
||||
if ($i >= count($argv) - 1) {
|
||||
echo 'Missing --cwd argument.' . PHP_EOL;
|
||||
fwrite(STDERR, 'Missing --cwd argument.' . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
$cwd = $argv[$i + 1];
|
||||
@@ -43,14 +43,21 @@ call_user_func(function () {
|
||||
$chunks = explode('/', $cwd);
|
||||
while (!empty($chunks)) {
|
||||
$path = implode('/', $chunks);
|
||||
$prettyPath = $path;
|
||||
if (isset($_SERVER['HOME']) && $_SERVER['HOME']) {
|
||||
$prettyPath = preg_replace('/^' . preg_quote($_SERVER['HOME'], '/') . '/', '~', $path);
|
||||
}
|
||||
|
||||
// Find composer.json
|
||||
if (is_file($path . '/composer.json')) {
|
||||
if ($cfg = json_decode(file_get_contents($path . '/composer.json'), true)) {
|
||||
if (isset($cfg['name']) && $cfg['name'] === 'psy/psysh') {
|
||||
// We're inside the psysh project. Let's use the local
|
||||
// Composer autoload.
|
||||
// We're inside the psysh project. Let's use the local Composer autoload.
|
||||
if (is_file($path . '/vendor/autoload.php')) {
|
||||
if (realpath($path) !== realpath(__DIR__ . '/..')) {
|
||||
fwrite(STDERR, 'Using local PsySH version at ' . $prettyPath . PHP_EOL);
|
||||
}
|
||||
|
||||
require $path . '/vendor/autoload.php';
|
||||
}
|
||||
|
||||
@@ -64,9 +71,12 @@ call_user_func(function () {
|
||||
if ($cfg = json_decode(file_get_contents($path . '/composer.lock'), true)) {
|
||||
foreach (array_merge($cfg['packages'], $cfg['packages-dev']) as $pkg) {
|
||||
if (isset($pkg['name']) && $pkg['name'] === 'psy/psysh') {
|
||||
// We're inside a project which requires psysh. We'll
|
||||
// use the local Composer autoload.
|
||||
// We're inside a project which requires psysh. We'll use the local Composer autoload.
|
||||
if (is_file($path . '/vendor/autoload.php')) {
|
||||
if (realpath($path . '/vendor') !== realpath(__DIR__ . '/../../..')) {
|
||||
fwrite(STDERR, 'Using local PsySH version at ' . $prettyPath . PHP_EOL);
|
||||
}
|
||||
|
||||
require $path . '/vendor/autoload.php';
|
||||
}
|
||||
|
||||
@@ -89,8 +99,8 @@ if (!class_exists('Psy\Shell')) {
|
||||
} elseif (is_file(__DIR__ . '/../../../autoload.php')) {
|
||||
require __DIR__ . '/../../../autoload.php';
|
||||
} else {
|
||||
echo 'PsySH dependencies not found, be sure to run `composer install`.' . PHP_EOL;
|
||||
echo 'See https://getcomposer.org to get Composer.' . PHP_EOL;
|
||||
fwrite(STDERR, 'PsySH dependencies not found, be sure to run `composer install`.' . PHP_EOL);
|
||||
fwrite(STDERR, 'See https://getcomposer.org to get Composer.' . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
/* >>> */
|
||||
@@ -99,14 +109,14 @@ if (!class_exists('Psy\Shell')) {
|
||||
// If the psysh binary was included directly, assume they just wanted an
|
||||
// autoloader and bail early.
|
||||
//
|
||||
// Keep this PHP 5.3 code around for a while in case someone is using a globally
|
||||
// installed psysh as a bin launcher for older local versions.
|
||||
// Keep this PHP 5.3 and 5.4 code around for a while in case someone is using a
|
||||
// globally installed psysh as a bin launcher for older local versions.
|
||||
if (version_compare(PHP_VERSION, '5.3.6', '<')) {
|
||||
$trace = debug_backtrace();
|
||||
} elseif (version_compare(PHP_VERSION, '5.4.0', '<')) {
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
} else {
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||
}
|
||||
|
||||
if (Psy\Shell::isIncluded($trace)) {
|
||||
@@ -120,17 +130,17 @@ unset($trace);
|
||||
|
||||
// If the local version is too old, we can't do this
|
||||
if (!function_exists('Psy\bin')) {
|
||||
$argv = $_SERVER['argv'];
|
||||
$argv = isset($_SERVER['argv']) ? $_SERVER['argv'] : array();
|
||||
$first = array_shift($argv);
|
||||
if (preg_match('/php(\.exe)?$/', $first)) {
|
||||
array_shift($argv);
|
||||
}
|
||||
array_unshift($argv, 'vendor/bin/psysh');
|
||||
|
||||
echo 'A local PsySH dependency was found, but it cannot be loaded. Please update to' . PHP_EOL;
|
||||
echo 'the latest version, or run the local copy directly, e.g.:' . PHP_EOL;
|
||||
echo PHP_EOL;
|
||||
echo ' ' . implode(' ', $argv) . PHP_EOL;
|
||||
fwrite(STDERR, 'A local PsySH dependency was found, but it cannot be loaded. Please update to' . PHP_EOL);
|
||||
fwrite(STDERR, 'the latest version, or run the local copy directly, e.g.:' . PHP_EOL);
|
||||
fwrite(STDERR, PHP_EOL);
|
||||
fwrite(STDERR, ' ' . implode(' ', $argv) . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
12
vendor/psy/psysh/box.json.dist
vendored
12
vendor/psy/psysh/box.json.dist
vendored
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"stub": "stub",
|
||||
"output": "psysh",
|
||||
"compactors": [
|
||||
"KevinGH\\Box\\Compactor\\Php"
|
||||
],
|
||||
"blacklist": [
|
||||
"grammar",
|
||||
"test_old",
|
||||
"Documentation"
|
||||
]
|
||||
}
|
25
vendor/psy/psysh/composer.json
vendored
25
vendor/psy/psysh/composer.json
vendored
@@ -13,26 +13,21 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"php": "^8.0 || ^7.0.8",
|
||||
"ext-json": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0|~5.0",
|
||||
"symfony/var-dumper": "~2.7|~3.0|~4.0|~5.0",
|
||||
"nikic/php-parser": "~1.3|~2.0|~3.0|~4.0",
|
||||
"dnoegel/php-xdg-base-dir": "0.1.*",
|
||||
"jakub-onderka/php-console-highlighter": "0.3.*|0.4.*"
|
||||
"symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.4",
|
||||
"symfony/var-dumper": "^6.0 || ^5.0 || ^4.0 || ^3.4",
|
||||
"nikic/php-parser": "^4.0 || ^3.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0",
|
||||
"hoa/console": "~2.15|~3.16",
|
||||
"bamarni/composer-bin-plugin": "^1.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
|
||||
"ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.",
|
||||
"ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.",
|
||||
"ext-pdo-sqlite": "The doc command requires SQLite to work.",
|
||||
"hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit."
|
||||
"ext-pdo-sqlite": "The doc command requires SQLite to work."
|
||||
},
|
||||
"autoload": {
|
||||
"files": ["src/functions.php"],
|
||||
@@ -46,9 +41,17 @@
|
||||
}
|
||||
},
|
||||
"bin": ["bin/psysh"],
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"bamarni/composer-bin-plugin": true
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-develop": "0.9.x-dev"
|
||||
"dev-main": "0.11.x-dev"
|
||||
}
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4"
|
||||
}
|
||||
}
|
||||
|
12
vendor/psy/psysh/phpunit.xml.dist
vendored
12
vendor/psy/psysh/phpunit.xml.dist
vendored
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false" colors="true" bootstrap="vendor/autoload.php">
|
||||
<testsuite name="PsySH">
|
||||
<directory suffix="Test.php">./test</directory>
|
||||
</testsuite>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">./src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
124
vendor/psy/psysh/src/CodeCleaner.php
vendored
124
vendor/psy/psysh/src/CodeCleaner.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -18,24 +18,26 @@ use Psy\CodeCleaner\AbstractClassPass;
|
||||
use Psy\CodeCleaner\AssignThisVariablePass;
|
||||
use Psy\CodeCleaner\CalledClassPass;
|
||||
use Psy\CodeCleaner\CallTimePassByReferencePass;
|
||||
use Psy\CodeCleaner\EmptyArrayDimFetchPass;
|
||||
use Psy\CodeCleaner\ExitPass;
|
||||
use Psy\CodeCleaner\FinalClassPass;
|
||||
use Psy\CodeCleaner\FunctionContextPass;
|
||||
use Psy\CodeCleaner\FunctionReturnInWriteContextPass;
|
||||
use Psy\CodeCleaner\ImplicitReturnPass;
|
||||
use Psy\CodeCleaner\InstanceOfPass;
|
||||
use Psy\CodeCleaner\IssetPass;
|
||||
use Psy\CodeCleaner\LabelContextPass;
|
||||
use Psy\CodeCleaner\LeavePsyshAlonePass;
|
||||
use Psy\CodeCleaner\LegacyEmptyPass;
|
||||
use Psy\CodeCleaner\ListPass;
|
||||
use Psy\CodeCleaner\LoopContextPass;
|
||||
use Psy\CodeCleaner\MagicConstantsPass;
|
||||
use Psy\CodeCleaner\NamespacePass;
|
||||
use Psy\CodeCleaner\PassableByReferencePass;
|
||||
use Psy\CodeCleaner\RequirePass;
|
||||
use Psy\CodeCleaner\ReturnTypePass;
|
||||
use Psy\CodeCleaner\StrictTypesPass;
|
||||
use Psy\CodeCleaner\UseStatementPass;
|
||||
use Psy\CodeCleaner\ValidClassNamePass;
|
||||
use Psy\CodeCleaner\ValidConstantPass;
|
||||
use Psy\CodeCleaner\ValidConstructorPass;
|
||||
use Psy\CodeCleaner\ValidFunctionNamePass;
|
||||
use Psy\Exception\ParseErrorException;
|
||||
@@ -46,6 +48,7 @@ use Psy\Exception\ParseErrorException;
|
||||
*/
|
||||
class CodeCleaner
|
||||
{
|
||||
private $yolo = false;
|
||||
private $parser;
|
||||
private $printer;
|
||||
private $traverser;
|
||||
@@ -54,19 +57,22 @@ class CodeCleaner
|
||||
/**
|
||||
* CodeCleaner constructor.
|
||||
*
|
||||
* @param Parser $parser A PhpParser Parser instance. One will be created if not explicitly supplied
|
||||
* @param Printer $printer A PhpParser Printer instance. One will be created if not explicitly supplied
|
||||
* @param NodeTraverser $traverser A PhpParser NodeTraverser instance. One will be created if not explicitly supplied
|
||||
* @param Parser|null $parser A PhpParser Parser instance. One will be created if not explicitly supplied
|
||||
* @param Printer|null $printer A PhpParser Printer instance. One will be created if not explicitly supplied
|
||||
* @param NodeTraverser|null $traverser A PhpParser NodeTraverser instance. One will be created if not explicitly supplied
|
||||
* @param bool $yolo run without input validation
|
||||
*/
|
||||
public function __construct(Parser $parser = null, Printer $printer = null, NodeTraverser $traverser = null)
|
||||
public function __construct(Parser $parser = null, Printer $printer = null, NodeTraverser $traverser = null, bool $yolo = false)
|
||||
{
|
||||
$this->yolo = $yolo;
|
||||
|
||||
if ($parser === null) {
|
||||
$parserFactory = new ParserFactory();
|
||||
$parser = $parserFactory->createParser();
|
||||
$parser = $parserFactory->createParser();
|
||||
}
|
||||
|
||||
$this->parser = $parser;
|
||||
$this->printer = $printer ?: new Printer();
|
||||
$this->parser = $parser;
|
||||
$this->printer = $printer ?: new Printer();
|
||||
$this->traverser = $traverser ?: new NodeTraverser();
|
||||
|
||||
foreach ($this->getDefaultPasses() as $pass) {
|
||||
@@ -74,15 +80,29 @@ class CodeCleaner
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this CodeCleaner is in YOLO mode.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function yolo(): bool
|
||||
{
|
||||
return $this->yolo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default CodeCleaner passes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getDefaultPasses()
|
||||
private function getDefaultPasses(): array
|
||||
{
|
||||
if ($this->yolo) {
|
||||
return $this->getYoloPasses();
|
||||
}
|
||||
|
||||
$useStatementPass = new UseStatementPass();
|
||||
$namespacePass = new NamespacePass($this);
|
||||
$namespacePass = new NamespacePass($this);
|
||||
|
||||
// Try to add implicit `use` statements and an implicit namespace,
|
||||
// based on the file in which the `debug` call was made.
|
||||
@@ -98,11 +118,14 @@ class CodeCleaner
|
||||
new FunctionContextPass(),
|
||||
new FunctionReturnInWriteContextPass(),
|
||||
new InstanceOfPass(),
|
||||
new IssetPass(),
|
||||
new LabelContextPass(),
|
||||
new LeavePsyshAlonePass(),
|
||||
new LegacyEmptyPass(),
|
||||
new ListPass(),
|
||||
new LoopContextPass(),
|
||||
new PassableByReferencePass(),
|
||||
new ReturnTypePass(),
|
||||
new EmptyArrayDimFetchPass(),
|
||||
new ValidConstructorPass(),
|
||||
|
||||
// Rewriting shenanigans
|
||||
@@ -116,11 +139,40 @@ class CodeCleaner
|
||||
|
||||
// Namespace-aware validation (which depends on aforementioned shenanigans)
|
||||
new ValidClassNamePass(),
|
||||
new ValidConstantPass(),
|
||||
new ValidFunctionNamePass(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of code cleaner passes that don't try to do any validation, and
|
||||
* only do minimal rewriting to make things work inside the REPL.
|
||||
*
|
||||
* This list should stay in sync with the "rewriting shenanigans" in
|
||||
* getDefaultPasses above.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getYoloPasses(): array
|
||||
{
|
||||
$useStatementPass = new UseStatementPass();
|
||||
$namespacePass = new NamespacePass($this);
|
||||
|
||||
// Try to add implicit `use` statements and an implicit namespace,
|
||||
// based on the file in which the `debug` call was made.
|
||||
$this->addImplicitDebugContext([$useStatementPass, $namespacePass]);
|
||||
|
||||
return [
|
||||
new LeavePsyshAlonePass(),
|
||||
$useStatementPass, // must run before the namespace pass
|
||||
new ExitPass(),
|
||||
new ImplicitReturnPass(),
|
||||
new MagicConstantsPass(),
|
||||
$namespacePass, // must run after the implicit return pass
|
||||
new RequirePass(),
|
||||
new StrictTypesPass(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* "Warm up" code cleaner passes when we're coming from a debug call.
|
||||
*
|
||||
@@ -157,8 +209,6 @@ class CodeCleaner
|
||||
$traverser->traverse($stmts);
|
||||
} catch (\Throwable $e) {
|
||||
// Don't care.
|
||||
} catch (\Exception $e) {
|
||||
// Still don't care.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +219,7 @@ class CodeCleaner
|
||||
*/
|
||||
private static function getDebugFile()
|
||||
{
|
||||
$trace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
|
||||
foreach (\array_reverse($trace) as $stackFrame) {
|
||||
if (!self::isDebugCall($stackFrame)) {
|
||||
@@ -193,13 +243,13 @@ class CodeCleaner
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function isDebugCall(array $stackFrame)
|
||||
private static function isDebugCall(array $stackFrame): bool
|
||||
{
|
||||
$class = isset($stackFrame['class']) ? $stackFrame['class'] : null;
|
||||
$class = isset($stackFrame['class']) ? $stackFrame['class'] : null;
|
||||
$function = isset($stackFrame['function']) ? $stackFrame['function'] : null;
|
||||
|
||||
return ($class === null && $function === 'Psy\debug') ||
|
||||
($class === 'Psy\Shell' && $function === 'debug');
|
||||
return ($class === null && $function === 'Psy\\debug') ||
|
||||
($class === Shell::class && $function === 'debug');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,9 +262,9 @@ class CodeCleaner
|
||||
*
|
||||
* @return string|false Cleaned PHP code, False if the input is incomplete
|
||||
*/
|
||||
public function clean(array $codeLines, $requireSemicolons = false)
|
||||
public function clean(array $codeLines, bool $requireSemicolons = false)
|
||||
{
|
||||
$stmts = $this->parse('<?php ' . \implode(PHP_EOL, $codeLines) . PHP_EOL, $requireSemicolons);
|
||||
$stmts = $this->parse('<?php '.\implode(\PHP_EOL, $codeLines).\PHP_EOL, $requireSemicolons);
|
||||
if ($stmts === false) {
|
||||
return false;
|
||||
}
|
||||
@@ -223,13 +273,13 @@ class CodeCleaner
|
||||
$stmts = $this->traverser->traverse($stmts);
|
||||
|
||||
// Work around https://github.com/nikic/PHP-Parser/issues/399
|
||||
$oldLocale = \setlocale(LC_NUMERIC, 0);
|
||||
\setlocale(LC_NUMERIC, 'C');
|
||||
$oldLocale = \setlocale(\LC_NUMERIC, 0);
|
||||
\setlocale(\LC_NUMERIC, 'C');
|
||||
|
||||
$code = $this->printer->prettyPrint($stmts);
|
||||
|
||||
// Now put the locale back
|
||||
\setlocale(LC_NUMERIC, $oldLocale);
|
||||
\setlocale(\LC_NUMERIC, $oldLocale);
|
||||
|
||||
return $code;
|
||||
}
|
||||
@@ -237,9 +287,9 @@ class CodeCleaner
|
||||
/**
|
||||
* Set the current local namespace.
|
||||
*
|
||||
* @param null|array $namespace (default: null)
|
||||
* @param array|null $namespace (default: null)
|
||||
*
|
||||
* @return null|array
|
||||
* @return array|null
|
||||
*/
|
||||
public function setNamespace(array $namespace = null)
|
||||
{
|
||||
@@ -249,7 +299,7 @@ class CodeCleaner
|
||||
/**
|
||||
* Get the current local namespace.
|
||||
*
|
||||
* @return null|array
|
||||
* @return array|null
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
@@ -269,7 +319,7 @@ class CodeCleaner
|
||||
*
|
||||
* @return array|false A set of statements, or false if incomplete
|
||||
*/
|
||||
protected function parse($code, $requireSemicolons = false)
|
||||
protected function parse(string $code, bool $requireSemicolons = false)
|
||||
{
|
||||
try {
|
||||
return $this->parser->parse($code);
|
||||
@@ -296,14 +346,14 @@ class CodeCleaner
|
||||
|
||||
try {
|
||||
// Unexpected EOF, try again with an implicit semicolon
|
||||
return $this->parser->parse($code . ';');
|
||||
return $this->parser->parse($code.';');
|
||||
} catch (\PhpParser\Error $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function parseErrorIsEOF(\PhpParser\Error $e)
|
||||
private function parseErrorIsEOF(\PhpParser\Error $e): bool
|
||||
{
|
||||
$msg = $e->getRawMessage();
|
||||
|
||||
@@ -322,27 +372,27 @@ class CodeCleaner
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function parseErrorIsUnclosedString(\PhpParser\Error $e, $code)
|
||||
private function parseErrorIsUnclosedString(\PhpParser\Error $e, string $code): bool
|
||||
{
|
||||
if ($e->getRawMessage() !== 'Syntax error, unexpected T_ENCAPSED_AND_WHITESPACE') {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->parser->parse($code . "';");
|
||||
} catch (\Exception $e) {
|
||||
$this->parser->parse($code."';");
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function parseErrorIsUnterminatedComment(\PhpParser\Error $e, $code)
|
||||
private function parseErrorIsUnterminatedComment(\PhpParser\Error $e, $code): bool
|
||||
{
|
||||
return $e->getRawMessage() === 'Unterminated comment';
|
||||
}
|
||||
|
||||
private function parseErrorIsTrailingComma(\PhpParser\Error $e, $code)
|
||||
private function parseErrorIsTrailingComma(\PhpParser\Error $e, $code): bool
|
||||
{
|
||||
return ($e->getRawMessage() === 'A trailing comma is not allowed here') && (\substr(\rtrim($code), -1) === ',');
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -25,9 +25,11 @@ class AbstractClassPass extends CodeCleanerPass
|
||||
private $abstractMethods;
|
||||
|
||||
/**
|
||||
* @throws RuntimeException if the node is an abstract function with a body
|
||||
* @throws FatalErrorException if the node is an abstract function with a body
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -41,16 +43,18 @@ class AbstractClassPass extends CodeCleanerPass
|
||||
|
||||
if ($node->stmts !== null) {
|
||||
$msg = \sprintf('Abstract function %s cannot contain body', $name);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException if the node is a non-abstract class with abstract methods
|
||||
* @throws FatalErrorException if the node is a non-abstract class with abstract methods
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
@@ -64,7 +68,7 @@ class AbstractClassPass extends CodeCleanerPass
|
||||
($count === 1) ? '' : 's',
|
||||
\implode(', ', $this->abstractMethods)
|
||||
);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -26,14 +26,16 @@ class AssignThisVariablePass extends CodeCleanerPass
|
||||
/**
|
||||
* Validate that the user input does not assign the `$this` variable.
|
||||
*
|
||||
* @throws RuntimeException if the user assign the `$this` variable
|
||||
* @throws FatalErrorException if the user assign the `$this` variable
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Assign && $node->var instanceof Variable && $node->var->name === 'this') {
|
||||
throw new FatalErrorException('Cannot re-assign $this', 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException('Cannot re-assign $this', 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -15,6 +15,7 @@ use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\VariadicPlaceholder;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
@@ -31,9 +32,11 @@ class CallTimePassByReferencePass extends CodeCleanerPass
|
||||
/**
|
||||
* Validate of use call-time pass-by-reference.
|
||||
*
|
||||
* @throws RuntimeException if the user used call-time pass-by-reference
|
||||
* @throws FatalErrorException if the user used call-time pass-by-reference
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -42,8 +45,12 @@ class CallTimePassByReferencePass extends CodeCleanerPass
|
||||
}
|
||||
|
||||
foreach ($node->args as $arg) {
|
||||
if ($arg instanceof VariadicPlaceholder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($arg->byRef) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -17,6 +17,7 @@ use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\Node\VariadicPlaceholder;
|
||||
use Psy\Exception\ErrorException;
|
||||
|
||||
/**
|
||||
@@ -29,6 +30,8 @@ class CalledClassPass extends CodeCleanerPass
|
||||
|
||||
/**
|
||||
* @param array $nodes
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
@@ -39,6 +42,8 @@ class CalledClassPass extends CodeCleanerPass
|
||||
* @throws ErrorException if get_class or get_called_class is called without an object from outside a class
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -61,13 +66,15 @@ class CalledClassPass extends CodeCleanerPass
|
||||
$name = \strtolower($node->name);
|
||||
if (\in_array($name, ['get_class', 'get_called_class'])) {
|
||||
$msg = \sprintf('%s() called without object from outside a class', $name);
|
||||
throw new ErrorException($msg, 0, E_USER_WARNING, null, $node->getLine());
|
||||
throw new ErrorException($msg, 0, \E_USER_WARNING, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
@@ -76,8 +83,12 @@ class CalledClassPass extends CodeCleanerPass
|
||||
}
|
||||
}
|
||||
|
||||
private function isNull(Node $node)
|
||||
private function isNull(Node $node): bool
|
||||
{
|
||||
if ($node instanceof VariadicPlaceholder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $node->value instanceof ConstFetch && \strtolower($node->value->name) === 'null';
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
55
vendor/psy/psysh/src/CodeCleaner/EmptyArrayDimFetchPass.php
vendored
Normal file
55
vendor/psy/psysh/src/CodeCleaner/EmptyArrayDimFetchPass.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate empty brackets are only used for assignment.
|
||||
*/
|
||||
class EmptyArrayDimFetchPass extends CodeCleanerPass
|
||||
{
|
||||
const EXCEPTION_MESSAGE = 'Cannot use [] for reading';
|
||||
|
||||
private $theseOnesAreFine = [];
|
||||
|
||||
/**
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$this->theseOnesAreFine = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FatalErrorException if the user used empty empty array dim fetch outside of assignment
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Assign && $node->var instanceof ArrayDimFetch) {
|
||||
$this->theseOnesAreFine[] = $node->var;
|
||||
}
|
||||
|
||||
if ($node instanceof ArrayDimFetch && $node->dim === null) {
|
||||
if (!\in_array($node, $this->theseOnesAreFine)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -15,6 +15,7 @@ use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Exit_;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
|
||||
use Psy\Exception\BreakException;
|
||||
|
||||
class ExitPass extends CodeCleanerPass
|
||||
{
|
||||
@@ -22,11 +23,13 @@ class ExitPass extends CodeCleanerPass
|
||||
* Converts exit calls to BreakExceptions.
|
||||
*
|
||||
* @param \PhpParser\Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Exit_) {
|
||||
return new StaticCall(new FullyQualifiedName('Psy\Exception\BreakException'), 'exitShell');
|
||||
return new StaticCall(new FullyQualifiedName(BreakException::class), 'exitShell');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -24,6 +24,8 @@ class FinalClassPass extends CodeCleanerPass
|
||||
|
||||
/**
|
||||
* @param array $nodes
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
@@ -31,9 +33,11 @@ class FinalClassPass extends CodeCleanerPass
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException if the node is a class that extends a final class
|
||||
* @throws FatalErrorException if the node is a class that extends a final class
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -42,7 +46,7 @@ class FinalClassPass extends CodeCleanerPass
|
||||
$extends = (string) $node->extends;
|
||||
if ($this->isFinalClass($extends)) {
|
||||
$msg = \sprintf('Class %s may not inherit from final class (%s)', $node->name, $extends);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +61,7 @@ class FinalClassPass extends CodeCleanerPass
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isFinalClass($name)
|
||||
private function isFinalClass(string $name): bool
|
||||
{
|
||||
if (!\class_exists($name)) {
|
||||
return isset($this->finalClasses[\strtolower($name)]);
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -23,12 +23,17 @@ class FunctionContextPass extends CodeCleanerPass
|
||||
|
||||
/**
|
||||
* @param array $nodes
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$this->functionDepth = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof FunctionLike) {
|
||||
@@ -45,12 +50,14 @@ class FunctionContextPass extends CodeCleanerPass
|
||||
// It causes fatal error.
|
||||
if ($node instanceof Yield_) {
|
||||
$msg = 'The "yield" expression can only be used inside a function';
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PhpParser\Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -14,12 +14,12 @@ namespace Psy\CodeCleaner;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Empty_;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Isset_;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt\Unset_;
|
||||
use PhpParser\Node\VariadicPlaceholder;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
@@ -29,33 +29,31 @@ use Psy\Exception\FatalErrorException;
|
||||
*/
|
||||
class FunctionReturnInWriteContextPass extends CodeCleanerPass
|
||||
{
|
||||
const PHP55_MESSAGE = 'Cannot use isset() on the result of a function call (you can use "null !== func()" instead)';
|
||||
const ISSET_MESSAGE = 'Cannot use isset() on the result of an expression (you can use "null !== expression" instead)';
|
||||
const EXCEPTION_MESSAGE = "Can't use function return value in write context";
|
||||
|
||||
private $atLeastPhp55;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->atLeastPhp55 = \version_compare(PHP_VERSION, '5.5', '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the functions are used correctly.
|
||||
*
|
||||
* @throws FatalErrorException if a function is passed as an argument reference
|
||||
* @throws FatalErrorException if a function is used as an argument in the isset
|
||||
* @throws FatalErrorException if a function is used as an argument in the empty, only for PHP < 5.5
|
||||
* @throws FatalErrorException if a value is assigned to a function
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Array_ || $this->isCallNode($node)) {
|
||||
$items = $node instanceof Array_ ? $node->items : $node->args;
|
||||
foreach ($items as $item) {
|
||||
if ($item instanceof VariadicPlaceholder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($item && $item->byRef && $this->isCallNode($item->value)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
} elseif ($node instanceof Isset_ || $node instanceof Unset_) {
|
||||
@@ -64,17 +62,15 @@ class FunctionReturnInWriteContextPass extends CodeCleanerPass
|
||||
continue;
|
||||
}
|
||||
|
||||
$msg = ($node instanceof Isset_ && $this->atLeastPhp55) ? self::PHP55_MESSAGE : self::EXCEPTION_MESSAGE;
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
$msg = $node instanceof Isset_ ? self::ISSET_MESSAGE : self::EXCEPTION_MESSAGE;
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
} elseif ($node instanceof Empty_ && !$this->atLeastPhp55 && $this->isCallNode($node->expr)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine()); // @codeCoverageIgnore
|
||||
} elseif ($node instanceof Assign && $this->isCallNode($node->var)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
private function isCallNode(Node $node)
|
||||
private function isCallNode(Node $node): bool
|
||||
{
|
||||
return $node instanceof FuncCall || $node instanceof MethodCall || $node instanceof StaticCall;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -32,7 +32,7 @@ class ImplicitReturnPass extends CodeCleanerPass
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
public function beforeTraverse(array $nodes): array
|
||||
{
|
||||
return $this->addImplicitReturn($nodes);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ class ImplicitReturnPass extends CodeCleanerPass
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function addImplicitReturn(array $nodes)
|
||||
private function addImplicitReturn(array $nodes): array
|
||||
{
|
||||
// If nodes is empty, it can't have a return value.
|
||||
if (empty($nodes)) {
|
||||
@@ -118,7 +118,7 @@ class ImplicitReturnPass extends CodeCleanerPass
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function isNonExpressionStmt(Node $node)
|
||||
private static function isNonExpressionStmt(Node $node): bool
|
||||
{
|
||||
return $node instanceof Stmt &&
|
||||
!$node instanceof Expression &&
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -12,6 +12,9 @@
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\BinaryOp;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\Instanceof_;
|
||||
use PhpParser\Node\Scalar;
|
||||
@@ -27,21 +30,40 @@ class InstanceOfPass extends CodeCleanerPass
|
||||
{
|
||||
const EXCEPTION_MSG = 'instanceof expects an object instance, constant given';
|
||||
|
||||
private $atLeastPhp73;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->atLeastPhp73 = \version_compare(\PHP_VERSION, '7.3', '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the instanceof statement does not receive a scalar value or a non-class constant.
|
||||
*
|
||||
* @throws FatalErrorException if a scalar or a non-class constant is given
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
// Basically everything is allowed in PHP 7.3 :)
|
||||
if ($this->atLeastPhp73) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$node instanceof Instanceof_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (($node->expr instanceof Scalar && !$node->expr instanceof Encapsed) || $node->expr instanceof ConstFetch) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MSG, 0, E_ERROR, null, $node->getLine());
|
||||
if (($node->expr instanceof Scalar && !$node->expr instanceof Encapsed) ||
|
||||
$node->expr instanceof BinaryOp ||
|
||||
$node->expr instanceof Array_ ||
|
||||
$node->expr instanceof ConstFetch ||
|
||||
$node->expr instanceof ClassConstFetch
|
||||
) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MSG, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
49
vendor/psy/psysh/src/CodeCleaner/IssetPass.php
vendored
Normal file
49
vendor/psy/psysh/src/CodeCleaner/IssetPass.php
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Isset_;
|
||||
use PhpParser\Node\Expr\NullsafePropertyFetch;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Code cleaner pass to ensure we only allow variables, array fetch and property
|
||||
* fetch expressions in isset() calls.
|
||||
*/
|
||||
class IssetPass extends CodeCleanerPass
|
||||
{
|
||||
const EXCEPTION_MSG = 'Cannot use isset() on the result of an expression (you can use "null !== expression" instead)';
|
||||
|
||||
/**
|
||||
* @throws FatalErrorException
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if (!$node instanceof Isset_) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($node->vars as $var) {
|
||||
if (!$var instanceof Variable && !$var instanceof ArrayDimFetch && !$var instanceof PropertyFetch && !$var instanceof NullsafePropertyFetch) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MSG, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
101
vendor/psy/psysh/src/CodeCleaner/LabelContextPass.php
vendored
Normal file
101
vendor/psy/psysh/src/CodeCleaner/LabelContextPass.php
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Stmt\Goto_;
|
||||
use PhpParser\Node\Stmt\Label;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* CodeCleanerPass for label context.
|
||||
*
|
||||
* This class partially emulates the PHP label specification.
|
||||
* PsySH can not declare labels by sequentially executing lines with eval,
|
||||
* but since it is not a syntax error, no error is raised.
|
||||
* This class warns before invalid goto causes a fatal error.
|
||||
* Since this is a simple checker, it does not block real fatal error
|
||||
* with complex syntax. (ex. it does not parse inside function.)
|
||||
*
|
||||
* @see http://php.net/goto
|
||||
*/
|
||||
class LabelContextPass extends CodeCleanerPass
|
||||
{
|
||||
/** @var int */
|
||||
private $functionDepth;
|
||||
|
||||
/** @var array */
|
||||
private $labelDeclarations;
|
||||
/** @var array */
|
||||
private $labelGotos;
|
||||
|
||||
/**
|
||||
* @param array $nodes
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$this->functionDepth = 0;
|
||||
$this->labelDeclarations = [];
|
||||
$this->labelGotos = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof FunctionLike) {
|
||||
$this->functionDepth++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// node is inside function context
|
||||
if ($this->functionDepth !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof Goto_) {
|
||||
$this->labelGotos[\strtolower($node->name)] = $node->getLine();
|
||||
} elseif ($node instanceof Label) {
|
||||
$this->labelDeclarations[\strtolower($node->name)] = $node->getLine();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PhpParser\Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof FunctionLike) {
|
||||
$this->functionDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function afterTraverse(array $nodes)
|
||||
{
|
||||
foreach ($this->labelGotos as $name => $line) {
|
||||
if (!isset($this->labelDeclarations[$name])) {
|
||||
$msg = "'goto' to undefined label '{$name}'";
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -26,6 +26,8 @@ class LeavePsyshAlonePass extends CodeCleanerPass
|
||||
* @throws RuntimeException if the user is messing with $__psysh__
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
|
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Empty_;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Psy\Exception\ParseErrorException;
|
||||
|
||||
/**
|
||||
* Validate that the user did not call the language construct `empty()` on a
|
||||
* statement in PHP < 5.5.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class LegacyEmptyPass extends CodeCleanerPass
|
||||
{
|
||||
private $atLeastPhp55;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->atLeastPhp55 = \version_compare(PHP_VERSION, '5.5', '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate use of empty in PHP < 5.5.
|
||||
*
|
||||
* @throws ParseErrorException if the user used empty with anything but a variable
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($this->atLeastPhp55) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$node instanceof Empty_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$node->expr instanceof Variable) {
|
||||
$msg = \sprintf('syntax error, unexpected %s', $this->getUnexpectedThing($node->expr));
|
||||
|
||||
throw new ParseErrorException($msg, $node->expr->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
private function getUnexpectedThing(Node $node)
|
||||
{
|
||||
switch ($node->getType()) {
|
||||
case 'Scalar_String':
|
||||
case 'Scalar_LNumber':
|
||||
case 'Scalar_DNumber':
|
||||
return \json_encode($node->value);
|
||||
|
||||
case 'Expr_ConstFetch':
|
||||
return (string) $node->name;
|
||||
|
||||
default:
|
||||
return $node->getType();
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -33,7 +33,7 @@ class ListPass extends CodeCleanerPass
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->atLeastPhp71 = \version_compare(PHP_VERSION, '7.1', '>=');
|
||||
$this->atLeastPhp71 = \version_compare(\PHP_VERSION, '7.1', '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,6 +42,8 @@ class ListPass extends CodeCleanerPass
|
||||
* @throws ParseErrorException if the user used empty with anything but a variable
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -97,7 +99,7 @@ class ListPass extends CodeCleanerPass
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function isValidArrayItem(Expr $item)
|
||||
private static function isValidArrayItem(Expr $item): bool
|
||||
{
|
||||
$value = ($item instanceof ArrayItem) ? $item->value : $item;
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -32,6 +32,8 @@ class LoopContextPass extends CodeCleanerPass
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
@@ -45,6 +47,8 @@ class LoopContextPass extends CodeCleanerPass
|
||||
* @throws FatalErrorException if the node is a break or continue and has an argument less than 1
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -63,23 +67,23 @@ class LoopContextPass extends CodeCleanerPass
|
||||
|
||||
if ($this->loopDepth === 0) {
|
||||
$msg = \sprintf("'%s' not in the 'loop' or 'switch' context", $operator);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
|
||||
if ($node->num instanceof LNumber || $node->num instanceof DNumber) {
|
||||
$num = $node->num->value;
|
||||
if ($node->num instanceof DNumber || $num < 1) {
|
||||
$msg = \sprintf("'%s' operator accepts only positive numbers", $operator);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
|
||||
if ($num > $this->loopDepth) {
|
||||
$msg = \sprintf("Cannot '%s' %d levels", $operator, $num);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
} elseif ($node->num) {
|
||||
$msg = \sprintf("'%s' operator with non-constant operand is no longer supported", $operator);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -87,6 +91,8 @@ class LoopContextPass extends CodeCleanerPass
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -29,7 +29,7 @@ class MagicConstantsPass extends CodeCleanerPass
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return null|FuncCall|String_
|
||||
* @return FuncCall|String_|null
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -29,10 +29,12 @@ abstract class NamespaceAwarePass extends CodeCleanerPass
|
||||
* use afterTraverse or call parent::beforeTraverse() when overloading.
|
||||
*
|
||||
* Reset the namespace and the current scope before beginning analysis
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$this->namespace = [];
|
||||
$this->namespace = [];
|
||||
$this->currentScope = [];
|
||||
}
|
||||
|
||||
@@ -41,6 +43,8 @@ abstract class NamespaceAwarePass extends CodeCleanerPass
|
||||
* leaveNode or call parent::enterNode() when overloading
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -56,7 +60,7 @@ abstract class NamespaceAwarePass extends CodeCleanerPass
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFullyQualifiedName($name)
|
||||
protected function getFullyQualifiedName($name): string
|
||||
{
|
||||
if ($name instanceof FullyQualifiedName) {
|
||||
return \implode('\\', $name->parts);
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use Psy\CodeCleaner;
|
||||
@@ -46,6 +47,8 @@ class NamespacePass extends CodeCleanerPass
|
||||
* is encountered.
|
||||
*
|
||||
* @param array $nodes
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
@@ -78,7 +81,7 @@ class NamespacePass extends CodeCleanerPass
|
||||
* Remember the namespace and (re)set the namespace on the CodeCleaner as
|
||||
* well.
|
||||
*
|
||||
* @param null|Name $namespace
|
||||
* @param Name|null $namespace
|
||||
*/
|
||||
private function setNamespace($namespace)
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -26,10 +26,10 @@ class NoReturnValue
|
||||
/**
|
||||
* Get PhpParser AST expression for creating a new NoReturnValue.
|
||||
*
|
||||
* @return PhpParser\Node\Expr\New_
|
||||
* @return New_
|
||||
*/
|
||||
public static function create()
|
||||
public static function create(): New_
|
||||
{
|
||||
return new New_(new FullyQualifiedName('Psy\CodeCleaner\NoReturnValue'));
|
||||
return new New_(new FullyQualifiedName(self::class));
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -13,6 +13,8 @@ namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
@@ -32,6 +34,8 @@ class PassableByReferencePass extends CodeCleanerPass
|
||||
* @throws FatalErrorException if non-variables are passed by reference
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -59,15 +63,20 @@ class PassableByReferencePass extends CodeCleanerPass
|
||||
if (\array_key_exists($key, $node->args)) {
|
||||
$arg = $node->args[$key];
|
||||
if ($param->isPassedByReference() && !$this->isPassableByReference($arg)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function isPassableByReference(Node $arg)
|
||||
private function isPassableByReference(Node $arg): bool
|
||||
{
|
||||
// Unpacked arrays can be passed by reference
|
||||
if ($arg->value instanceof Array_) {
|
||||
return $arg->unpack;
|
||||
}
|
||||
|
||||
// FuncCall, MethodCall and StaticCall are all PHP _warnings_ not fatal errors, so we'll let
|
||||
// PHP handle those ones :)
|
||||
return $arg->value instanceof ClassConstFetch ||
|
||||
@@ -75,7 +84,8 @@ class PassableByReferencePass extends CodeCleanerPass
|
||||
$arg->value instanceof Variable ||
|
||||
$arg->value instanceof FuncCall ||
|
||||
$arg->value instanceof MethodCall ||
|
||||
$arg->value instanceof StaticCall;
|
||||
$arg->value instanceof StaticCall ||
|
||||
$arg->value instanceof ArrayDimFetch;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +112,7 @@ class PassableByReferencePass extends CodeCleanerPass
|
||||
} elseif (++$nonPassable > 2) {
|
||||
// There can be *at most* two non-passable-by-reference args in a row. This is about
|
||||
// as close as we can get to validating the arguments for this function :-/
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
52
vendor/psy/psysh/src/CodeCleaner/RequirePass.php
vendored
52
vendor/psy/psysh/src/CodeCleaner/RequirePass.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -19,7 +19,6 @@ use PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use Psy\Exception\ErrorException;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
use Psy\Shell;
|
||||
|
||||
/**
|
||||
* Add runtime validation for `require` and `require_once` calls.
|
||||
@@ -30,6 +29,8 @@ class RequirePass extends CodeCleanerPass
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $origNode)
|
||||
{
|
||||
@@ -49,7 +50,7 @@ class RequirePass extends CodeCleanerPass
|
||||
* $foo = require \Psy\CodeCleaner\RequirePass::resolve($bar)
|
||||
*/
|
||||
$node->expr = new StaticCall(
|
||||
new FullyQualifiedName('Psy\CodeCleaner\RequirePass'),
|
||||
new FullyQualifiedName(self::class),
|
||||
'resolve',
|
||||
[new Arg($origNode->expr), new Arg(new LNumber($origNode->getLine()))],
|
||||
$origNode->getAttributes()
|
||||
@@ -63,15 +64,18 @@ class RequirePass extends CodeCleanerPass
|
||||
*
|
||||
* If $file can be resolved, return $file. Otherwise throw a fatal error exception.
|
||||
*
|
||||
* If $file collides with a path in the currently running PsySH phar, it will be resolved
|
||||
* relative to the include path, to prevent PHP from grabbing the phar version of the file.
|
||||
*
|
||||
* @throws FatalErrorException when unable to resolve include path for $file
|
||||
* @throws ErrorException if $file is empty and E_WARNING is included in error_reporting level
|
||||
*
|
||||
* @param string $file
|
||||
* @param int $lineNumber Line number of the original require expression
|
||||
*
|
||||
* @return string Exactly the same as $file
|
||||
* @return string Exactly the same as $file, unless $file collides with a path in the currently running phar
|
||||
*/
|
||||
public static function resolve($file, $lineNumber = null)
|
||||
public static function resolve($file, $lineNumber = null): string
|
||||
{
|
||||
$file = (string) $file;
|
||||
|
||||
@@ -79,23 +83,51 @@ class RequirePass extends CodeCleanerPass
|
||||
// @todo Shell::handleError would be better here, because we could
|
||||
// fake the file and line number, but we can't call it statically.
|
||||
// So we're duplicating some of the logics here.
|
||||
if (E_WARNING & \error_reporting()) {
|
||||
ErrorException::throwException(E_WARNING, 'Filename cannot be empty', null, $lineNumber);
|
||||
if (\E_WARNING & \error_reporting()) {
|
||||
ErrorException::throwException(\E_WARNING, 'Filename cannot be empty', null, $lineNumber);
|
||||
}
|
||||
// @todo trigger an error as fallback? this is pretty ugly…
|
||||
// trigger_error('Filename cannot be empty', E_USER_WARNING);
|
||||
}
|
||||
|
||||
if ($file === '' || !\stream_resolve_include_path($file)) {
|
||||
$resolvedPath = \stream_resolve_include_path($file);
|
||||
if ($file === '' || !$resolvedPath) {
|
||||
$msg = \sprintf("Failed opening required '%s'", $file);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $lineNumber);
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $lineNumber);
|
||||
}
|
||||
|
||||
// Special case: if the path is not already relative or absolute, and it would resolve to
|
||||
// something inside the currently running phar (e.g. `vendor/autoload.php`), we'll resolve
|
||||
// it relative to the include path so PHP won't grab the phar version.
|
||||
//
|
||||
// Note that this only works if the phar has `psysh` in the path. We might want to lift this
|
||||
// restriction and special case paths that would collide with any running phar?
|
||||
if ($resolvedPath !== $file && $file[0] !== '.') {
|
||||
$runningPhar = \Phar::running();
|
||||
if (\strpos($runningPhar, 'psysh') !== false && \is_file($runningPhar.\DIRECTORY_SEPARATOR.$file)) {
|
||||
foreach (self::getIncludePath() as $prefix) {
|
||||
$resolvedPath = $prefix.\DIRECTORY_SEPARATOR.$file;
|
||||
if (\is_file($resolvedPath)) {
|
||||
return $resolvedPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function isRequireNode(Node $node)
|
||||
private function isRequireNode(Node $node): bool
|
||||
{
|
||||
return $node instanceof Include_ && \in_array($node->type, self::$requireTypes);
|
||||
}
|
||||
|
||||
private static function getIncludePath(): array
|
||||
{
|
||||
if (\PATH_SEPARATOR === ':') {
|
||||
return \preg_split('#:(?!//)#', \get_include_path());
|
||||
}
|
||||
|
||||
return \explode(\PATH_SEPARATOR, \get_include_path());
|
||||
}
|
||||
}
|
||||
|
127
vendor/psy/psysh/src/CodeCleaner/ReturnTypePass.php
vendored
Normal file
127
vendor/psy/psysh/src/CodeCleaner/ReturnTypePass.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\UnionType;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Add runtime validation for return types.
|
||||
*/
|
||||
class ReturnTypePass extends CodeCleanerPass
|
||||
{
|
||||
const MESSAGE = 'A function with return type must return a value';
|
||||
const NULLABLE_MESSAGE = 'A function with return type must return a value (did you mean "return null;" instead of "return;"?)';
|
||||
const VOID_MESSAGE = 'A void function must not return a value';
|
||||
const VOID_NULL_MESSAGE = 'A void function must not return a value (did you mean "return;" instead of "return null;"?)';
|
||||
const NULLABLE_VOID_MESSAGE = 'Void type cannot be nullable';
|
||||
|
||||
private $atLeastPhp71;
|
||||
private $returnTypeStack = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->atLeastPhp71 = \version_compare(\PHP_VERSION, '7.1', '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if (!$this->atLeastPhp71) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
if ($this->isFunctionNode($node)) {
|
||||
$this->returnTypeStack[] = $node->returnType;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($this->returnTypeStack) && $node instanceof Return_) {
|
||||
$expectedType = \end($this->returnTypeStack);
|
||||
if ($expectedType === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$msg = null;
|
||||
|
||||
if ($this->typeName($expectedType) === 'void') {
|
||||
// Void functions
|
||||
if ($expectedType instanceof NullableType) {
|
||||
$msg = self::NULLABLE_VOID_MESSAGE;
|
||||
} elseif ($node->expr instanceof ConstFetch && \strtolower($node->expr->name) === 'null') {
|
||||
$msg = self::VOID_NULL_MESSAGE;
|
||||
} elseif ($node->expr !== null) {
|
||||
$msg = self::VOID_MESSAGE;
|
||||
}
|
||||
} else {
|
||||
// Everything else
|
||||
if ($node->expr === null) {
|
||||
$msg = $expectedType instanceof NullableType ? self::NULLABLE_MESSAGE : self::MESSAGE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($msg !== null) {
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if (!$this->atLeastPhp71) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
if (!empty($this->returnTypeStack) && $this->isFunctionNode($node)) {
|
||||
\array_pop($this->returnTypeStack);
|
||||
}
|
||||
}
|
||||
|
||||
private function isFunctionNode(Node $node): bool
|
||||
{
|
||||
return $node instanceof Function_ || $node instanceof Closure;
|
||||
}
|
||||
|
||||
private function typeName(Node $node): string
|
||||
{
|
||||
if ($node instanceof UnionType) {
|
||||
return \implode('|', \array_map([$this, 'typeName'], $node->types));
|
||||
}
|
||||
|
||||
if ($node instanceof NullableType) {
|
||||
return \strtolower($node->type->name);
|
||||
}
|
||||
|
||||
if ($node instanceof Identifier) {
|
||||
return \strtolower($node->name);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Unable to find type name');
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use PhpParser\Node\Stmt\Declare_;
|
||||
@@ -32,12 +33,6 @@ class StrictTypesPass extends CodeCleanerPass
|
||||
const EXCEPTION_MESSAGE = 'strict_types declaration must have 0 or 1 as its value';
|
||||
|
||||
private $strictTypes = false;
|
||||
private $atLeastPhp7;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->atLeastPhp7 = \version_compare(PHP_VERSION, '7.0', '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a standalone strict types declaration, remember it for later.
|
||||
@@ -48,16 +43,14 @@ class StrictTypesPass extends CodeCleanerPass
|
||||
* @throws FatalErrorException if an invalid `strict_types` declaration is found
|
||||
*
|
||||
* @param array $nodes
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
if (!$this->atLeastPhp7) {
|
||||
return; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$prependStrictTypes = $this->strictTypes;
|
||||
|
||||
foreach ($nodes as $key => $node) {
|
||||
foreach ($nodes as $node) {
|
||||
if ($node instanceof Declare_) {
|
||||
foreach ($node->declares as $declare) {
|
||||
// For PHP Parser 4.x
|
||||
@@ -65,7 +58,7 @@ class StrictTypesPass extends CodeCleanerPass
|
||||
if ($declareKey === 'strict_types') {
|
||||
$value = $declare->value;
|
||||
if (!$value instanceof LNumber || ($value->value !== 0 && $value->value !== 1)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
|
||||
$this->strictTypes = $value->value === 1;
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -17,6 +17,7 @@ use PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use PhpParser\NodeTraverser;
|
||||
|
||||
/**
|
||||
@@ -31,8 +32,8 @@ use PhpParser\NodeTraverser;
|
||||
*/
|
||||
class UseStatementPass extends CodeCleanerPass
|
||||
{
|
||||
private $aliases = [];
|
||||
private $lastAliases = [];
|
||||
private $aliases = [];
|
||||
private $lastAliases = [];
|
||||
private $lastNamespace = null;
|
||||
|
||||
/**
|
||||
@@ -43,13 +44,15 @@ class UseStatementPass extends CodeCleanerPass
|
||||
* work like you'd expect.
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Namespace_) {
|
||||
// If this is the same namespace as last namespace, let's do ourselves
|
||||
// a favor and reload all the aliases...
|
||||
if (\strtolower($node->name) === \strtolower($this->lastNamespace)) {
|
||||
if (\strtolower($node->name ?: '') === \strtolower($this->lastNamespace ?: '')) {
|
||||
$this->aliases = $this->lastAliases;
|
||||
}
|
||||
}
|
||||
@@ -62,21 +65,23 @@ class UseStatementPass extends CodeCleanerPass
|
||||
* remembered aliases to the code.
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
// Store a reference to every "use" statement, because we'll need them in a bit.
|
||||
if ($node instanceof Use_) {
|
||||
// Store a reference to every "use" statement, because we'll need
|
||||
// them in a bit.
|
||||
foreach ($node->uses as $use) {
|
||||
$alias = $use->alias ?: \end($use->name->parts);
|
||||
$this->aliases[\strtolower($alias)] = $use->name;
|
||||
}
|
||||
|
||||
return NodeTraverser::REMOVE_NODE;
|
||||
} elseif ($node instanceof GroupUse) {
|
||||
// Expand every "use" statement in the group into a full, standalone
|
||||
// "use" and store 'em with the others.
|
||||
}
|
||||
|
||||
// Expand every "use" statement in the group into a full, standalone "use" and store 'em with the others.
|
||||
if ($node instanceof GroupUse) {
|
||||
foreach ($node->uses as $use) {
|
||||
$alias = $use->alias ?: \end($use->name->parts);
|
||||
$this->aliases[\strtolower($alias)] = Name::concat($node->prefix, $use->name, [
|
||||
@@ -86,23 +91,32 @@ class UseStatementPass extends CodeCleanerPass
|
||||
}
|
||||
|
||||
return NodeTraverser::REMOVE_NODE;
|
||||
} elseif ($node instanceof Namespace_) {
|
||||
// Start fresh, since we're done with this namespace.
|
||||
}
|
||||
|
||||
// Start fresh, since we're done with this namespace.
|
||||
if ($node instanceof Namespace_) {
|
||||
$this->lastNamespace = $node->name;
|
||||
$this->lastAliases = $this->aliases;
|
||||
$this->aliases = [];
|
||||
} else {
|
||||
foreach ($node as $name => $subNode) {
|
||||
if ($subNode instanceof Name) {
|
||||
// Implicitly thunk all aliases.
|
||||
if ($replacement = $this->findAlias($subNode)) {
|
||||
$node->$name = $replacement;
|
||||
}
|
||||
$this->lastAliases = $this->aliases;
|
||||
$this->aliases = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Do nothing with UseUse; this an entry in the list of uses in the use statement.
|
||||
if ($node instanceof UseUse) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For everything else, we'll implicitly thunk all aliases into fully-qualified names.
|
||||
foreach ($node as $name => $subNode) {
|
||||
if ($subNode instanceof Name) {
|
||||
if ($replacement = $this->findAlias($subNode)) {
|
||||
$node->$name = $replacement;
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +132,8 @@ class UseStatementPass extends CodeCleanerPass
|
||||
foreach ($this->aliases as $alias => $prefix) {
|
||||
if ($that === $alias) {
|
||||
return new FullyQualifiedName($prefix->toString());
|
||||
} elseif (\substr($that, 0, \strlen($alias) + 1) === $alias . '\\') {
|
||||
return new FullyQualifiedName($prefix->toString() . \substr($name, \strlen($alias)));
|
||||
} elseif (\substr($that, 0, \strlen($alias) + 1) === $alias.'\\') {
|
||||
return new FullyQualifiedName($prefix->toString().\substr($name, \strlen($alias)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -13,9 +13,7 @@ namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Do_;
|
||||
@@ -34,17 +32,11 @@ use Psy\Exception\FatalErrorException;
|
||||
*/
|
||||
class ValidClassNamePass extends NamespaceAwarePass
|
||||
{
|
||||
const CLASS_TYPE = 'class';
|
||||
const CLASS_TYPE = 'class';
|
||||
const INTERFACE_TYPE = 'interface';
|
||||
const TRAIT_TYPE = 'trait';
|
||||
const TRAIT_TYPE = 'trait';
|
||||
|
||||
private $conditionalScopes = 0;
|
||||
private $atLeastPhp55;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->atLeastPhp55 = \version_compare(PHP_VERSION, '5.5', '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate class, interface and trait definitions.
|
||||
@@ -54,6 +46,8 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
* trait methods.
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -61,51 +55,42 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
|
||||
if (self::isConditional($node)) {
|
||||
$this->conditionalScopes++;
|
||||
} else {
|
||||
// @todo add an "else" here which adds a runtime check for instances where we can't tell
|
||||
// whether a class is being redefined by static analysis alone.
|
||||
if ($this->conditionalScopes === 0) {
|
||||
if ($node instanceof Class_) {
|
||||
$this->validateClassStatement($node);
|
||||
} elseif ($node instanceof Interface_) {
|
||||
$this->validateInterfaceStatement($node);
|
||||
} elseif ($node instanceof Trait_) {
|
||||
$this->validateTraitStatement($node);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->conditionalScopes === 0) {
|
||||
if ($node instanceof Class_) {
|
||||
$this->validateClassStatement($node);
|
||||
} elseif ($node instanceof Interface_) {
|
||||
$this->validateInterfaceStatement($node);
|
||||
} elseif ($node instanceof Trait_) {
|
||||
$this->validateTraitStatement($node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate `new` expressions, class constant fetches, and static calls.
|
||||
*
|
||||
* @throws FatalErrorException if a class, interface or trait is referenced which does not exist
|
||||
* @throws FatalErrorException if a class extends something that is not a class
|
||||
* @throws FatalErrorException if a class implements something that is not an interface
|
||||
* @throws FatalErrorException if an interface extends something that is not an interface
|
||||
* @throws FatalErrorException if a class, interface or trait redefines an existing class, interface or trait name
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if (self::isConditional($node)) {
|
||||
$this->conditionalScopes--;
|
||||
} elseif ($node instanceof New_) {
|
||||
$this->validateNewExpression($node);
|
||||
} elseif ($node instanceof ClassConstFetch) {
|
||||
$this->validateClassConstFetchExpression($node);
|
||||
} elseif ($node instanceof StaticCall) {
|
||||
$this->validateStaticCallExpression($node);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static function isConditional(Node $node)
|
||||
private static function isConditional(Node $node): bool
|
||||
{
|
||||
return $node instanceof If_ ||
|
||||
$node instanceof While_ ||
|
||||
$node instanceof Do_ ||
|
||||
$node instanceof Switch_;
|
||||
$node instanceof Switch_ ||
|
||||
$node instanceof Ternary;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,50 +128,6 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
$this->ensureCanDefine($stmt, self::TRAIT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a `new` expression.
|
||||
*
|
||||
* @param New_ $stmt
|
||||
*/
|
||||
protected function validateNewExpression(New_ $stmt)
|
||||
{
|
||||
// if class name is an expression or an anonymous class, give it a pass for now
|
||||
if (!$stmt->class instanceof Expr && !$stmt->class instanceof Class_) {
|
||||
$this->ensureClassExists($this->getFullyQualifiedName($stmt->class), $stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a class constant fetch expression's class.
|
||||
*
|
||||
* @param ClassConstFetch $stmt
|
||||
*/
|
||||
protected function validateClassConstFetchExpression(ClassConstFetch $stmt)
|
||||
{
|
||||
// there is no need to check exists for ::class const for php 5.5 or newer
|
||||
if (\strtolower($stmt->name) === 'class' && $this->atLeastPhp55) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if class name is an expression, give it a pass for now
|
||||
if (!$stmt->class instanceof Expr) {
|
||||
$this->ensureClassOrInterfaceExists($this->getFullyQualifiedName($stmt->class), $stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a class constant fetch expression's class.
|
||||
*
|
||||
* @param StaticCall $stmt
|
||||
*/
|
||||
protected function validateStaticCallExpression(StaticCall $stmt)
|
||||
{
|
||||
// if class name is an expression, give it a pass for now
|
||||
if (!$stmt->class instanceof Expr) {
|
||||
$this->ensureMethodExists($this->getFullyQualifiedName($stmt->class), $stmt->name, $stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that no class, interface or trait name collides with a new definition.
|
||||
*
|
||||
@@ -195,8 +136,13 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
* @param Stmt $stmt
|
||||
* @param string $scopeType
|
||||
*/
|
||||
protected function ensureCanDefine(Stmt $stmt, $scopeType = self::CLASS_TYPE)
|
||||
protected function ensureCanDefine(Stmt $stmt, string $scopeType = self::CLASS_TYPE)
|
||||
{
|
||||
// Anonymous classes don't have a name, and uniqueness shouldn't be enforced.
|
||||
if ($stmt->name === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $this->getFullyQualifiedName($stmt->name);
|
||||
|
||||
// check for name collisions
|
||||
@@ -226,7 +172,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
* @param string $name
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureClassExists($name, $stmt)
|
||||
protected function ensureClassExists(string $name, Stmt $stmt)
|
||||
{
|
||||
if (!$this->classExists($name)) {
|
||||
throw $this->createError(\sprintf('Class \'%s\' not found', $name), $stmt);
|
||||
@@ -241,7 +187,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
* @param string $name
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureClassOrInterfaceExists($name, $stmt)
|
||||
protected function ensureClassOrInterfaceExists(string $name, Stmt $stmt)
|
||||
{
|
||||
if (!$this->classExists($name) && !$this->interfaceExists($name)) {
|
||||
throw $this->createError(\sprintf('Class \'%s\' not found', $name), $stmt);
|
||||
@@ -256,7 +202,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
* @param string $name
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureClassOrTraitExists($name, $stmt)
|
||||
protected function ensureClassOrTraitExists(string $name, Stmt $stmt)
|
||||
{
|
||||
if (!$this->classExists($name) && !$this->traitExists($name)) {
|
||||
throw $this->createError(\sprintf('Class \'%s\' not found', $name), $stmt);
|
||||
@@ -272,7 +218,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
* @param string $name
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureMethodExists($class, $name, $stmt)
|
||||
protected function ensureMethodExists(string $class, string $name, Stmt $stmt)
|
||||
{
|
||||
$this->ensureClassOrTraitExists($class, $stmt);
|
||||
|
||||
@@ -304,7 +250,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
* @param Interface_[] $interfaces
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureInterfacesExist($interfaces, $stmt)
|
||||
protected function ensureInterfacesExist(array $interfaces, Stmt $stmt)
|
||||
{
|
||||
foreach ($interfaces as $interface) {
|
||||
/** @var string $name */
|
||||
@@ -321,11 +267,13 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
* @deprecated No longer used. Scope type should be passed into ensureCanDefine directly.
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @throws FatalErrorException
|
||||
*
|
||||
* @param Stmt $stmt
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getScopeType(Stmt $stmt)
|
||||
protected function getScopeType(Stmt $stmt): string
|
||||
{
|
||||
if ($stmt instanceof Class_) {
|
||||
return self::CLASS_TYPE;
|
||||
@@ -334,6 +282,8 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
} elseif ($stmt instanceof Trait_) {
|
||||
return self::TRAIT_TYPE;
|
||||
}
|
||||
|
||||
throw $this->createError('Unsupported statement type', $stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +295,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function classExists($name)
|
||||
protected function classExists(string $name): bool
|
||||
{
|
||||
// Give `self`, `static` and `parent` a pass. This will actually let
|
||||
// some errors through, since we're not checking whether the keyword is
|
||||
@@ -364,7 +314,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function interfaceExists($name)
|
||||
protected function interfaceExists(string $name): bool
|
||||
{
|
||||
return \interface_exists($name) || $this->findInScope($name) === self::INTERFACE_TYPE;
|
||||
}
|
||||
@@ -376,7 +326,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function traitExists($name)
|
||||
protected function traitExists(string $name): bool
|
||||
{
|
||||
return \trait_exists($name) || $this->findInScope($name) === self::TRAIT_TYPE;
|
||||
}
|
||||
@@ -388,7 +338,7 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function findInScope($name)
|
||||
protected function findInScope(string $name)
|
||||
{
|
||||
$name = \strtolower($name);
|
||||
if (isset($this->currentScope[$name])) {
|
||||
@@ -404,8 +354,8 @@ class ValidClassNamePass extends NamespaceAwarePass
|
||||
*
|
||||
* @return FatalErrorException
|
||||
*/
|
||||
protected function createError($msg, $stmt)
|
||||
protected function createError(string $msg, Stmt $stmt): FatalErrorException
|
||||
{
|
||||
return new FatalErrorException($msg, 0, E_ERROR, null, $stmt->getLine());
|
||||
return new FatalErrorException($msg, 0, \E_ERROR, null, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
|
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that namespaced constant references will succeed.
|
||||
*
|
||||
* This pass throws a FatalErrorException rather than letting PHP run
|
||||
* headfirst into a real fatal error and die.
|
||||
*
|
||||
* @todo Detect constants defined in the current code snippet?
|
||||
* ... Might not be worth it, since it would need to both be defining and
|
||||
* referencing a namespaced constant, which doesn't seem like that big of
|
||||
* a target for failure
|
||||
*/
|
||||
class ValidConstantPass extends NamespaceAwarePass
|
||||
{
|
||||
/**
|
||||
* Validate that namespaced constant references will succeed.
|
||||
*
|
||||
* Note that this does not (yet) detect constants defined in the current code
|
||||
* snippet. It won't happen very often, so we'll punt for now.
|
||||
*
|
||||
* @throws FatalErrorException if a constant reference is not defined
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof ConstFetch && \count($node->name->parts) > 1) {
|
||||
$name = $this->getFullyQualifiedName($node->name);
|
||||
if (!\defined($name)) {
|
||||
$msg = \sprintf('Undefined constant %s', $name);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
}
|
||||
} elseif ($node instanceof ClassConstFetch) {
|
||||
$this->validateClassConstFetchExpression($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a class constant fetch expression.
|
||||
*
|
||||
* @throws FatalErrorException if a class constant is not defined
|
||||
*
|
||||
* @param ClassConstFetch $stmt
|
||||
*/
|
||||
protected function validateClassConstFetchExpression(ClassConstFetch $stmt)
|
||||
{
|
||||
// For PHP Parser 4.x
|
||||
$constName = $stmt->name instanceof Identifier ? $stmt->name->toString() : $stmt->name;
|
||||
|
||||
// give the `class` pseudo-constant a pass
|
||||
if ($constName === 'class') {
|
||||
return;
|
||||
}
|
||||
|
||||
// if class name is an expression, give it a pass for now
|
||||
if (!$stmt->class instanceof Expr) {
|
||||
$className = $this->getFullyQualifiedName($stmt->class);
|
||||
|
||||
// if the class doesn't exist, don't throw an exception… it might be
|
||||
// defined in the same line it's used or something stupid like that.
|
||||
if (\class_exists($className) || \interface_exists($className)) {
|
||||
$refl = new \ReflectionClass($className);
|
||||
if (!$refl->hasConstant($constName)) {
|
||||
$constType = \class_exists($className) ? 'Class' : 'Interface';
|
||||
$msg = \sprintf('%s constant \'%s::%s\' not found', $constType, $className, $constName);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -35,6 +35,9 @@ class ValidConstructorPass extends CodeCleanerPass
|
||||
{
|
||||
private $namespace;
|
||||
|
||||
/**
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$this->namespace = [];
|
||||
@@ -47,6 +50,8 @@ class ValidConstructorPass extends CodeCleanerPass
|
||||
* @throws FatalErrorException the constructor function has a return type
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -94,7 +99,7 @@ class ValidConstructorPass extends CodeCleanerPass
|
||||
\implode('\\', \array_merge($this->namespace, (array) $className)),
|
||||
$constructor->name
|
||||
);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $classNode->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $classNode->getLine());
|
||||
}
|
||||
|
||||
if (\method_exists($constructor, 'getReturnType') && $constructor->getReturnType()) {
|
||||
@@ -106,7 +111,7 @@ class ValidConstructorPass extends CodeCleanerPass
|
||||
\implode('\\', \array_merge($this->namespace, (array) $className)),
|
||||
$constructor->name
|
||||
);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $classNode->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $classNode->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -12,9 +12,6 @@
|
||||
namespace Psy\CodeCleaner;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Do_;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
@@ -35,7 +32,11 @@ class ValidFunctionNamePass extends NamespaceAwarePass
|
||||
/**
|
||||
* Store newly defined function names on the way in, to allow recursion.
|
||||
*
|
||||
* @throws FatalErrorException if a function is redefined in a non-conditional scope
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -52,7 +53,7 @@ class ValidFunctionNamePass extends NamespaceAwarePass
|
||||
if (\function_exists($name) ||
|
||||
isset($this->currentScope[\strtolower($name)])) {
|
||||
$msg = \sprintf('Cannot redeclare %s()', $name);
|
||||
throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
|
||||
throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,29 +62,14 @@ class ValidFunctionNamePass extends NamespaceAwarePass
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that function calls will succeed.
|
||||
*
|
||||
* @throws FatalErrorException if a function is redefined
|
||||
* @throws FatalErrorException if the function name is a string (not an expression) and is not defined
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if (self::isConditional($node)) {
|
||||
$this->conditionalScopes--;
|
||||
} elseif ($node instanceof FuncCall) {
|
||||
// if function name is an expression or a variable, give it a pass for now.
|
||||
$name = $node->name;
|
||||
if (!$name instanceof Expr && !$name instanceof Variable) {
|
||||
$shortName = \implode('\\', $name->parts);
|
||||
$fullName = $this->getFullyQualifiedName($name);
|
||||
$inScope = isset($this->currentScope[\strtolower($fullName)]);
|
||||
if (!$inScope && !\function_exists($shortName) && !\function_exists($fullName)) {
|
||||
$message = \sprintf('Call to undefined function %s()', $name);
|
||||
throw new FatalErrorException($message, 0, E_ERROR, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
16
vendor/psy/psysh/src/Command/BufferCommand.php
vendored
16
vendor/psy/psysh/src/Command/BufferCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Psy\Command;
|
||||
|
||||
use Psy\Exception\RuntimeException;
|
||||
use Psy\Output\ShellOutput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
@@ -46,12 +47,19 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$buf = $this->getApplication()->getCodeBuffer();
|
||||
$app = $this->getApplication();
|
||||
if (!$app instanceof \Psy\Shell) {
|
||||
throw new RuntimeException('Buffer command requires a \Psy\Shell application');
|
||||
}
|
||||
|
||||
$buf = $app->getCodeBuffer();
|
||||
if ($input->getOption('clear')) {
|
||||
$this->getApplication()->resetCodeBuffer();
|
||||
$app->resetCodeBuffer();
|
||||
$output->writeln($this->formatLines($buf, 'urgent'), ShellOutput::NUMBER_LINES);
|
||||
} else {
|
||||
$output->writeln($this->formatLines($buf), ShellOutput::NUMBER_LINES);
|
||||
@@ -68,7 +76,7 @@ HELP
|
||||
*
|
||||
* @return array Formatted strings
|
||||
*/
|
||||
protected function formatLines(array $lines, $type = 'return')
|
||||
protected function formatLines(array $lines, string $type = 'return'): array
|
||||
{
|
||||
$template = \sprintf('<%s>%%s</%s>', $type, $type);
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -41,6 +41,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
65
vendor/psy/psysh/src/Command/Command.php
vendored
65
vendor/psy/psysh/src/Command/Command.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -27,7 +27,7 @@ abstract class Command extends BaseCommand
|
||||
/**
|
||||
* Sets the application instance for this command.
|
||||
*
|
||||
* @param Application $application An Application instance
|
||||
* @param Application|null $application An Application instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
@@ -43,11 +43,11 @@ abstract class Command extends BaseCommand
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function asText()
|
||||
public function asText(): string
|
||||
{
|
||||
$messages = [
|
||||
'<comment>Usage:</comment>',
|
||||
' ' . $this->getSynopsis(),
|
||||
' '.$this->getSynopsis(),
|
||||
'',
|
||||
];
|
||||
|
||||
@@ -65,7 +65,7 @@ abstract class Command extends BaseCommand
|
||||
|
||||
if ($help = $this->getProcessedHelp()) {
|
||||
$messages[] = '<comment>Help:</comment>';
|
||||
$messages[] = ' ' . \str_replace("\n", "\n ", $help) . "\n";
|
||||
$messages[] = ' '.\str_replace("\n", "\n ", $help)."\n";
|
||||
}
|
||||
|
||||
return \implode("\n", $messages);
|
||||
@@ -74,7 +74,7 @@ abstract class Command extends BaseCommand
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function getArguments()
|
||||
private function getArguments(): array
|
||||
{
|
||||
$hidden = $this->getHiddenArguments();
|
||||
|
||||
@@ -88,7 +88,7 @@ abstract class Command extends BaseCommand
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getHiddenArguments()
|
||||
protected function getHiddenArguments(): array
|
||||
{
|
||||
return ['command'];
|
||||
}
|
||||
@@ -96,7 +96,7 @@ abstract class Command extends BaseCommand
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function getOptions()
|
||||
private function getOptions(): array
|
||||
{
|
||||
$hidden = $this->getHiddenOptions();
|
||||
|
||||
@@ -110,7 +110,7 @@ abstract class Command extends BaseCommand
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getHiddenOptions()
|
||||
protected function getHiddenOptions(): array
|
||||
{
|
||||
return ['verbose'];
|
||||
}
|
||||
@@ -120,9 +120,9 @@ abstract class Command extends BaseCommand
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function aliasesAsText()
|
||||
private function aliasesAsText(): string
|
||||
{
|
||||
return '<comment>Aliases:</comment> <info>' . \implode(', ', $this->getAliases()) . '</info>' . PHP_EOL;
|
||||
return '<comment>Aliases:</comment> <info>'.\implode(', ', $this->getAliases()).'</info>'.\PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +130,7 @@ abstract class Command extends BaseCommand
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function argumentsAsText()
|
||||
private function argumentsAsText(): string
|
||||
{
|
||||
$max = $this->getMaxWidth();
|
||||
$messages = [];
|
||||
@@ -145,15 +145,15 @@ abstract class Command extends BaseCommand
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$description = \str_replace("\n", "\n" . \str_pad('', $max + 2, ' '), $argument->getDescription());
|
||||
$description = \str_replace("\n", "\n".\str_pad('', $max + 2, ' '), $argument->getDescription());
|
||||
|
||||
$messages[] = \sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $description, $default);
|
||||
$messages[] = \sprintf(" <info>%-{$max}s</info> %s%s", $argument->getName(), $description, $default);
|
||||
}
|
||||
|
||||
$messages[] = '';
|
||||
}
|
||||
|
||||
return \implode(PHP_EOL, $messages);
|
||||
return \implode(\PHP_EOL, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,7 +161,7 @@ abstract class Command extends BaseCommand
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function optionsAsText()
|
||||
private function optionsAsText(): string
|
||||
{
|
||||
$max = $this->getMaxWidth();
|
||||
$messages = [];
|
||||
@@ -178,12 +178,12 @@ abstract class Command extends BaseCommand
|
||||
}
|
||||
|
||||
$multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
|
||||
$description = \str_replace("\n", "\n" . \str_pad('', $max + 2, ' '), $option->getDescription());
|
||||
$description = \str_replace("\n", "\n".\str_pad('', $max + 2, ' '), $option->getDescription());
|
||||
|
||||
$optionMax = $max - \strlen($option->getName()) - 2;
|
||||
$messages[] = \sprintf(
|
||||
" <info>%s</info> %-${optionMax}s%s%s%s",
|
||||
'--' . $option->getName(),
|
||||
" <info>%s</info> %-{$optionMax}s%s%s%s",
|
||||
'--'.$option->getName(),
|
||||
$option->getShortcut() ? \sprintf('(-%s) ', $option->getShortcut()) : '',
|
||||
$description,
|
||||
$default,
|
||||
@@ -194,7 +194,7 @@ abstract class Command extends BaseCommand
|
||||
$messages[] = '';
|
||||
}
|
||||
|
||||
return \implode(PHP_EOL, $messages);
|
||||
return \implode(\PHP_EOL, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,7 +202,7 @@ abstract class Command extends BaseCommand
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getMaxWidth()
|
||||
private function getMaxWidth(): int
|
||||
{
|
||||
$max = 0;
|
||||
|
||||
@@ -229,10 +229,10 @@ abstract class Command extends BaseCommand
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function formatDefaultValue($default)
|
||||
private function formatDefaultValue($default): string
|
||||
{
|
||||
if (\is_array($default) && $default === \array_values($default)) {
|
||||
return \sprintf("array('%s')", \implode("', '", $default));
|
||||
return \sprintf("['%s']", \implode("', '", $default));
|
||||
}
|
||||
|
||||
return \str_replace("\n", '', \var_export($default, true));
|
||||
@@ -247,15 +247,22 @@ abstract class Command extends BaseCommand
|
||||
*/
|
||||
protected function getTable(OutputInterface $output)
|
||||
{
|
||||
if (!\class_exists('Symfony\Component\Console\Helper\Table')) {
|
||||
if (!\class_exists(Table::class)) {
|
||||
return $this->getTableHelper();
|
||||
}
|
||||
|
||||
$style = new TableStyle();
|
||||
$style
|
||||
->setVerticalBorderChar(' ')
|
||||
->setHorizontalBorderChar('')
|
||||
->setCrossingChar('');
|
||||
|
||||
// Symfony 4.1 deprecated single-argument style setters.
|
||||
if (\method_exists($style, 'setVerticalBorderChars')) {
|
||||
$style->setVerticalBorderChars(' ');
|
||||
$style->setHorizontalBorderChars('');
|
||||
$style->setCrossingChars('', '', '', '', '', '', '', '', '');
|
||||
} else {
|
||||
$style->setVerticalBorderChar(' ');
|
||||
$style->setHorizontalBorderChar('');
|
||||
$style->setCrossingChar('');
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
|
||||
@@ -269,7 +276,7 @@ abstract class Command extends BaseCommand
|
||||
*
|
||||
* @return TableHelper
|
||||
*/
|
||||
protected function getTableHelper()
|
||||
protected function getTableHelper(): TableHelper
|
||||
{
|
||||
$table = $this->getApplication()->getHelperSet()->get('table');
|
||||
|
||||
|
171
vendor/psy/psysh/src/Command/DocCommand.php
vendored
171
vendor/psy/psysh/src/Command/DocCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -14,8 +14,12 @@ namespace Psy\Command;
|
||||
use Psy\Formatter\DocblockFormatter;
|
||||
use Psy\Formatter\SignatureFormatter;
|
||||
use Psy\Input\CodeArgument;
|
||||
use Psy\Output\ShellOutput;
|
||||
use Psy\Reflection\ReflectionClassConstant;
|
||||
use Psy\Reflection\ReflectionConstant_;
|
||||
use Psy\Reflection\ReflectionLanguageConstruct;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
@@ -23,6 +27,8 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
*/
|
||||
class DocCommand extends ReflectingCommand
|
||||
{
|
||||
const INHERIT_DOC_TAG = '{@inheritdoc}';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -32,6 +38,7 @@ class DocCommand extends ReflectingCommand
|
||||
->setName('doc')
|
||||
->setAliases(['rtfm', 'man'])
|
||||
->setDefinition([
|
||||
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Show documentation for superclasses as well as the current class.'),
|
||||
new CodeArgument('target', CodeArgument::REQUIRED, 'Function, class, instance, constant, method or property to document.'),
|
||||
])
|
||||
->setDescription('Read the documentation for an object, class, constant, method or property.')
|
||||
@@ -53,6 +60,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -67,18 +76,51 @@ HELP
|
||||
|
||||
$db = $this->getApplication()->getManualDb();
|
||||
|
||||
$output->page(function ($output) use ($reflector, $doc, $db) {
|
||||
$output->writeln(SignatureFormatter::format($reflector));
|
||||
$output->writeln('');
|
||||
if ($output instanceof ShellOutput) {
|
||||
$output->startPaging();
|
||||
}
|
||||
|
||||
if (empty($doc) && !$db) {
|
||||
$output->writeln('<warning>PHP manual not found</warning>');
|
||||
$output->writeln(' To document core PHP functionality, download the PHP reference manual:');
|
||||
$output->writeln(' https://github.com/bobthecow/psysh/wiki/PHP-manual');
|
||||
} else {
|
||||
$output->writeln($doc);
|
||||
// Maybe include the declaring class
|
||||
if ($reflector instanceof \ReflectionMethod || $reflector instanceof \ReflectionProperty) {
|
||||
$output->writeln(SignatureFormatter::format($reflector->getDeclaringClass()));
|
||||
}
|
||||
|
||||
$output->writeln(SignatureFormatter::format($reflector));
|
||||
$output->writeln('');
|
||||
|
||||
if (empty($doc) && !$db) {
|
||||
$output->writeln('<warning>PHP manual not found</warning>');
|
||||
$output->writeln(' To document core PHP functionality, download the PHP reference manual:');
|
||||
$output->writeln(' https://github.com/bobthecow/psysh/wiki/PHP-manual');
|
||||
} else {
|
||||
$output->writeln($doc);
|
||||
}
|
||||
|
||||
// Implicit --all if the original docblock has an {@inheritdoc} tag.
|
||||
if ($input->getOption('all') || \stripos($doc, self::INHERIT_DOC_TAG) !== false) {
|
||||
$parent = $reflector;
|
||||
foreach ($this->getParentReflectors($reflector) as $parent) {
|
||||
$output->writeln('');
|
||||
$output->writeln('---');
|
||||
$output->writeln('');
|
||||
|
||||
// Maybe include the declaring class
|
||||
if ($parent instanceof \ReflectionMethod || $parent instanceof \ReflectionProperty) {
|
||||
$output->writeln(SignatureFormatter::format($parent->getDeclaringClass()));
|
||||
}
|
||||
|
||||
$output->writeln(SignatureFormatter::format($parent));
|
||||
$output->writeln('');
|
||||
|
||||
if ($doc = $this->getManualDoc($parent) ?: DocblockFormatter::format($parent)) {
|
||||
$output->writeln($doc);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ($output instanceof ShellOutput) {
|
||||
$output->stopPaging();
|
||||
}
|
||||
|
||||
// Set some magic local variables
|
||||
$this->setCommandScopeVariables($reflector);
|
||||
@@ -89,29 +131,29 @@ HELP
|
||||
private function getManualDoc($reflector)
|
||||
{
|
||||
switch (\get_class($reflector)) {
|
||||
case 'ReflectionClass':
|
||||
case 'ReflectionObject':
|
||||
case 'ReflectionFunction':
|
||||
case \ReflectionClass::class:
|
||||
case \ReflectionObject::class:
|
||||
case \ReflectionFunction::class:
|
||||
$id = $reflector->name;
|
||||
break;
|
||||
|
||||
case 'ReflectionMethod':
|
||||
$id = $reflector->class . '::' . $reflector->name;
|
||||
case \ReflectionMethod::class:
|
||||
$id = $reflector->class.'::'.$reflector->name;
|
||||
break;
|
||||
|
||||
case 'ReflectionProperty':
|
||||
$id = $reflector->class . '::$' . $reflector->name;
|
||||
case \ReflectionProperty::class:
|
||||
$id = $reflector->class.'::$'.$reflector->name;
|
||||
break;
|
||||
|
||||
case 'ReflectionClassConstant':
|
||||
case 'Psy\Reflection\ReflectionClassConstant':
|
||||
case \ReflectionClassConstant::class:
|
||||
case ReflectionClassConstant::class:
|
||||
// @todo this is going to collide with ReflectionMethod ids
|
||||
// someday... start running the query by id + type if the DB
|
||||
// supports it.
|
||||
$id = $reflector->class . '::' . $reflector->name;
|
||||
$id = $reflector->class.'::'.$reflector->name;
|
||||
break;
|
||||
|
||||
case 'Psy\Reflection\ReflectionConstant_':
|
||||
case ReflectionConstant_::class:
|
||||
$id = $reflector->name;
|
||||
break;
|
||||
|
||||
@@ -122,12 +164,91 @@ HELP
|
||||
return $this->getManualDocById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all all parent Reflectors for a given Reflector.
|
||||
*
|
||||
* For example, passing a Class, Object or TraitReflector will yield all
|
||||
* traits and parent classes. Passing a Method or PropertyReflector will
|
||||
* yield Reflectors for the same-named method or property on all traits and
|
||||
* parent classes.
|
||||
*
|
||||
* @return \Generator a whole bunch of \Reflector instances
|
||||
*/
|
||||
private function getParentReflectors($reflector): \Generator
|
||||
{
|
||||
$seenClasses = [];
|
||||
|
||||
switch (\get_class($reflector)) {
|
||||
case \ReflectionClass::class:
|
||||
case \ReflectionObject::class:
|
||||
foreach ($reflector->getTraits() as $trait) {
|
||||
if (!\in_array($trait->getName(), $seenClasses)) {
|
||||
$seenClasses[] = $trait->getName();
|
||||
yield $trait;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($reflector->getInterfaces() as $interface) {
|
||||
if (!\in_array($interface->getName(), $seenClasses)) {
|
||||
$seenClasses[] = $interface->getName();
|
||||
yield $interface;
|
||||
}
|
||||
}
|
||||
|
||||
while ($reflector = $reflector->getParentClass()) {
|
||||
yield $reflector;
|
||||
|
||||
foreach ($reflector->getTraits() as $trait) {
|
||||
if (!\in_array($trait->getName(), $seenClasses)) {
|
||||
$seenClasses[] = $trait->getName();
|
||||
yield $trait;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($reflector->getInterfaces() as $interface) {
|
||||
if (!\in_array($interface->getName(), $seenClasses)) {
|
||||
$seenClasses[] = $interface->getName();
|
||||
yield $interface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case \ReflectionMethod::class:
|
||||
foreach ($this->getParentReflectors($reflector->getDeclaringClass()) as $parent) {
|
||||
if ($parent->hasMethod($reflector->getName())) {
|
||||
$parentMethod = $parent->getMethod($reflector->getName());
|
||||
if (!\in_array($parentMethod->getDeclaringClass()->getName(), $seenClasses)) {
|
||||
$seenClasses[] = $parentMethod->getDeclaringClass()->getName();
|
||||
yield $parentMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case \ReflectionProperty::class:
|
||||
foreach ($this->getParentReflectors($reflector->getDeclaringClass()) as $parent) {
|
||||
if ($parent->hasProperty($reflector->getName())) {
|
||||
$parentProperty = $parent->getProperty($reflector->getName());
|
||||
if (!\in_array($parentProperty->getDeclaringClass()->getName(), $seenClasses)) {
|
||||
$seenClasses[] = $parentProperty->getDeclaringClass()->getName();
|
||||
yield $parentProperty;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function getManualDocById($id)
|
||||
{
|
||||
if ($db = $this->getApplication()->getManualDb()) {
|
||||
return $db
|
||||
->query(\sprintf('SELECT doc FROM php_manual WHERE id = %s', $db->quote($id)))
|
||||
->fetchColumn(0);
|
||||
$result = $db->query(\sprintf('SELECT doc FROM php_manual WHERE id = %s', $db->quote($id)));
|
||||
if ($result !== false) {
|
||||
return $result->fetchColumn(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
vendor/psy/psysh/src/Command/DumpCommand.php
vendored
10
vendor/psy/psysh/src/Command/DumpCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -66,10 +66,12 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$depth = $input->getOption('depth');
|
||||
$depth = $input->getOption('depth');
|
||||
$target = $this->resolveCode($input->getArgument('target'));
|
||||
$output->page($this->presenter->present($target, $depth, $input->getOption('all') ? Presenter::VERBOSE : 0));
|
||||
|
||||
@@ -87,9 +89,9 @@ HELP
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function resolveTarget($name)
|
||||
protected function resolveTarget(string $name)
|
||||
{
|
||||
@\trigger_error('`resolveTarget` is deprecated; use `resolveCode` instead.', E_USER_DEPRECATED);
|
||||
@\trigger_error('`resolveTarget` is deprecated; use `resolveCode` instead.', \E_USER_DEPRECATED);
|
||||
|
||||
return $this->resolveCode($name);
|
||||
}
|
||||
|
17
vendor/psy/psysh/src/Command/EditCommand.php
vendored
17
vendor/psy/psysh/src/Command/EditCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -74,6 +74,8 @@ class EditCommand extends Command implements ContextAware
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*
|
||||
* @throws \InvalidArgumentException when both exec and no-exec flags are given or if a given variable is not found in the current context
|
||||
* @throws \UnexpectedValueException if file_get_contents on the edited file returns false instead of a string
|
||||
*/
|
||||
@@ -115,7 +117,7 @@ class EditCommand extends Command implements ContextAware
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function shouldExecuteFile($execOption, $noExecOption, $filePath)
|
||||
private function shouldExecuteFile(bool $execOption, bool $noExecOption, string $filePath = null): bool
|
||||
{
|
||||
if ($execOption) {
|
||||
return true;
|
||||
@@ -136,11 +138,11 @@ class EditCommand extends Command implements ContextAware
|
||||
*
|
||||
* @throws \InvalidArgumentException If the variable is not found in the current context
|
||||
*/
|
||||
private function extractFilePath($fileArgument)
|
||||
private function extractFilePath(string $fileArgument = null)
|
||||
{
|
||||
// If the file argument was a variable, get it from the context
|
||||
if ($fileArgument !== null &&
|
||||
\strlen($fileArgument) > 0 &&
|
||||
$fileArgument !== '' &&
|
||||
$fileArgument[0] === '$') {
|
||||
$fileArgument = $this->context->get(\preg_replace('/^\$/', '', $fileArgument));
|
||||
}
|
||||
@@ -150,18 +152,19 @@ class EditCommand extends Command implements ContextAware
|
||||
|
||||
/**
|
||||
* @param string $filePath
|
||||
* @param string $shouldRemoveFile
|
||||
* @param bool $shouldRemoveFile
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \UnexpectedValueException if file_get_contents on $filePath returns false instead of a string
|
||||
*/
|
||||
private function editFile($filePath, $shouldRemoveFile)
|
||||
private function editFile(string $filePath, bool $shouldRemoveFile): string
|
||||
{
|
||||
$escapedFilePath = \escapeshellarg($filePath);
|
||||
$editor = (isset($_SERVER['EDITOR']) && $_SERVER['EDITOR']) ? $_SERVER['EDITOR'] : 'nano';
|
||||
|
||||
$pipes = [];
|
||||
$proc = \proc_open((\getenv('EDITOR') ?: 'nano') . " {$escapedFilePath}", [STDIN, STDOUT, STDERR], $pipes);
|
||||
$proc = \proc_open("{$editor} {$escapedFilePath}", [\STDIN, \STDOUT, \STDERR], $pipes);
|
||||
\proc_close($proc);
|
||||
|
||||
$editedContent = @\file_get_contents($filePath);
|
||||
|
4
vendor/psy/psysh/src/Command/ExitCommand.php
vendored
4
vendor/psy/psysh/src/Command/ExitCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -44,6 +44,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
17
vendor/psy/psysh/src/Command/HelpCommand.php
vendored
17
vendor/psy/psysh/src/Command/HelpCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Psy\Command;
|
||||
|
||||
use Psy\Output\ShellOutput;
|
||||
use Symfony\Component\Console\Helper\TableHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -45,13 +46,15 @@ class HelpCommand extends Command
|
||||
*
|
||||
* @param Command $command
|
||||
*/
|
||||
public function setCommand($command)
|
||||
public function setCommand(Command $command)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -86,13 +89,19 @@ class HelpCommand extends Command
|
||||
]);
|
||||
}
|
||||
|
||||
$output->startPaging();
|
||||
if ($output instanceof ShellOutput) {
|
||||
$output->startPaging();
|
||||
}
|
||||
|
||||
if ($table instanceof TableHelper) {
|
||||
$table->render($output);
|
||||
} else {
|
||||
$table->render();
|
||||
}
|
||||
$output->stopPaging();
|
||||
|
||||
if ($output instanceof ShellOutput) {
|
||||
$output->stopPaging();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
54
vendor/psy/psysh/src/Command/HistoryCommand.php
vendored
54
vendor/psy/psysh/src/Command/HistoryCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -60,19 +60,19 @@ class HistoryCommand extends Command
|
||||
->setName('history')
|
||||
->setAliases(['hist'])
|
||||
->setDefinition([
|
||||
new InputOption('show', 's', InputOption::VALUE_REQUIRED, 'Show the given range of lines.'),
|
||||
new InputOption('head', 'H', InputOption::VALUE_REQUIRED, 'Display the first N items.'),
|
||||
new InputOption('tail', 'T', InputOption::VALUE_REQUIRED, 'Display the last N items.'),
|
||||
new InputOption('show', 's', InputOption::VALUE_REQUIRED, 'Show the given range of lines.'),
|
||||
new InputOption('head', 'H', InputOption::VALUE_REQUIRED, 'Display the first N items.'),
|
||||
new InputOption('tail', 'T', InputOption::VALUE_REQUIRED, 'Display the last N items.'),
|
||||
|
||||
$grep,
|
||||
$insensitive,
|
||||
$invert,
|
||||
|
||||
new InputOption('no-numbers', 'N', InputOption::VALUE_NONE, 'Omit line numbers.'),
|
||||
new InputOption('no-numbers', 'N', InputOption::VALUE_NONE, 'Omit line numbers.'),
|
||||
|
||||
new InputOption('save', '', InputOption::VALUE_REQUIRED, 'Save history to a file.'),
|
||||
new InputOption('replay', '', InputOption::VALUE_NONE, 'Replay.'),
|
||||
new InputOption('clear', '', InputOption::VALUE_NONE, 'Clear the history.'),
|
||||
new InputOption('save', '', InputOption::VALUE_REQUIRED, 'Save history to a file.'),
|
||||
new InputOption('replay', '', InputOption::VALUE_NONE, 'Replay.'),
|
||||
new InputOption('clear', '', InputOption::VALUE_NONE, 'Clear the history.'),
|
||||
])
|
||||
->setDescription('Show the Psy Shell history.')
|
||||
->setHelp(
|
||||
@@ -90,6 +90,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -105,14 +107,14 @@ HELP
|
||||
|
||||
$this->filter->bind($input);
|
||||
if ($this->filter->hasFilter()) {
|
||||
$matches = [];
|
||||
$matches = [];
|
||||
$highlighted = [];
|
||||
foreach ($history as $i => $line) {
|
||||
if ($this->filter->match($line, $matches)) {
|
||||
if (isset($matches[0])) {
|
||||
$chunks = \explode($matches[0], $history[$i]);
|
||||
$chunks = \array_map([__CLASS__, 'escape'], $chunks);
|
||||
$glue = \sprintf('<urgent>%s</urgent>', self::escape($matches[0]));
|
||||
$glue = \sprintf('<urgent>%s</urgent>', self::escape($matches[0]));
|
||||
|
||||
$highlighted[$i] = \implode($glue, $chunks);
|
||||
}
|
||||
@@ -124,7 +126,7 @@ HELP
|
||||
|
||||
if ($save = $input->getOption('save')) {
|
||||
$output->writeln(\sprintf('Saving history in %s...', $save));
|
||||
\file_put_contents($save, \implode(PHP_EOL, $history) . PHP_EOL);
|
||||
\file_put_contents($save, \implode(\PHP_EOL, $history).\PHP_EOL);
|
||||
$output->writeln('<info>History saved.</info>');
|
||||
} elseif ($input->getOption('replay')) {
|
||||
if (!($input->getOption('show') || $input->getOption('head') || $input->getOption('tail'))) {
|
||||
@@ -156,7 +158,7 @@ HELP
|
||||
*
|
||||
* @return array [ start, end ]
|
||||
*/
|
||||
private function extractRange($range)
|
||||
private function extractRange(string $range): array
|
||||
{
|
||||
if (\preg_match('/^\d+$/', $range)) {
|
||||
return [$range, $range + 1];
|
||||
@@ -164,25 +166,25 @@ HELP
|
||||
|
||||
$matches = [];
|
||||
if ($range !== '..' && \preg_match('/^(\d*)\.\.(\d*)$/', $range, $matches)) {
|
||||
$start = $matches[1] ? \intval($matches[1]) : 0;
|
||||
$end = $matches[2] ? \intval($matches[2]) + 1 : PHP_INT_MAX;
|
||||
$start = $matches[1] ? (int) $matches[1] : 0;
|
||||
$end = $matches[2] ? (int) $matches[2] + 1 : \PHP_INT_MAX;
|
||||
|
||||
return [$start, $end];
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Unexpected range: ' . $range);
|
||||
throw new \InvalidArgumentException('Unexpected range: '.$range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a slice of the readline history.
|
||||
*
|
||||
* @param string $show
|
||||
* @param string $head
|
||||
* @param string $tail
|
||||
* @param string|null $show
|
||||
* @param string|null $head
|
||||
* @param string|null $tail
|
||||
*
|
||||
* @return array A slilce of history
|
||||
* @return array A slice of history
|
||||
*/
|
||||
private function getHistorySlice($show, $head, $tail)
|
||||
private function getHistorySlice($show, $head, $tail): array
|
||||
{
|
||||
$history = $this->readline->listHistory();
|
||||
|
||||
@@ -197,15 +199,15 @@ HELP
|
||||
throw new \InvalidArgumentException('Please specify an integer argument for --head');
|
||||
}
|
||||
|
||||
$start = 0;
|
||||
$length = \intval($head);
|
||||
$start = 0;
|
||||
$length = (int) $head;
|
||||
} elseif ($tail) {
|
||||
if (!\preg_match('/^\d+$/', $tail)) {
|
||||
throw new \InvalidArgumentException('Please specify an integer argument for --tail');
|
||||
}
|
||||
|
||||
$start = \count($history) - $tail;
|
||||
$length = \intval($tail) + 1;
|
||||
$start = \count($history) - $tail;
|
||||
$length = (int) $tail + 1;
|
||||
} else {
|
||||
return $history;
|
||||
}
|
||||
@@ -229,7 +231,7 @@ HELP
|
||||
}
|
||||
|
||||
if ($count > 1) {
|
||||
throw new \InvalidArgumentException('Please specify only one of --' . \implode(', --', $options));
|
||||
throw new \InvalidArgumentException('Please specify only one of --'.\implode(', --', $options));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +243,7 @@ HELP
|
||||
$this->readline->clearHistory();
|
||||
}
|
||||
|
||||
public static function escape($string)
|
||||
public static function escape(string $string): string
|
||||
{
|
||||
return OutputFormatter::escape($string);
|
||||
}
|
||||
|
68
vendor/psy/psysh/src/Command/ListCommand.php
vendored
68
vendor/psy/psysh/src/Command/ListCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -22,6 +22,7 @@ use Psy\Command\ListCommand\VariableEnumerator;
|
||||
use Psy\Exception\RuntimeException;
|
||||
use Psy\Input\CodeArgument;
|
||||
use Psy\Input\FilterOptions;
|
||||
use Psy\Output\ShellOutput;
|
||||
use Psy\VarDumper\Presenter;
|
||||
use Psy\VarDumper\PresenterAware;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
@@ -57,33 +58,33 @@ class ListCommand extends ReflectingCommand implements PresenterAware
|
||||
|
||||
$this
|
||||
->setName('ls')
|
||||
->setAliases(['list', 'dir'])
|
||||
->setAliases(['dir'])
|
||||
->setDefinition([
|
||||
new CodeArgument('target', CodeArgument::OPTIONAL, 'A target class or object to list.'),
|
||||
|
||||
new InputOption('vars', '', InputOption::VALUE_NONE, 'Display variables.'),
|
||||
new InputOption('constants', 'c', InputOption::VALUE_NONE, 'Display defined constants.'),
|
||||
new InputOption('functions', 'f', InputOption::VALUE_NONE, 'Display defined functions.'),
|
||||
new InputOption('classes', 'k', InputOption::VALUE_NONE, 'Display declared classes.'),
|
||||
new InputOption('interfaces', 'I', InputOption::VALUE_NONE, 'Display declared interfaces.'),
|
||||
new InputOption('traits', 't', InputOption::VALUE_NONE, 'Display declared traits.'),
|
||||
new InputOption('vars', '', InputOption::VALUE_NONE, 'Display variables.'),
|
||||
new InputOption('constants', 'c', InputOption::VALUE_NONE, 'Display defined constants.'),
|
||||
new InputOption('functions', 'f', InputOption::VALUE_NONE, 'Display defined functions.'),
|
||||
new InputOption('classes', 'k', InputOption::VALUE_NONE, 'Display declared classes.'),
|
||||
new InputOption('interfaces', 'I', InputOption::VALUE_NONE, 'Display declared interfaces.'),
|
||||
new InputOption('traits', 't', InputOption::VALUE_NONE, 'Display declared traits.'),
|
||||
|
||||
new InputOption('no-inherit', '', InputOption::VALUE_NONE, 'Exclude inherited methods, properties and constants.'),
|
||||
new InputOption('no-inherit', '', InputOption::VALUE_NONE, 'Exclude inherited methods, properties and constants.'),
|
||||
|
||||
new InputOption('properties', 'p', InputOption::VALUE_NONE, 'Display class or object properties (public properties by default).'),
|
||||
new InputOption('methods', 'm', InputOption::VALUE_NONE, 'Display class or object methods (public methods by default).'),
|
||||
new InputOption('properties', 'p', InputOption::VALUE_NONE, 'Display class or object properties (public properties by default).'),
|
||||
new InputOption('methods', 'm', InputOption::VALUE_NONE, 'Display class or object methods (public methods by default).'),
|
||||
|
||||
$grep,
|
||||
$insensitive,
|
||||
$invert,
|
||||
|
||||
new InputOption('globals', 'g', InputOption::VALUE_NONE, 'Include global variables.'),
|
||||
new InputOption('internal', 'n', InputOption::VALUE_NONE, 'Limit to internal functions and classes.'),
|
||||
new InputOption('user', 'u', InputOption::VALUE_NONE, 'Limit to user-defined constants, functions and classes.'),
|
||||
new InputOption('category', 'C', InputOption::VALUE_REQUIRED, 'Limit to constants in a specific category (e.g. "date").'),
|
||||
new InputOption('globals', 'g', InputOption::VALUE_NONE, 'Include global variables.'),
|
||||
new InputOption('internal', 'n', InputOption::VALUE_NONE, 'Limit to internal functions and classes.'),
|
||||
new InputOption('user', 'u', InputOption::VALUE_NONE, 'Limit to user-defined constants, functions and classes.'),
|
||||
new InputOption('category', 'C', InputOption::VALUE_REQUIRED, 'Limit to constants in a specific category (e.g. "date").'),
|
||||
|
||||
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Include private and protected methods and properties.'),
|
||||
new InputOption('long', 'l', InputOption::VALUE_NONE, 'List in long format: includes class names and method signatures.'),
|
||||
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Include private and protected methods and properties.'),
|
||||
new InputOption('long', 'l', InputOption::VALUE_NONE, 'List in long format: includes class names and method signatures.'),
|
||||
])
|
||||
->setDescription('List local, instance or class variables, methods and constants.')
|
||||
->setHelp(
|
||||
@@ -111,6 +112,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -126,7 +129,7 @@ HELP
|
||||
}
|
||||
|
||||
// @todo something cleaner than this :-/
|
||||
if ($input->getOption('long')) {
|
||||
if ($output instanceof ShellOutput && $input->getOption('long')) {
|
||||
$output->startPaging();
|
||||
}
|
||||
|
||||
@@ -134,7 +137,7 @@ HELP
|
||||
$this->$method($output, $enumerator->enumerate($input, $reflector, $target));
|
||||
}
|
||||
|
||||
if ($input->getOption('long')) {
|
||||
if ($output instanceof ShellOutput && $input->getOption('long')) {
|
||||
$output->stopPaging();
|
||||
}
|
||||
|
||||
@@ -171,11 +174,11 @@ HELP
|
||||
* Write the list items to $output.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param null|array $result List of enumerated items
|
||||
* @param array $result List of enumerated items
|
||||
*/
|
||||
protected function write(OutputInterface $output, array $result = null)
|
||||
protected function write(OutputInterface $output, array $result)
|
||||
{
|
||||
if ($result === null) {
|
||||
if (\count($result) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -191,11 +194,11 @@ HELP
|
||||
* Items are listed one per line, and include the item signature.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param null|array $result List of enumerated items
|
||||
* @param array $result List of enumerated items
|
||||
*/
|
||||
protected function writeLong(OutputInterface $output, array $result = null)
|
||||
protected function writeLong(OutputInterface $output, array $result)
|
||||
{
|
||||
if ($result === null) {
|
||||
if (\count($result) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -225,7 +228,7 @@ HELP
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function formatItemName($item)
|
||||
private function formatItemName(array $item): string
|
||||
{
|
||||
return \sprintf('<%s>%s</%s>', $item['style'], OutputFormatter::escape($item['name']), $item['style']);
|
||||
}
|
||||
@@ -243,7 +246,7 @@ HELP
|
||||
// if no target is passed, there can be no properties or methods
|
||||
foreach (['properties', 'methods', 'no-inherit'] as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
throw new RuntimeException('--' . $option . ' does not make sense without a specified target');
|
||||
throw new RuntimeException('--'.$option.' does not make sense without a specified target');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,22 +260,23 @@ HELP
|
||||
$input->setOption('vars', true);
|
||||
} else {
|
||||
// if a target is passed, classes, functions, etc don't make sense
|
||||
foreach (['vars', 'globals', 'functions', 'classes', 'interfaces', 'traits'] as $option) {
|
||||
foreach (['vars', 'globals'] as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
throw new RuntimeException('--' . $option . ' does not make sense with a specified target');
|
||||
throw new RuntimeException('--'.$option.' does not make sense with a specified target');
|
||||
}
|
||||
}
|
||||
|
||||
foreach (['constants', 'properties', 'methods'] as $option) {
|
||||
// @todo ensure that 'functions', 'classes', 'interfaces', 'traits' only accept namespace target?
|
||||
foreach (['constants', 'properties', 'methods', 'functions', 'classes', 'interfaces', 'traits'] as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// default to --constants --properties --methods if no other options are passed
|
||||
$input->setOption('constants', true);
|
||||
$input->setOption('constants', true);
|
||||
$input->setOption('properties', true);
|
||||
$input->setOption('methods', true);
|
||||
$input->setOption('methods', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -22,30 +22,29 @@ class ClassConstantEnumerator extends Enumerator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
// only list constants when a Reflector is present.
|
||||
|
||||
if ($reflector === null) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// We can only list constants on actual class (or object) reflectors.
|
||||
if (!$reflector instanceof \ReflectionClass) {
|
||||
// @todo handle ReflectionExtension as well
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// only list constants if we are specifically asked
|
||||
if (!$input->getOption('constants')) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$noInherit = $input->getOption('no-inherit');
|
||||
$constants = $this->prepareConstants($this->getConstants($reflector, $noInherit));
|
||||
|
||||
if (empty($constants)) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$ret = [];
|
||||
@@ -62,7 +61,7 @@ class ClassConstantEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getConstants(\Reflector $reflector, $noInherit = false)
|
||||
protected function getConstants(\Reflector $reflector, bool $noInherit = false): array
|
||||
{
|
||||
$className = $reflector->getName();
|
||||
|
||||
@@ -77,7 +76,7 @@ class ClassConstantEnumerator extends Enumerator
|
||||
$constants[$name] = $constReflector;
|
||||
}
|
||||
|
||||
\ksort($constants, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
\ksort($constants, \SORT_NATURAL | \SORT_FLAG_CASE);
|
||||
|
||||
return $constants;
|
||||
}
|
||||
@@ -89,7 +88,7 @@ class ClassConstantEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareConstants(array $constants)
|
||||
protected function prepareConstants(array $constants): array
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = [];
|
||||
@@ -114,12 +113,10 @@ class ClassConstantEnumerator extends Enumerator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getKindLabel(\ReflectionClass $reflector)
|
||||
protected function getKindLabel(\ReflectionClass $reflector): string
|
||||
{
|
||||
if ($reflector->isInterface()) {
|
||||
return 'Interface Constants';
|
||||
} elseif (\method_exists($reflector, 'isTrait') && $reflector->isTrait()) {
|
||||
return 'Trait Constants';
|
||||
} else {
|
||||
return 'Class Constants';
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Psy\Command\ListCommand;
|
||||
|
||||
use Psy\Reflection\ReflectionNamespace;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
@@ -21,37 +22,31 @@ class ClassEnumerator extends Enumerator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
// only list classes when no Reflector is present.
|
||||
//
|
||||
// @todo make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --classes Foo
|
||||
//
|
||||
// ... for listing classes in the Foo namespace
|
||||
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
// if we have a reflector, ensure that it's a namespace reflector
|
||||
if (($target !== null || $reflector !== null) && !$reflector instanceof ReflectionNamespace) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$user = $input->getOption('user');
|
||||
$internal = $input->getOption('internal');
|
||||
$user = $input->getOption('user');
|
||||
$prefix = $reflector === null ? null : \strtolower($reflector->getName()).'\\';
|
||||
|
||||
$ret = [];
|
||||
|
||||
// only list classes, interfaces and traits if we are specifically asked
|
||||
|
||||
if ($input->getOption('classes')) {
|
||||
$ret = \array_merge($ret, $this->filterClasses('Classes', \get_declared_classes(), $internal, $user));
|
||||
$ret = \array_merge($ret, $this->filterClasses('Classes', \get_declared_classes(), $internal, $user, $prefix));
|
||||
}
|
||||
|
||||
if ($input->getOption('interfaces')) {
|
||||
$ret = \array_merge($ret, $this->filterClasses('Interfaces', \get_declared_interfaces(), $internal, $user));
|
||||
$ret = \array_merge($ret, $this->filterClasses('Interfaces', \get_declared_interfaces(), $internal, $user, $prefix));
|
||||
}
|
||||
|
||||
if ($input->getOption('traits')) {
|
||||
$ret = \array_merge($ret, $this->filterClasses('Traits', \get_declared_traits(), $internal, $user));
|
||||
$ret = \array_merge($ret, $this->filterClasses('Traits', \get_declared_traits(), $internal, $user, $prefix));
|
||||
}
|
||||
|
||||
return \array_map([$this, 'prepareClasses'], \array_filter($ret));
|
||||
@@ -67,15 +62,20 @@ class ClassEnumerator extends Enumerator
|
||||
* @param array $classes
|
||||
* @param bool $internal
|
||||
* @param bool $user
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function filterClasses($key, $classes, $internal, $user)
|
||||
protected function filterClasses(string $key, array $classes, bool $internal, bool $user, string $prefix = null): array
|
||||
{
|
||||
$ret = [];
|
||||
|
||||
if ($internal) {
|
||||
$ret['Internal ' . $key] = \array_filter($classes, function ($class) {
|
||||
$ret['Internal '.$key] = \array_filter($classes, function ($class) use ($prefix) {
|
||||
if ($prefix !== null && \strpos(\strtolower($class), $prefix) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$refl = new \ReflectionClass($class);
|
||||
|
||||
return $refl->isInternal();
|
||||
@@ -83,7 +83,11 @@ class ClassEnumerator extends Enumerator
|
||||
}
|
||||
|
||||
if ($user) {
|
||||
$ret['User ' . $key] = \array_filter($classes, function ($class) {
|
||||
$ret['User '.$key] = \array_filter($classes, function ($class) use ($prefix) {
|
||||
if ($prefix !== null && \strpos(\strtolower($class), $prefix) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$refl = new \ReflectionClass($class);
|
||||
|
||||
return !$refl->isInternal();
|
||||
@@ -91,7 +95,9 @@ class ClassEnumerator extends Enumerator
|
||||
}
|
||||
|
||||
if (!$user && !$internal) {
|
||||
$ret[$key] = $classes;
|
||||
$ret[$key] = \array_filter($classes, function ($class) use ($prefix) {
|
||||
return $prefix === null || \strpos(\strtolower($class), $prefix) === 0;
|
||||
});
|
||||
}
|
||||
|
||||
return $ret;
|
||||
@@ -104,7 +110,7 @@ class ClassEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareClasses(array $classes)
|
||||
protected function prepareClasses(array $classes): array
|
||||
{
|
||||
\natcasesort($classes);
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Psy\Command\ListCommand;
|
||||
|
||||
use Psy\Reflection\ReflectionNamespace;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
@@ -18,31 +19,64 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
*/
|
||||
class ConstantEnumerator extends Enumerator
|
||||
{
|
||||
// Because `Json` is ugly.
|
||||
private static $categoryLabels = [
|
||||
'libxml' => 'libxml',
|
||||
'openssl' => 'OpenSSL',
|
||||
'pcre' => 'PCRE',
|
||||
'sqlite3' => 'SQLite3',
|
||||
'curl' => 'cURL',
|
||||
'dom' => 'DOM',
|
||||
'ftp' => 'FTP',
|
||||
'gd' => 'GD',
|
||||
'gmp' => 'GMP',
|
||||
'iconv' => 'iconv',
|
||||
'json' => 'JSON',
|
||||
'ldap' => 'LDAP',
|
||||
'mbstring' => 'mbstring',
|
||||
'odbc' => 'ODBC',
|
||||
'pcntl' => 'PCNTL',
|
||||
'pgsql' => 'pgsql',
|
||||
'posix' => 'POSIX',
|
||||
'mysqli' => 'mysqli',
|
||||
'soap' => 'SOAP',
|
||||
'exif' => 'EXIF',
|
||||
'sysvmsg' => 'sysvmsg',
|
||||
'xml' => 'XML',
|
||||
'xsl' => 'XSL',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
// only list constants when no Reflector is present.
|
||||
//
|
||||
// @todo make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --constants Foo
|
||||
//
|
||||
// ... for listing constants in the Foo namespace
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
// if we have a reflector, ensure that it's a namespace reflector
|
||||
if (($target !== null || $reflector !== null) && !$reflector instanceof ReflectionNamespace) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// only list constants if we are specifically asked
|
||||
if (!$input->getOption('constants')) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$user = $input->getOption('user');
|
||||
$user = $input->getOption('user');
|
||||
$internal = $input->getOption('internal');
|
||||
$category = $input->getOption('category');
|
||||
|
||||
if ($category) {
|
||||
$category = \strtolower($category);
|
||||
|
||||
if ($category === 'internal') {
|
||||
$internal = true;
|
||||
$category = null;
|
||||
} elseif ($category === 'user') {
|
||||
$user = true;
|
||||
$category = null;
|
||||
}
|
||||
}
|
||||
|
||||
$ret = [];
|
||||
|
||||
if ($user) {
|
||||
@@ -50,11 +84,12 @@ class ConstantEnumerator extends Enumerator
|
||||
}
|
||||
|
||||
if ($internal) {
|
||||
$ret['Interal Constants'] = $this->getConstants('internal');
|
||||
$ret['Internal Constants'] = $this->getConstants('internal');
|
||||
}
|
||||
|
||||
if ($category) {
|
||||
$label = \ucfirst($category) . ' Constants';
|
||||
$caseCategory = \array_key_exists($category, self::$categoryLabels) ? self::$categoryLabels[$category] : \ucfirst($category);
|
||||
$label = $caseCategory.' Constants';
|
||||
$ret[$label] = $this->getConstants($category);
|
||||
}
|
||||
|
||||
@@ -62,6 +97,18 @@ class ConstantEnumerator extends Enumerator
|
||||
$ret['Constants'] = $this->getConstants();
|
||||
}
|
||||
|
||||
if ($reflector !== null) {
|
||||
$prefix = \strtolower($reflector->getName()).'\\';
|
||||
|
||||
foreach ($ret as $key => $names) {
|
||||
foreach (\array_keys($names) as $name) {
|
||||
if (\strpos(\strtolower($name), $prefix) !== 0) {
|
||||
unset($ret[$key][$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \array_map([$this, 'prepareConstants'], \array_filter($ret));
|
||||
}
|
||||
|
||||
@@ -75,7 +122,7 @@ class ConstantEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getConstants($category = null)
|
||||
protected function getConstants(string $category = null): array
|
||||
{
|
||||
if (!$category) {
|
||||
return \get_defined_constants();
|
||||
@@ -86,10 +133,16 @@ class ConstantEnumerator extends Enumerator
|
||||
if ($category === 'internal') {
|
||||
unset($consts['user']);
|
||||
|
||||
return \call_user_func_array('array_merge', $consts);
|
||||
return \array_merge(...\array_values($consts));
|
||||
}
|
||||
|
||||
return isset($consts[$category]) ? $consts[$category] : [];
|
||||
foreach ($consts as $key => $value) {
|
||||
if (\strtolower($key) === $category) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +152,7 @@ class ConstantEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareConstants(array $constants)
|
||||
protected function prepareConstants(array $constants): array
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = [];
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -23,13 +23,13 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
abstract class Enumerator
|
||||
{
|
||||
// Output styles
|
||||
const IS_PUBLIC = 'public';
|
||||
const IS_PUBLIC = 'public';
|
||||
const IS_PROTECTED = 'protected';
|
||||
const IS_PRIVATE = 'private';
|
||||
const IS_GLOBAL = 'global';
|
||||
const IS_CONSTANT = 'const';
|
||||
const IS_CLASS = 'class';
|
||||
const IS_FUNCTION = 'function';
|
||||
const IS_PRIVATE = 'private';
|
||||
const IS_GLOBAL = 'global';
|
||||
const IS_CONSTANT = 'const';
|
||||
const IS_CLASS = 'class';
|
||||
const IS_FUNCTION = 'function';
|
||||
|
||||
private $filter;
|
||||
private $presenter;
|
||||
@@ -48,13 +48,13 @@ abstract class Enumerator
|
||||
/**
|
||||
* Return a list of categorized things with the given input options and target.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param \Reflector $reflector
|
||||
* @param mixed $target
|
||||
* @param InputInterface $input
|
||||
* @param \Reflector|null $reflector
|
||||
* @param mixed $target
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function enumerate(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
public function enumerate(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
$this->filter->bind($input);
|
||||
|
||||
@@ -76,13 +76,13 @@ abstract class Enumerator
|
||||
* ],
|
||||
* ]
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param \Reflector $reflector
|
||||
* @param mixed $target
|
||||
* @param InputInterface $input
|
||||
* @param \Reflector|null $reflector
|
||||
* @param mixed $target
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null);
|
||||
abstract protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array;
|
||||
|
||||
protected function showItem($name)
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Psy\Command\ListCommand;
|
||||
|
||||
use Psy\Reflection\ReflectionNamespace;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
@@ -21,40 +22,34 @@ class FunctionEnumerator extends Enumerator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
// only list functions when no Reflector is present.
|
||||
//
|
||||
// @todo make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --functions Foo
|
||||
//
|
||||
// ... for listing functions in the Foo namespace
|
||||
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
// if we have a reflector, ensure that it's a namespace reflector
|
||||
if (($target !== null || $reflector !== null) && !$reflector instanceof ReflectionNamespace) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// only list functions if we are specifically asked
|
||||
if (!$input->getOption('functions')) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($input->getOption('user')) {
|
||||
$label = 'User Functions';
|
||||
$label = 'User Functions';
|
||||
$functions = $this->getFunctions('user');
|
||||
} elseif ($input->getOption('internal')) {
|
||||
$label = 'Internal Functions';
|
||||
$label = 'Internal Functions';
|
||||
$functions = $this->getFunctions('internal');
|
||||
} else {
|
||||
$label = 'Functions';
|
||||
$label = 'Functions';
|
||||
$functions = $this->getFunctions();
|
||||
}
|
||||
|
||||
$functions = $this->prepareFunctions($functions);
|
||||
$prefix = $reflector === null ? null : \strtolower($reflector->getName()).'\\';
|
||||
$functions = $this->prepareFunctions($functions, $prefix);
|
||||
|
||||
if (empty($functions)) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$ret = [];
|
||||
@@ -68,11 +63,11 @@ class FunctionEnumerator extends Enumerator
|
||||
*
|
||||
* Optionally limit functions to "user" or "internal" functions.
|
||||
*
|
||||
* @param null|string $type "user" or "internal" (default: both)
|
||||
* @param string|null $type "user" or "internal" (default: both)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFunctions($type = null)
|
||||
protected function getFunctions(string $type = null): array
|
||||
{
|
||||
$funcs = \get_defined_functions();
|
||||
|
||||
@@ -86,11 +81,12 @@ class FunctionEnumerator extends Enumerator
|
||||
/**
|
||||
* Prepare formatted function array.
|
||||
*
|
||||
* @param array $functions
|
||||
* @param array $functions
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareFunctions(array $functions)
|
||||
protected function prepareFunctions(array $functions, string $prefix = null): array
|
||||
{
|
||||
\natcasesort($functions);
|
||||
|
||||
@@ -98,12 +94,20 @@ class FunctionEnumerator extends Enumerator
|
||||
$ret = [];
|
||||
|
||||
foreach ($functions as $name) {
|
||||
if ($prefix !== null && \strpos(\strtolower($name), $prefix) !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = [
|
||||
'name' => $name,
|
||||
'style' => self::IS_FUNCTION,
|
||||
'value' => $this->presentSignature($name),
|
||||
];
|
||||
try {
|
||||
$ret[$name] = [
|
||||
'name' => $name,
|
||||
'style' => self::IS_FUNCTION,
|
||||
'value' => $this->presentSignature($name),
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
// Ignore failures.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,22 +21,22 @@ class GlobalVariableEnumerator extends Enumerator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
// only list globals when no Reflector is present.
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// only list globals if we are specifically asked
|
||||
if (!$input->getOption('globals')) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$globals = $this->prepareGlobals($this->getGlobals());
|
||||
|
||||
if (empty($globals)) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -49,7 +49,7 @@ class GlobalVariableEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getGlobals()
|
||||
protected function getGlobals(): array
|
||||
{
|
||||
global $GLOBALS;
|
||||
|
||||
@@ -71,14 +71,14 @@ class GlobalVariableEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareGlobals($globals)
|
||||
protected function prepareGlobals(array $globals): array
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = [];
|
||||
|
||||
foreach ($globals as $name => $value) {
|
||||
if ($this->showItem($name)) {
|
||||
$fname = '$' . $name;
|
||||
$fname = '$'.$name;
|
||||
$ret[$fname] = [
|
||||
'name' => $fname,
|
||||
'style' => self::IS_GLOBAL,
|
||||
|
@@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\Command\ListCommand;
|
||||
|
||||
use Psy\VarDumper\Presenter;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Interface Enumerator class.
|
||||
*
|
||||
* @deprecated Nothing should use this anymore
|
||||
*/
|
||||
class InterfaceEnumerator extends Enumerator
|
||||
{
|
||||
public function __construct(Presenter $presenter)
|
||||
{
|
||||
@\trigger_error('InterfaceEnumerator is no longer used', E_USER_DEPRECATED);
|
||||
parent::__construct($presenter);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list interfaces when no Reflector is present.
|
||||
//
|
||||
// @todo make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --interfaces Foo
|
||||
//
|
||||
// ... for listing interfaces in the Foo namespace
|
||||
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list interfaces if we are specifically asked
|
||||
if (!$input->getOption('interfaces')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$interfaces = $this->prepareInterfaces(\get_declared_interfaces());
|
||||
|
||||
if (empty($interfaces)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return [
|
||||
'Interfaces' => $interfaces,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted interface array.
|
||||
*
|
||||
* @param array $interfaces
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareInterfaces(array $interfaces)
|
||||
{
|
||||
\natcasesort($interfaces);
|
||||
|
||||
// My kingdom for a generator.
|
||||
$ret = [];
|
||||
|
||||
foreach ($interfaces as $name) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = [
|
||||
'name' => $name,
|
||||
'style' => self::IS_CLASS,
|
||||
'value' => $this->presentSignature($name),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,30 +21,29 @@ class MethodEnumerator extends Enumerator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
// only list methods when a Reflector is present.
|
||||
|
||||
if ($reflector === null) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// We can only list methods on actual class (or object) reflectors.
|
||||
if (!$reflector instanceof \ReflectionClass) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// only list methods if we are specifically asked
|
||||
if (!$input->getOption('methods')) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$showAll = $input->getOption('all');
|
||||
$showAll = $input->getOption('all');
|
||||
$noInherit = $input->getOption('no-inherit');
|
||||
$methods = $this->prepareMethods($this->getMethods($showAll, $reflector, $noInherit));
|
||||
$methods = $this->prepareMethods($this->getMethods($showAll, $reflector, $noInherit));
|
||||
|
||||
if (empty($methods)) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$ret = [];
|
||||
@@ -62,13 +61,15 @@ class MethodEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getMethods($showAll, \Reflector $reflector, $noInherit = false)
|
||||
protected function getMethods(bool $showAll, \Reflector $reflector, bool $noInherit = false): array
|
||||
{
|
||||
$className = $reflector->getName();
|
||||
|
||||
$methods = [];
|
||||
foreach ($reflector->getMethods() as $name => $method) {
|
||||
if ($noInherit && $method->getDeclaringClass()->getName() !== $className) {
|
||||
// For some reason PHP reflection shows private methods from the parent class, even
|
||||
// though they're effectively worthless. Let's suppress them here, like --no-inherit
|
||||
if (($noInherit || $method->isPrivate()) && $method->getDeclaringClass()->getName() !== $className) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -77,7 +78,7 @@ class MethodEnumerator extends Enumerator
|
||||
}
|
||||
}
|
||||
|
||||
\ksort($methods, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
\ksort($methods, \SORT_NATURAL | \SORT_FLAG_CASE);
|
||||
|
||||
return $methods;
|
||||
}
|
||||
@@ -89,7 +90,7 @@ class MethodEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareMethods(array $methods)
|
||||
protected function prepareMethods(array $methods): array
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = [];
|
||||
@@ -114,7 +115,7 @@ class MethodEnumerator extends Enumerator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getKindLabel(\ReflectionClass $reflector)
|
||||
protected function getKindLabel(\ReflectionClass $reflector): string
|
||||
{
|
||||
if ($reflector->isInterface()) {
|
||||
return 'Interface Methods';
|
||||
@@ -132,7 +133,7 @@ class MethodEnumerator extends Enumerator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getVisibilityStyle(\ReflectionMethod $method)
|
||||
private function getVisibilityStyle(\ReflectionMethod $method): string
|
||||
{
|
||||
if ($method->isPublic()) {
|
||||
return self::IS_PUBLIC;
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,30 +21,30 @@ class PropertyEnumerator extends Enumerator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
// only list properties when a Reflector is present.
|
||||
|
||||
if ($reflector === null) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// We can only list properties on actual class (or object) reflectors.
|
||||
if (!$reflector instanceof \ReflectionClass) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// only list properties if we are specifically asked
|
||||
if (!$input->getOption('properties')) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$showAll = $input->getOption('all');
|
||||
$noInherit = $input->getOption('no-inherit');
|
||||
$showAll = $input->getOption('all');
|
||||
$noInherit = $input->getOption('no-inherit');
|
||||
$properties = $this->prepareProperties($this->getProperties($showAll, $reflector, $noInherit), $target);
|
||||
|
||||
if (empty($properties)) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$ret = [];
|
||||
@@ -62,7 +62,7 @@ class PropertyEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getProperties($showAll, \Reflector $reflector, $noInherit = false)
|
||||
protected function getProperties(bool $showAll, \Reflector $reflector, bool $noInherit = false): array
|
||||
{
|
||||
$className = $reflector->getName();
|
||||
|
||||
@@ -77,7 +77,7 @@ class PropertyEnumerator extends Enumerator
|
||||
}
|
||||
}
|
||||
|
||||
\ksort($properties, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
\ksort($properties, \SORT_NATURAL | \SORT_FLAG_CASE);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
@@ -89,14 +89,14 @@ class PropertyEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareProperties(array $properties, $target = null)
|
||||
protected function prepareProperties(array $properties, $target = null): array
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = [];
|
||||
|
||||
foreach ($properties as $name => $property) {
|
||||
if ($this->showItem($name)) {
|
||||
$fname = '$' . $name;
|
||||
$fname = '$'.$name;
|
||||
$ret[$fname] = [
|
||||
'name' => $fname,
|
||||
'style' => $this->getVisibilityStyle($property),
|
||||
@@ -115,11 +115,9 @@ class PropertyEnumerator extends Enumerator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getKindLabel(\ReflectionClass $reflector)
|
||||
protected function getKindLabel(\ReflectionClass $reflector): string
|
||||
{
|
||||
if ($reflector->isInterface()) {
|
||||
return 'Interface Properties';
|
||||
} elseif (\method_exists($reflector, 'isTrait') && $reflector->isTrait()) {
|
||||
if (\method_exists($reflector, 'isTrait') && $reflector->isTrait()) {
|
||||
return 'Trait Properties';
|
||||
} else {
|
||||
return 'Class Properties';
|
||||
@@ -133,7 +131,7 @@ class PropertyEnumerator extends Enumerator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getVisibilityStyle(\ReflectionProperty $property)
|
||||
private function getVisibilityStyle(\ReflectionProperty $property): string
|
||||
{
|
||||
if ($property->isPublic()) {
|
||||
return self::IS_PUBLIC;
|
||||
@@ -152,9 +150,13 @@ class PropertyEnumerator extends Enumerator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function presentValue(\ReflectionProperty $property, $target)
|
||||
protected function presentValue(\ReflectionProperty $property, $target): string
|
||||
{
|
||||
// If $target is a class, trait or interface (try to) get the default
|
||||
if (!$target) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// If $target is a class or trait (try to) get the default
|
||||
// value for the property.
|
||||
if (!\is_object($target)) {
|
||||
try {
|
||||
@@ -163,9 +165,9 @@ class PropertyEnumerator extends Enumerator
|
||||
if (\array_key_exists($property->name, $props)) {
|
||||
$suffix = $property->isStatic() ? '' : ' <aside>(default)</aside>';
|
||||
|
||||
return $this->presentRef($props[$property->name]) . $suffix;
|
||||
return $this->presentRef($props[$property->name]).$suffix;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
// Well, we gave it a shot.
|
||||
}
|
||||
|
||||
|
@@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\Command\ListCommand;
|
||||
|
||||
use Psy\VarDumper\Presenter;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Trait Enumerator class.
|
||||
*
|
||||
* @deprecated Nothing should use this anymore
|
||||
*/
|
||||
class TraitEnumerator extends Enumerator
|
||||
{
|
||||
public function __construct(Presenter $presenter)
|
||||
{
|
||||
@\trigger_error('TraitEnumerator is no longer used', E_USER_DEPRECATED);
|
||||
parent::__construct($presenter);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list traits when no Reflector is present.
|
||||
//
|
||||
// @todo make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --traits Foo
|
||||
//
|
||||
// ... for listing traits in the Foo namespace
|
||||
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list traits if we are specifically asked
|
||||
if (!$input->getOption('traits')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$traits = $this->prepareTraits(\get_declared_traits());
|
||||
|
||||
if (empty($traits)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return [
|
||||
'Traits' => $traits,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted trait array.
|
||||
*
|
||||
* @param array $traits
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareTraits(array $traits)
|
||||
{
|
||||
\natcasesort($traits);
|
||||
|
||||
// My kingdom for a generator.
|
||||
$ret = [];
|
||||
|
||||
foreach ($traits as $name) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = [
|
||||
'name' => $name,
|
||||
'style' => self::IS_CLASS,
|
||||
'value' => $this->presentSignature($name),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -45,23 +45,23 @@ class VariableEnumerator extends Enumerator
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
|
||||
{
|
||||
// only list variables when no Reflector is present.
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// only list variables if we are specifically asked
|
||||
if (!$input->getOption('vars')) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
$showAll = $input->getOption('all');
|
||||
$showAll = $input->getOption('all');
|
||||
$variables = $this->prepareVariables($this->getVariables($showAll));
|
||||
|
||||
if (empty($variables)) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -76,7 +76,7 @@ class VariableEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getVariables($showAll)
|
||||
protected function getVariables(bool $showAll): array
|
||||
{
|
||||
$scopeVars = $this->context->getAll();
|
||||
\uksort($scopeVars, function ($a, $b) {
|
||||
@@ -117,13 +117,13 @@ class VariableEnumerator extends Enumerator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareVariables(array $variables)
|
||||
protected function prepareVariables(array $variables): array
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = [];
|
||||
foreach ($variables as $name => $val) {
|
||||
if ($this->showItem($name)) {
|
||||
$fname = '$' . $name;
|
||||
$fname = '$'.$name;
|
||||
$ret[$fname] = [
|
||||
'name' => $fname,
|
||||
'style' => \in_array($name, self::$specialNames) ? self::IS_PRIVATE : self::IS_PUBLIC,
|
||||
|
50
vendor/psy/psysh/src/Command/ParseCommand.php
vendored
50
vendor/psy/psysh/src/Command/ParseCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -46,7 +46,7 @@ class ParseCommand extends Command implements ContextAware, PresenterAware
|
||||
public function __construct($name = null)
|
||||
{
|
||||
$this->parserFactory = new ParserFactory();
|
||||
$this->parsers = [];
|
||||
$this->parsers = [];
|
||||
|
||||
parent::__construct($name);
|
||||
}
|
||||
@@ -70,14 +70,14 @@ class ParseCommand extends Command implements ContextAware, PresenterAware
|
||||
{
|
||||
$this->presenter = clone $presenter;
|
||||
$this->presenter->addCasters([
|
||||
'PhpParser\Node' => function (Node $node, array $a) {
|
||||
Node::class => function (Node $node, array $a) {
|
||||
$a = [
|
||||
Caster::PREFIX_VIRTUAL . 'type' => $node->getType(),
|
||||
Caster::PREFIX_VIRTUAL . 'attributes' => $node->getAttributes(),
|
||||
Caster::PREFIX_VIRTUAL.'type' => $node->getType(),
|
||||
Caster::PREFIX_VIRTUAL.'attributes' => $node->getAttributes(),
|
||||
];
|
||||
|
||||
foreach ($node->getSubNodeNames() as $name) {
|
||||
$a[Caster::PREFIX_VIRTUAL . $name] = $node->$name;
|
||||
$a[Caster::PREFIX_VIRTUAL.$name] = $node->$name;
|
||||
}
|
||||
|
||||
return $a;
|
||||
@@ -90,23 +90,17 @@ class ParseCommand extends Command implements ContextAware, PresenterAware
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$definition = [
|
||||
new CodeArgument('code', CodeArgument::REQUIRED, 'PHP code to parse.'),
|
||||
new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse.', 10),
|
||||
];
|
||||
|
||||
if ($this->parserFactory->hasKindsSupport()) {
|
||||
$msg = 'One of PhpParser\\ParserFactory constants: '
|
||||
. \implode(', ', ParserFactory::getPossibleKinds())
|
||||
. " (default is based on current interpreter's version).";
|
||||
$defaultKind = $this->parserFactory->getDefaultKind();
|
||||
|
||||
$definition[] = new InputOption('kind', '', InputOption::VALUE_REQUIRED, $msg, $defaultKind);
|
||||
}
|
||||
$kindMsg = 'One of PhpParser\\ParserFactory constants: '
|
||||
.\implode(', ', ParserFactory::getPossibleKinds())
|
||||
." (default is based on current interpreter's version).";
|
||||
|
||||
$this
|
||||
->setName('parse')
|
||||
->setDefinition($definition)
|
||||
->setDefinition([
|
||||
new CodeArgument('code', CodeArgument::REQUIRED, 'PHP code to parse.'),
|
||||
new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse.', 10),
|
||||
new InputOption('kind', '', InputOption::VALUE_REQUIRED, $kindMsg, $this->parserFactory->getDefaultKind()),
|
||||
])
|
||||
->setDescription('Parse PHP code and show the abstract syntax tree.')
|
||||
->setHelp(
|
||||
<<<'HELP'
|
||||
@@ -128,13 +122,13 @@ HELP
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$code = $input->getArgument('code');
|
||||
if (\strpos('<?', $code) === false) {
|
||||
$code = '<?php ' . $code;
|
||||
if (\strpos($code, '<?') === false) {
|
||||
$code = '<?php '.$code;
|
||||
}
|
||||
|
||||
$parserKind = $this->parserFactory->hasKindsSupport() ? $input->getOption('kind') : null;
|
||||
$depth = $input->getOption('depth');
|
||||
$nodes = $this->parse($this->getParser($parserKind), $code);
|
||||
$parserKind = $input->getOption('kind');
|
||||
$depth = $input->getOption('depth');
|
||||
$nodes = $this->parse($this->getParser($parserKind), $code);
|
||||
$output->page($this->presenter->present($nodes, $depth));
|
||||
|
||||
$this->context->setReturnValue($nodes);
|
||||
@@ -150,7 +144,7 @@ HELP
|
||||
*
|
||||
* @return array Statements
|
||||
*/
|
||||
private function parse(Parser $parser, $code)
|
||||
private function parse(Parser $parser, string $code): array
|
||||
{
|
||||
try {
|
||||
return $parser->parse($code);
|
||||
@@ -160,7 +154,7 @@ HELP
|
||||
}
|
||||
|
||||
// If we got an unexpected EOF, let's try it again with a semicolon.
|
||||
return $parser->parse($code . ';');
|
||||
return $parser->parse($code.';');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +165,7 @@ HELP
|
||||
*
|
||||
* @return Parser
|
||||
*/
|
||||
private function getParser($kind = null)
|
||||
private function getParser(string $kind = null): Parser
|
||||
{
|
||||
if (!\array_key_exists($kind, $this->parsers)) {
|
||||
$this->parsers[$kind] = $this->parserFactory->createParser($kind);
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -16,6 +16,9 @@ use Psy\Context;
|
||||
use Psy\ContextAware;
|
||||
use Psy\Exception\ErrorException;
|
||||
use Psy\Exception\RuntimeException;
|
||||
use Psy\Exception\UnexpectedTargetException;
|
||||
use Psy\Reflection\ReflectionClassConstant;
|
||||
use Psy\Reflection\ReflectionConstant_;
|
||||
use Psy\Util\Mirror;
|
||||
|
||||
/**
|
||||
@@ -23,9 +26,9 @@ use Psy\Util\Mirror;
|
||||
*/
|
||||
abstract class ReflectingCommand extends Command implements ContextAware
|
||||
{
|
||||
const CLASS_OR_FUNC = '/^[\\\\\w]+$/';
|
||||
const CLASS_MEMBER = '/^([\\\\\w]+)::(\w+)$/';
|
||||
const CLASS_STATIC = '/^([\\\\\w]+)::\$(\w+)$/';
|
||||
const CLASS_OR_FUNC = '/^[\\\\\w]+$/';
|
||||
const CLASS_MEMBER = '/^([\\\\\w]+)::(\w+)$/';
|
||||
const CLASS_STATIC = '/^([\\\\\w]+)::\$(\w+)$/';
|
||||
const INSTANCE_MEMBER = '/^(\$\w+)(::|->)(\w+)$/';
|
||||
|
||||
/**
|
||||
@@ -54,10 +57,10 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
*
|
||||
* @return array (class or instance name, member name, kind)
|
||||
*/
|
||||
protected function getTarget($valueName)
|
||||
protected function getTarget(string $valueName): array
|
||||
{
|
||||
$valueName = \trim($valueName);
|
||||
$matches = [];
|
||||
$matches = [];
|
||||
switch (true) {
|
||||
case \preg_match(self::CLASS_OR_FUNC, $valueName, $matches):
|
||||
return [$this->resolveName($matches[0], true), null, 0];
|
||||
@@ -92,7 +95,7 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveName($name, $includeFunctions = false)
|
||||
protected function resolveName(string $name, bool $includeFunctions = false): string
|
||||
{
|
||||
$shell = $this->getApplication();
|
||||
|
||||
@@ -107,15 +110,24 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
}
|
||||
|
||||
$msg = \sprintf('Cannot use "%s" when no class scope is active', \strtolower($name));
|
||||
throw new ErrorException($msg, 0, E_USER_ERROR, "eval()'d code", 1);
|
||||
throw new ErrorException($msg, 0, \E_USER_ERROR, "eval()'d code", 1);
|
||||
}
|
||||
|
||||
if (\substr($name, 0, 1) === '\\') {
|
||||
return $name;
|
||||
}
|
||||
|
||||
// Check $name against the current namespace and use statements.
|
||||
if (self::couldBeClassName($name)) {
|
||||
try {
|
||||
$name = $this->resolveCode($name.'::class');
|
||||
} catch (RuntimeException $e) {
|
||||
// /shrug
|
||||
}
|
||||
}
|
||||
|
||||
if ($namespace = $shell->getNamespace()) {
|
||||
$fullName = $namespace . '\\' . $name;
|
||||
$fullName = $namespace.'\\'.$name;
|
||||
|
||||
if (\class_exists($fullName) || \interface_exists($fullName) || ($includeFunctions && \function_exists($fullName))) {
|
||||
return $fullName;
|
||||
@@ -125,6 +137,15 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given name could be a class name.
|
||||
*/
|
||||
protected function couldBeClassName(string $name): bool
|
||||
{
|
||||
// Regex based on https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class
|
||||
return \preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*(\\\\[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)*$/', $name) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Reflector and documentation for a function, class or instance, constant, method or property.
|
||||
*
|
||||
@@ -132,7 +153,7 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
*
|
||||
* @return array (value, Reflector)
|
||||
*/
|
||||
protected function getTargetAndReflector($valueName)
|
||||
protected function getTargetAndReflector(string $valueName): array
|
||||
{
|
||||
list($value, $member, $kind) = $this->getTarget($valueName);
|
||||
|
||||
@@ -148,16 +169,16 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
*
|
||||
* @return mixed Variable value
|
||||
*/
|
||||
protected function resolveCode($code)
|
||||
protected function resolveCode(string $code)
|
||||
{
|
||||
try {
|
||||
$value = $this->getApplication()->execute($code, true);
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
// Swallow all exceptions?
|
||||
}
|
||||
|
||||
if (!isset($value) || $value instanceof NoReturnValue) {
|
||||
throw new RuntimeException('Unknown target: ' . $code);
|
||||
throw new RuntimeException('Unknown target: '.$code);
|
||||
}
|
||||
|
||||
return $value;
|
||||
@@ -166,18 +187,18 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
/**
|
||||
* Resolve code to an object in the current scope.
|
||||
*
|
||||
* @throws RuntimeException when the code resolves to a non-object value
|
||||
* @throws UnexpectedTargetException when the code resolves to a non-object value
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return object Variable instance
|
||||
*/
|
||||
private function resolveObject($code)
|
||||
private function resolveObject(string $code)
|
||||
{
|
||||
$value = $this->resolveCode($code);
|
||||
|
||||
if (!\is_object($value)) {
|
||||
throw new RuntimeException('Unable to inspect a non-object');
|
||||
throw new UnexpectedTargetException($value, 'Unable to inspect a non-object');
|
||||
}
|
||||
|
||||
return $value;
|
||||
@@ -190,9 +211,9 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
*
|
||||
* @return mixed Variable instance
|
||||
*/
|
||||
protected function resolveInstance($name)
|
||||
protected function resolveInstance(string $name)
|
||||
{
|
||||
@\trigger_error('`resolveInstance` is deprecated; use `resolveCode` instead.', E_USER_DEPRECATED);
|
||||
@\trigger_error('`resolveInstance` is deprecated; use `resolveCode` instead.', \E_USER_DEPRECATED);
|
||||
|
||||
return $this->resolveCode($name);
|
||||
}
|
||||
@@ -204,7 +225,7 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getScopeVariable($name)
|
||||
protected function getScopeVariable(string $name)
|
||||
{
|
||||
return $this->context->get($name);
|
||||
}
|
||||
@@ -214,7 +235,7 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getScopeVariables()
|
||||
protected function getScopeVariables(): array
|
||||
{
|
||||
return $this->context->getAll();
|
||||
}
|
||||
@@ -231,15 +252,15 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
$vars = [];
|
||||
|
||||
switch (\get_class($reflector)) {
|
||||
case 'ReflectionClass':
|
||||
case 'ReflectionObject':
|
||||
case \ReflectionClass::class:
|
||||
case \ReflectionObject::class:
|
||||
$vars['__class'] = $reflector->name;
|
||||
if ($reflector->inNamespace()) {
|
||||
$vars['__namespace'] = $reflector->getNamespaceName();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ReflectionMethod':
|
||||
case \ReflectionMethod::class:
|
||||
$vars['__method'] = \sprintf('%s::%s', $reflector->class, $reflector->name);
|
||||
$vars['__class'] = $reflector->class;
|
||||
$classReflector = $reflector->getDeclaringClass();
|
||||
@@ -248,14 +269,14 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ReflectionFunction':
|
||||
case \ReflectionFunction::class:
|
||||
$vars['__function'] = $reflector->name;
|
||||
if ($reflector->inNamespace()) {
|
||||
$vars['__namespace'] = $reflector->getNamespaceName();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ReflectionGenerator':
|
||||
case \ReflectionGenerator::class:
|
||||
$funcReflector = $reflector->getFunction();
|
||||
$vars['__function'] = $funcReflector->name;
|
||||
if ($funcReflector->inNamespace()) {
|
||||
@@ -264,13 +285,13 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
if ($fileName = $reflector->getExecutingFile()) {
|
||||
$vars['__file'] = $fileName;
|
||||
$vars['__line'] = $reflector->getExecutingLine();
|
||||
$vars['__dir'] = \dirname($fileName);
|
||||
$vars['__dir'] = \dirname($fileName);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ReflectionProperty':
|
||||
case 'ReflectionClassConstant':
|
||||
case 'Psy\Reflection\ReflectionClassConstant':
|
||||
case \ReflectionProperty::class:
|
||||
case \ReflectionClassConstant::class:
|
||||
case ReflectionClassConstant::class:
|
||||
$classReflector = $reflector->getDeclaringClass();
|
||||
$vars['__class'] = $classReflector->name;
|
||||
if ($classReflector->inNamespace()) {
|
||||
@@ -279,11 +300,11 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
// no line for these, but this'll do
|
||||
if ($fileName = $reflector->getDeclaringClass()->getFileName()) {
|
||||
$vars['__file'] = $fileName;
|
||||
$vars['__dir'] = \dirname($fileName);
|
||||
$vars['__dir'] = \dirname($fileName);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Psy\Reflection\ReflectionConstant_':
|
||||
case ReflectionConstant_::class:
|
||||
if ($reflector->inNamespace()) {
|
||||
$vars['__namespace'] = $reflector->getNamespaceName();
|
||||
}
|
||||
@@ -294,7 +315,7 @@ abstract class ReflectingCommand extends Command implements ContextAware
|
||||
if ($fileName = $reflector->getFileName()) {
|
||||
$vars['__file'] = $fileName;
|
||||
$vars['__line'] = $reflector->getStartLine();
|
||||
$vars['__dir'] = \dirname($fileName);
|
||||
$vars['__dir'] = \dirname($fileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
69
vendor/psy/psysh/src/Command/ShowCommand.php
vendored
69
vendor/psy/psysh/src/Command/ShowCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,10 +11,8 @@
|
||||
|
||||
namespace Psy\Command;
|
||||
|
||||
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
|
||||
use Psy\Configuration;
|
||||
use Psy\ConsoleColorFactory;
|
||||
use Psy\Exception\RuntimeException;
|
||||
use Psy\Exception\UnexpectedTargetException;
|
||||
use Psy\Formatter\CodeFormatter;
|
||||
use Psy\Formatter\SignatureFormatter;
|
||||
use Psy\Input\CodeArgument;
|
||||
@@ -28,18 +26,14 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
*/
|
||||
class ShowCommand extends ReflectingCommand
|
||||
{
|
||||
private $colorMode;
|
||||
private $highlighter;
|
||||
private $lastException;
|
||||
private $lastExceptionIndex;
|
||||
|
||||
/**
|
||||
* @param null|string $colorMode (default: null)
|
||||
* @param string|null $colorMode (deprecated and ignored)
|
||||
*/
|
||||
public function __construct($colorMode = null)
|
||||
{
|
||||
$this->colorMode = $colorMode ?: Configuration::COLOR_MODE_AUTO;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@@ -52,7 +46,7 @@ class ShowCommand extends ReflectingCommand
|
||||
->setName('show')
|
||||
->setDefinition([
|
||||
new CodeArgument('target', CodeArgument::OPTIONAL, 'Function, class, instance, constant, method or property to show.'),
|
||||
new InputOption('ex', null, InputOption::VALUE_OPTIONAL, 'Show last exception context. Optionally specify a stack index.', 1),
|
||||
new InputOption('ex', null, InputOption::VALUE_OPTIONAL, 'Show last exception context. Optionally specify a stack index.', 1),
|
||||
])
|
||||
->setDescription('Show the code for an object, class, constant, method or property.')
|
||||
->setHelp(
|
||||
@@ -75,6 +69,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -114,13 +110,33 @@ HELP
|
||||
|
||||
private function writeCodeContext(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
list($target, $reflector) = $this->getTargetAndReflector($input->getArgument('target'));
|
||||
try {
|
||||
list($target, $reflector) = $this->getTargetAndReflector($input->getArgument('target'));
|
||||
} catch (UnexpectedTargetException $e) {
|
||||
// If we didn't get a target and Reflector, maybe we got a filename?
|
||||
$target = $e->getTarget();
|
||||
if (\is_string($target) && \is_file($target) && $code = @\file_get_contents($target)) {
|
||||
$file = \realpath($target);
|
||||
if ($file !== $this->context->get('__file')) {
|
||||
$this->context->setCommandScopeVariables([
|
||||
'__file' => $file,
|
||||
'__dir' => \dirname($file),
|
||||
]);
|
||||
}
|
||||
|
||||
$output->page(CodeFormatter::formatCode($code));
|
||||
|
||||
return;
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
// Set some magic local variables
|
||||
$this->setCommandScopeVariables($reflector);
|
||||
|
||||
try {
|
||||
$output->page(CodeFormatter::format($reflector, $this->colorMode), OutputInterface::OUTPUT_RAW);
|
||||
$output->page(CodeFormatter::format($reflector));
|
||||
} catch (RuntimeException $e) {
|
||||
$output->writeln(SignatureFormatter::format($reflector));
|
||||
throw $e;
|
||||
@@ -143,7 +159,7 @@ HELP
|
||||
$index = 0;
|
||||
}
|
||||
} else {
|
||||
$index = \max(0, \intval($input->getOption('ex')) - 1);
|
||||
$index = \max(0, (int) $input->getOption('ex') - 1);
|
||||
}
|
||||
|
||||
$trace = $exception->getTrace();
|
||||
@@ -173,7 +189,7 @@ HELP
|
||||
$line = isset($trace[$index]['line']) ? $trace[$index]['line'] : 'n/a';
|
||||
|
||||
$output->writeln(\sprintf(
|
||||
'From <info>%s:%d</info> at <strong>level %d</strong> of backtrace (of %d).',
|
||||
'From <info>%s:%d</info> at <strong>level %d</strong> of backtrace (of %d):',
|
||||
OutputFormatter::escape($file),
|
||||
OutputFormatter::escape($line),
|
||||
$index + 1,
|
||||
@@ -181,16 +197,16 @@ HELP
|
||||
));
|
||||
}
|
||||
|
||||
private function replaceCwd($file)
|
||||
private function replaceCwd(string $file): string
|
||||
{
|
||||
if ($cwd = \getcwd()) {
|
||||
$cwd = \rtrim($cwd, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
$cwd = \rtrim($cwd, \DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
if ($cwd === false) {
|
||||
return $file;
|
||||
} else {
|
||||
return \preg_replace('/^' . \preg_quote($cwd, '/') . '/', '', $file);
|
||||
return \preg_replace('/^'.\preg_quote($cwd, '/').'/', '', $file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,17 +235,10 @@ HELP
|
||||
return;
|
||||
}
|
||||
|
||||
$output->write($this->getHighlighter()->getCodeSnippet($code, $line, 5, 5), false, OutputInterface::OUTPUT_RAW);
|
||||
}
|
||||
$startLine = \max($line - 5, 0);
|
||||
$endLine = $line + 5;
|
||||
|
||||
private function getHighlighter()
|
||||
{
|
||||
if (!$this->highlighter) {
|
||||
$factory = new ConsoleColorFactory($this->colorMode);
|
||||
$this->highlighter = new Highlighter($factory->getConsoleColor());
|
||||
}
|
||||
|
||||
return $this->highlighter;
|
||||
$output->write(CodeFormatter::formatCode($code, $startLine, $endLine, $line), false);
|
||||
}
|
||||
|
||||
private function setCommandScopeVariablesFromContext(array $context)
|
||||
@@ -247,7 +256,7 @@ HELP
|
||||
if ($namespace = $refl->getNamespaceName()) {
|
||||
$vars['__namespace'] = $namespace;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
// oh well
|
||||
}
|
||||
} elseif (isset($context['function'])) {
|
||||
@@ -258,7 +267,7 @@ HELP
|
||||
if ($namespace = $refl->getNamespaceName()) {
|
||||
$vars['__namespace'] = $namespace;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
// oh well
|
||||
}
|
||||
}
|
||||
@@ -283,7 +292,7 @@ HELP
|
||||
$this->context->setCommandScopeVariables($vars);
|
||||
}
|
||||
|
||||
private function extractEvalFileAndLine($file)
|
||||
private function extractEvalFileAndLine(string $file)
|
||||
{
|
||||
if (\preg_match('/(.*)\\((\\d+)\\) : eval\\(\\)\'d code$/', $file, $matches)) {
|
||||
return [$matches[1], $matches[2]];
|
||||
|
12
vendor/psy/psysh/src/Command/SudoCommand.php
vendored
12
vendor/psy/psysh/src/Command/SudoCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -95,6 +95,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -109,8 +111,8 @@ HELP
|
||||
$code = $history[\count($history) - 2];
|
||||
}
|
||||
|
||||
if (\strpos('<?', $code) === false) {
|
||||
$code = '<?php ' . $code;
|
||||
if (\strpos($code, '<?') === false) {
|
||||
$code = '<?php '.$code;
|
||||
}
|
||||
|
||||
$nodes = $this->traverser->traverse($this->parse($code));
|
||||
@@ -129,7 +131,7 @@ HELP
|
||||
*
|
||||
* @return array Statements
|
||||
*/
|
||||
private function parse($code)
|
||||
private function parse(string $code): array
|
||||
{
|
||||
try {
|
||||
return $this->parser->parse($code);
|
||||
@@ -139,7 +141,7 @@ HELP
|
||||
}
|
||||
|
||||
// If we got an unexpected EOF, let's try it again with a semicolon.
|
||||
return $this->parser->parse($code . ';');
|
||||
return $this->parser->parse($code.';');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
vendor/psy/psysh/src/Command/ThrowUpCommand.php
vendored
39
vendor/psy/psysh/src/Command/ThrowUpCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -13,7 +13,6 @@ namespace Psy\Command;
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
@@ -21,6 +20,7 @@ use PhpParser\Node\Stmt\Throw_;
|
||||
use PhpParser\PrettyPrinter\Standard as Printer;
|
||||
use Psy\Context;
|
||||
use Psy\ContextAware;
|
||||
use Psy\Exception\ThrowUpException;
|
||||
use Psy\Input\CodeArgument;
|
||||
use Psy\ParserFactory;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -31,18 +31,9 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
*/
|
||||
class ThrowUpCommand extends Command implements ContextAware
|
||||
{
|
||||
const THROW_CLASS = 'Psy\Exception\ThrowUpException';
|
||||
|
||||
private $parser;
|
||||
private $printer;
|
||||
|
||||
/**
|
||||
* Context instance (for ContextAware interface).
|
||||
*
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -50,20 +41,20 @@ class ThrowUpCommand extends Command implements ContextAware
|
||||
{
|
||||
$parserFactory = new ParserFactory();
|
||||
|
||||
$this->parser = $parserFactory->createParser();
|
||||
$this->parser = $parserFactory->createParser();
|
||||
$this->printer = new Printer();
|
||||
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* ContextAware interface.
|
||||
* @deprecated throwUp no longer needs to be ContextAware
|
||||
*
|
||||
* @param Context $context
|
||||
*/
|
||||
public function setContext(Context $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,12 +86,14 @@ HELP
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws InvalidArgumentException if there is no exception to throw
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*
|
||||
* @throws \InvalidArgumentException if there is no exception to throw
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$args = $this->prepareArgs($input->getArgument('exception'));
|
||||
$throwStmt = new Throw_(new StaticCall(new FullyQualifiedName(self::THROW_CLASS), 'fromThrowable', $args));
|
||||
$throwStmt = new Throw_(new New_(new FullyQualifiedName(ThrowUpException::class), $args));
|
||||
$throwCode = $this->printer->prettyPrint([$throwStmt]);
|
||||
|
||||
$shell = $this->getApplication();
|
||||
@@ -114,21 +107,21 @@ HELP
|
||||
*
|
||||
* If no argument was given, this falls back to `$_e`
|
||||
*
|
||||
* @throws InvalidArgumentException if there is no exception to throw
|
||||
* @throws \InvalidArgumentException if there is no exception to throw
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return Arg[]
|
||||
*/
|
||||
private function prepareArgs($code = null)
|
||||
private function prepareArgs(string $code = null): array
|
||||
{
|
||||
if (!$code) {
|
||||
// Default to last exception if nothing else was supplied
|
||||
return [new Arg(new Variable('_e'))];
|
||||
}
|
||||
|
||||
if (\strpos('<?', $code) === false) {
|
||||
$code = '<?php ' . $code;
|
||||
if (\strpos($code, '<?') === false) {
|
||||
$code = '<?php '.$code;
|
||||
}
|
||||
|
||||
$nodes = $this->parse($code);
|
||||
@@ -145,7 +138,7 @@ HELP
|
||||
|
||||
// Allow throwing via a string, e.g. `throw-up "SUP"`
|
||||
if ($expr instanceof String_) {
|
||||
return [new New_(new FullyQualifiedName('Exception'), $args)];
|
||||
return [new New_(new FullyQualifiedName(\Exception::class), $args)];
|
||||
}
|
||||
|
||||
return $args;
|
||||
@@ -158,7 +151,7 @@ HELP
|
||||
*
|
||||
* @return array Statements
|
||||
*/
|
||||
private function parse($code)
|
||||
private function parse(string $code): array
|
||||
{
|
||||
try {
|
||||
return $this->parser->parse($code);
|
||||
@@ -168,7 +161,7 @@ HELP
|
||||
}
|
||||
|
||||
// If we got an unexpected EOF, let's try it again with a semicolon.
|
||||
return $this->parser->parse($code . ';');
|
||||
return $this->parser->parse($code.';');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
14
vendor/psy/psysh/src/Command/TimeitCommand.php
vendored
14
vendor/psy/psysh/src/Command/TimeitCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -25,7 +25,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
*/
|
||||
class TimeitCommand extends Command
|
||||
{
|
||||
const RESULT_MSG = '<info>Command took %.6f seconds to complete.</info>';
|
||||
const RESULT_MSG = '<info>Command took %.6f seconds to complete.</info>';
|
||||
const AVG_RESULT_MSG = '<info>Command took %.6f seconds on average (%.6f median; %.6f total) to complete.</info>';
|
||||
|
||||
private static $start = null;
|
||||
@@ -76,6 +76,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -167,7 +169,7 @@ HELP
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function instrumentCode($code)
|
||||
private function instrumentCode(string $code): string
|
||||
{
|
||||
return $this->printer->prettyPrint($this->traverser->traverse($this->parse($code)));
|
||||
}
|
||||
@@ -179,9 +181,9 @@ HELP
|
||||
*
|
||||
* @return array Statements
|
||||
*/
|
||||
private function parse($code)
|
||||
private function parse(string $code): array
|
||||
{
|
||||
$code = '<?php ' . $code;
|
||||
$code = '<?php '.$code;
|
||||
|
||||
try {
|
||||
return $this->parser->parse($code);
|
||||
@@ -191,7 +193,7 @@ HELP
|
||||
}
|
||||
|
||||
// If we got an unexpected EOF, let's try it again with a semicolon.
|
||||
return $this->parser->parse($code . ';');
|
||||
return $this->parser->parse($code.';');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,6 +21,7 @@ use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use Psy\CodeCleaner\NoReturnValue;
|
||||
use Psy\Command\TimeitCommand;
|
||||
|
||||
/**
|
||||
* A node visitor for instrumenting code to be executed by the `timeit` command.
|
||||
@@ -34,6 +35,8 @@ class TimeitVisitor extends NodeVisitorAbstract
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
@@ -42,6 +45,8 @@ class TimeitVisitor extends NodeVisitorAbstract
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int|Node|null Replacement node (or special return value)
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
@@ -61,6 +66,8 @@ class TimeitVisitor extends NodeVisitorAbstract
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int|Node|Node[]|null Replacement node (or special return value)
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
@@ -71,6 +78,8 @@ class TimeitVisitor extends NodeVisitorAbstract
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return Node[]|null Array of nodes
|
||||
*/
|
||||
public function afterTraverse(array $nodes)
|
||||
{
|
||||
@@ -97,11 +106,11 @@ class TimeitVisitor extends NodeVisitorAbstract
|
||||
/**
|
||||
* Get PhpParser AST nodes for a `markStart` call.
|
||||
*
|
||||
* @return PhpParser\Node\Expr\StaticCall
|
||||
* @return \PhpParser\Node\Expr\StaticCall
|
||||
*/
|
||||
private function getStartCall()
|
||||
private function getStartCall(): StaticCall
|
||||
{
|
||||
return new StaticCall(new FullyQualifiedName('Psy\Command\TimeitCommand'), 'markStart');
|
||||
return new StaticCall(new FullyQualifiedName(TimeitCommand::class), 'markStart');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,15 +120,15 @@ class TimeitVisitor extends NodeVisitorAbstract
|
||||
*
|
||||
* @param Expr|null $arg
|
||||
*
|
||||
* @return PhpParser\Node\Expr\StaticCall
|
||||
* @return \PhpParser\Node\Expr\StaticCall
|
||||
*/
|
||||
private function getEndCall(Expr $arg = null)
|
||||
private function getEndCall(Expr $arg = null): StaticCall
|
||||
{
|
||||
if ($arg === null) {
|
||||
$arg = NoReturnValue::create();
|
||||
}
|
||||
|
||||
return new StaticCall(new FullyQualifiedName('Psy\Command\TimeitCommand'), 'markEnd', [new Arg($arg)]);
|
||||
return new StaticCall(new FullyQualifiedName(TimeitCommand::class), 'markEnd', [new Arg($arg)]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,13 +136,13 @@ class TimeitVisitor extends NodeVisitorAbstract
|
||||
*
|
||||
* Wrap $expr in a PhpParser\Node\Stmt\Expression if the class exists.
|
||||
*
|
||||
* @param PhpParser\Node $expr
|
||||
* @param array $attrs
|
||||
* @param \PhpParser\Node $expr
|
||||
* @param array $attrs
|
||||
*
|
||||
* @return PhpParser\Node\Expr|PhpParser\Node\Stmt\Expression
|
||||
* @return \PhpParser\Node\Expr|\PhpParser\Node\Stmt\Expression
|
||||
*/
|
||||
private function maybeExpression($expr, $attrs = [])
|
||||
private function maybeExpression(Node $expr, array $attrs = [])
|
||||
{
|
||||
return \class_exists('PhpParser\Node\Stmt\Expression') ? new Expression($expr, $attrs) : $expr;
|
||||
return \class_exists(Expression::class) ? new Expression($expr, $attrs) : $expr;
|
||||
}
|
||||
}
|
||||
|
90
vendor/psy/psysh/src/Command/TraceCommand.php
vendored
90
vendor/psy/psysh/src/Command/TraceCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
namespace Psy\Command;
|
||||
|
||||
use Psy\Formatter\TraceFormatter;
|
||||
use Psy\Input\FilterOptions;
|
||||
use Psy\Output\ShellOutput;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -45,8 +45,8 @@ class TraceCommand extends Command
|
||||
$this
|
||||
->setName('trace')
|
||||
->setDefinition([
|
||||
new InputOption('include-psy', 'p', InputOption::VALUE_NONE, 'Include Psy in the call stack.'),
|
||||
new InputOption('num', 'n', InputOption::VALUE_REQUIRED, 'Only include NUM lines.'),
|
||||
new InputOption('include-psy', 'p', InputOption::VALUE_NONE, 'Include Psy in the call stack.'),
|
||||
new InputOption('num', 'n', InputOption::VALUE_REQUIRED, 'Only include NUM lines.'),
|
||||
|
||||
$grep,
|
||||
$insensitive,
|
||||
@@ -68,6 +68,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -79,91 +81,19 @@ HELP
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a backtrace for an exception.
|
||||
* Get a backtrace for an exception or error.
|
||||
*
|
||||
* Optionally limit the number of rows to include with $count, and exclude
|
||||
* Psy from the trace.
|
||||
*
|
||||
* @param \Exception $e The exception with a backtrace
|
||||
* @param \Throwable $e The exception or error with a backtrace
|
||||
* @param int $count (default: PHP_INT_MAX)
|
||||
* @param bool $includePsy (default: true)
|
||||
*
|
||||
* @return array Formatted stacktrace lines
|
||||
*/
|
||||
protected function getBacktrace(\Exception $e, $count = null, $includePsy = true)
|
||||
protected function getBacktrace(\Throwable $e, int $count = null, bool $includePsy = true): array
|
||||
{
|
||||
if ($cwd = \getcwd()) {
|
||||
$cwd = \rtrim($cwd, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
if ($count === null) {
|
||||
$count = PHP_INT_MAX;
|
||||
}
|
||||
|
||||
$lines = [];
|
||||
|
||||
$trace = $e->getTrace();
|
||||
\array_unshift($trace, [
|
||||
'function' => '',
|
||||
'file' => $e->getFile() !== null ? $e->getFile() : 'n/a',
|
||||
'line' => $e->getLine() !== null ? $e->getLine() : 'n/a',
|
||||
'args' => [],
|
||||
]);
|
||||
|
||||
if (!$includePsy) {
|
||||
for ($i = \count($trace) - 1; $i >= 0; $i--) {
|
||||
$thing = isset($trace[$i]['class']) ? $trace[$i]['class'] : $trace[$i]['function'];
|
||||
if (\preg_match('/\\\\?Psy\\\\/', $thing)) {
|
||||
$trace = \array_slice($trace, $i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0, $count = \min($count, \count($trace)); $i < $count; $i++) {
|
||||
$class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
|
||||
$type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
|
||||
$function = $trace[$i]['function'];
|
||||
$file = isset($trace[$i]['file']) ? $this->replaceCwd($cwd, $trace[$i]['file']) : 'n/a';
|
||||
$line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
|
||||
|
||||
// Leave execution loop out of the `eval()'d code` lines
|
||||
if (\preg_match("#/src/Execution(?:Loop)?Closure.php\(\d+\) : eval\(\)'d code$#", \str_replace('\\', '/', $file))) {
|
||||
$file = "eval()'d code";
|
||||
}
|
||||
|
||||
// Skip any lines that don't match our filter options
|
||||
if (!$this->filter->match(\sprintf('%s%s%s() at %s:%s', $class, $type, $function, $file, $line))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lines[] = \sprintf(
|
||||
' <class>%s</class>%s%s() at <info>%s:%s</info>',
|
||||
OutputFormatter::escape($class),
|
||||
OutputFormatter::escape($type),
|
||||
OutputFormatter::escape($function),
|
||||
OutputFormatter::escape($file),
|
||||
OutputFormatter::escape($line)
|
||||
);
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the given directory from the start of a filepath.
|
||||
*
|
||||
* @param string $cwd
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function replaceCwd($cwd, $file)
|
||||
{
|
||||
if ($cwd === false) {
|
||||
return $file;
|
||||
} else {
|
||||
return \preg_replace('/^' . \preg_quote($cwd, '/') . '/', '', $file);
|
||||
}
|
||||
return TraceFormatter::formatTrace($e, $this->filter, $count, $includePsy);
|
||||
}
|
||||
}
|
||||
|
72
vendor/psy/psysh/src/Command/WhereamiCommand.php
vendored
72
vendor/psy/psysh/src/Command/WhereamiCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
namespace Psy\Command;
|
||||
|
||||
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
|
||||
use Psy\Configuration;
|
||||
use Psy\ConsoleColorFactory;
|
||||
use Psy\Formatter\CodeFormatter;
|
||||
use Psy\Output\ShellOutput;
|
||||
use Psy\Shell;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -23,16 +23,14 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
*/
|
||||
class WhereamiCommand extends Command
|
||||
{
|
||||
private $colorMode;
|
||||
private $backtrace;
|
||||
|
||||
/**
|
||||
* @param null|string $colorMode (default: null)
|
||||
* @param string|null $colorMode (deprecated and ignored)
|
||||
*/
|
||||
public function __construct($colorMode = null)
|
||||
{
|
||||
$this->colorMode = $colorMode ?: Configuration::COLOR_MODE_AUTO;
|
||||
$this->backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$this->backtrace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -46,17 +44,20 @@ class WhereamiCommand extends Command
|
||||
->setName('whereami')
|
||||
->setDefinition([
|
||||
new InputOption('num', 'n', InputOption::VALUE_OPTIONAL, 'Number of lines before and after.', '5'),
|
||||
new InputOption('file', 'f|a', InputOption::VALUE_NONE, 'Show the full source for the current file.'),
|
||||
])
|
||||
->setDescription('Show where you are in the code.')
|
||||
->setHelp(
|
||||
<<<'HELP'
|
||||
Show where you are in the code.
|
||||
|
||||
Optionally, include how many lines before and after you want to display.
|
||||
Optionally, include the number of lines before and after you want to display,
|
||||
or --file for the whole file.
|
||||
|
||||
e.g.
|
||||
<return>> whereami </return>
|
||||
<return>> whereami -n10</return>
|
||||
<return>> whereami --file</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
@@ -66,7 +67,7 @@ HELP
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function trace()
|
||||
protected function trace(): array
|
||||
{
|
||||
foreach (\array_reverse($this->backtrace) as $stackFrame) {
|
||||
if ($this->isDebugCall($stackFrame)) {
|
||||
@@ -77,13 +78,13 @@ HELP
|
||||
return \end($this->backtrace);
|
||||
}
|
||||
|
||||
private static function isDebugCall(array $stackFrame)
|
||||
private static function isDebugCall(array $stackFrame): bool
|
||||
{
|
||||
$class = isset($stackFrame['class']) ? $stackFrame['class'] : null;
|
||||
$class = isset($stackFrame['class']) ? $stackFrame['class'] : null;
|
||||
$function = isset($stackFrame['function']) ? $stackFrame['function'] : null;
|
||||
|
||||
return ($class === null && $function === 'Psy\debug') ||
|
||||
($class === 'Psy\Shell' && \in_array($function, ['__construct', 'debug']));
|
||||
return ($class === null && $function === 'Psy\\debug') ||
|
||||
($class === Shell::class && \in_array($function, ['__construct', 'debug']));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,7 +92,7 @@ HELP
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function fileInfo()
|
||||
protected function fileInfo(): array
|
||||
{
|
||||
$stackFrame = $this->trace();
|
||||
if (\preg_match('/eval\(/', $stackFrame['file'])) {
|
||||
@@ -108,22 +109,33 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$info = $this->fileInfo();
|
||||
$num = $input->getOption('num');
|
||||
$factory = new ConsoleColorFactory($this->colorMode);
|
||||
$colors = $factory->getConsoleColor();
|
||||
$highlighter = new Highlighter($colors);
|
||||
$contents = \file_get_contents($info['file']);
|
||||
$info = $this->fileInfo();
|
||||
$num = $input->getOption('num');
|
||||
$lineNum = $info['line'];
|
||||
$startLine = \max($lineNum - $num, 1);
|
||||
$endLine = $lineNum + $num;
|
||||
$code = \file_get_contents($info['file']);
|
||||
|
||||
$output->startPaging();
|
||||
$output->writeln('');
|
||||
$output->writeln(\sprintf('From <info>%s:%s</info>:', $this->replaceCwd($info['file']), $info['line']));
|
||||
$output->writeln('');
|
||||
$output->write($highlighter->getCodeSnippet($contents, $info['line'], $num, $num), false, OutputInterface::OUTPUT_RAW);
|
||||
$output->stopPaging();
|
||||
if ($input->getOption('file')) {
|
||||
$startLine = 1;
|
||||
$endLine = null;
|
||||
}
|
||||
|
||||
if ($output instanceof ShellOutput) {
|
||||
$output->startPaging();
|
||||
}
|
||||
|
||||
$output->writeln(\sprintf('From <info>%s:%s</info>:', $this->replaceCwd($info['file']), $lineNum));
|
||||
$output->write(CodeFormatter::formatCode($code, $startLine, $endLine, $lineNum), false);
|
||||
|
||||
if ($output instanceof ShellOutput) {
|
||||
$output->stopPaging();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -135,15 +147,15 @@ HELP
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function replaceCwd($file)
|
||||
private function replaceCwd(string $file): string
|
||||
{
|
||||
$cwd = \getcwd();
|
||||
if ($cwd === false) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
$cwd = \rtrim($cwd, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
$cwd = \rtrim($cwd, \DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;
|
||||
|
||||
return \preg_replace('/^' . \preg_quote($cwd, '/') . '/', '', $file);
|
||||
return \preg_replace('/^'.\preg_quote($cwd, '/').'/', '', $file);
|
||||
}
|
||||
}
|
||||
|
25
vendor/psy/psysh/src/Command/WtfCommand.php
vendored
25
vendor/psy/psysh/src/Command/WtfCommand.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -54,7 +54,7 @@ class WtfCommand extends TraceCommand implements ContextAware
|
||||
->setAliases(['last-exception', 'wtf?'])
|
||||
->setDefinition([
|
||||
new InputArgument('incredulity', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Number of lines to show.'),
|
||||
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Show entire backtrace.'),
|
||||
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Show entire backtrace.'),
|
||||
|
||||
$grep,
|
||||
$insensitive,
|
||||
@@ -81,6 +81,8 @@ HELP
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
@@ -92,19 +94,23 @@ HELP
|
||||
}
|
||||
|
||||
$exception = $this->context->getLastException();
|
||||
$count = $input->getOption('all') ? PHP_INT_MAX : \max(3, \pow(2, \strlen($incredulity) + 1));
|
||||
$count = $input->getOption('all') ? \PHP_INT_MAX : \max(3, \pow(2, \strlen($incredulity) + 1));
|
||||
|
||||
$shell = $this->getApplication();
|
||||
$output->startPaging();
|
||||
|
||||
if ($output instanceof ShellOutput) {
|
||||
$output->startPaging();
|
||||
}
|
||||
|
||||
do {
|
||||
$traceCount = \count($exception->getTrace());
|
||||
$showLines = $count;
|
||||
$showLines = $count;
|
||||
// Show the whole trace if we'd only be hiding a few lines
|
||||
if ($traceCount < \max($count * 1.2, $count + 2)) {
|
||||
$showLines = PHP_INT_MAX;
|
||||
$showLines = \PHP_INT_MAX;
|
||||
}
|
||||
|
||||
$trace = $this->getBacktrace($exception, $showLines);
|
||||
$trace = $this->getBacktrace($exception, $showLines);
|
||||
$moreLines = $traceCount - \count($trace);
|
||||
|
||||
$output->writeln($shell->formatException($exception));
|
||||
@@ -120,7 +126,10 @@ HELP
|
||||
$output->writeln('');
|
||||
}
|
||||
} while ($exception = $exception->getPrevious());
|
||||
$output->stopPaging();
|
||||
|
||||
if ($output instanceof ShellOutput) {
|
||||
$output->stopPaging();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
342
vendor/psy/psysh/src/ConfigPaths.php
vendored
342
vendor/psy/psysh/src/ConfigPaths.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,13 +11,93 @@
|
||||
|
||||
namespace Psy;
|
||||
|
||||
use XdgBaseDir\Xdg;
|
||||
|
||||
/**
|
||||
* A Psy Shell configuration path helper.
|
||||
*/
|
||||
class ConfigPaths
|
||||
{
|
||||
private $configDir;
|
||||
private $dataDir;
|
||||
private $runtimeDir;
|
||||
private $env;
|
||||
|
||||
/**
|
||||
* ConfigPaths constructor.
|
||||
*
|
||||
* Optionally provide `configDir`, `dataDir` and `runtimeDir` overrides.
|
||||
*
|
||||
* @see self::overrideDirs
|
||||
*
|
||||
* @param string[] $overrides Directory overrides
|
||||
* @param EnvInterface $env
|
||||
*/
|
||||
public function __construct(array $overrides = [], EnvInterface $env = null)
|
||||
{
|
||||
$this->overrideDirs($overrides);
|
||||
$this->env = $env ?: new SuperglobalsEnv();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide `configDir`, `dataDir` and `runtimeDir` overrides.
|
||||
*
|
||||
* If a key is set but empty, the override will be removed. If it is not set
|
||||
* at all, any existing override will persist.
|
||||
*
|
||||
* @param string[] $overrides Directory overrides
|
||||
*/
|
||||
public function overrideDirs(array $overrides)
|
||||
{
|
||||
if (\array_key_exists('configDir', $overrides)) {
|
||||
$this->configDir = $overrides['configDir'] ?: null;
|
||||
}
|
||||
|
||||
if (\array_key_exists('dataDir', $overrides)) {
|
||||
$this->dataDir = $overrides['dataDir'] ?: null;
|
||||
}
|
||||
|
||||
if (\array_key_exists('runtimeDir', $overrides)) {
|
||||
$this->runtimeDir = $overrides['runtimeDir'] ?: null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current home directory.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function homeDir()
|
||||
{
|
||||
if ($homeDir = $this->getEnv('HOME') ?: $this->windowsHomeDir()) {
|
||||
return \strtr($homeDir, '\\', '/');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function windowsHomeDir()
|
||||
{
|
||||
if (\defined('PHP_WINDOWS_VERSION_MAJOR')) {
|
||||
$homeDrive = $this->getEnv('HOMEDRIVE');
|
||||
$homePath = $this->getEnv('HOMEPATH');
|
||||
if ($homeDrive && $homePath) {
|
||||
return $homeDrive.'/'.$homePath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function homeConfigDir()
|
||||
{
|
||||
if ($homeConfigDir = $this->getEnv('XDG_CONFIG_HOME')) {
|
||||
return $homeConfigDir;
|
||||
}
|
||||
|
||||
$homeDir = $this->homeDir();
|
||||
|
||||
return $homeDir === '/' ? $homeDir.'.config' : $homeDir.'/.config';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get potential config directory paths.
|
||||
*
|
||||
@@ -28,11 +108,23 @@ class ConfigPaths
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getConfigDirs()
|
||||
public function configDirs(): array
|
||||
{
|
||||
$xdg = new Xdg();
|
||||
if ($this->configDir !== null) {
|
||||
return [$this->configDir];
|
||||
}
|
||||
|
||||
return self::getDirNames($xdg->getConfigDirs());
|
||||
$configDirs = $this->getEnvArray('XDG_CONFIG_DIRS') ?: ['/etc/xdg'];
|
||||
|
||||
return $this->allDirNames(\array_merge([$this->homeConfigDir()], $configDirs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getConfigDirs(): array
|
||||
{
|
||||
return (new self())->configDirs();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,13 +135,14 @@ class ConfigPaths
|
||||
*
|
||||
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
*
|
||||
* @deprecated
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getHomeConfigDirs()
|
||||
public static function getHomeConfigDirs(): array
|
||||
{
|
||||
$xdg = new Xdg();
|
||||
|
||||
return self::getDirNames([$xdg->getHomeConfigDir()]);
|
||||
// Not quite the same, but this is deprecated anyway /shrug
|
||||
return self::getConfigDirs();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,13 +153,18 @@ class ConfigPaths
|
||||
* config directory (`%APPDATA%/PsySH` on Windows, `~/.config/psysh`
|
||||
* everywhere else).
|
||||
*
|
||||
* @see self::getHomeConfigDirs
|
||||
* @see self::homeConfigDir
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getCurrentConfigDir()
|
||||
public function currentConfigDir(): string
|
||||
{
|
||||
$configDirs = self::getHomeConfigDirs();
|
||||
if ($this->configDir !== null) {
|
||||
return $this->configDir;
|
||||
}
|
||||
|
||||
$configDirs = $this->allDirNames([$this->homeConfigDir()]);
|
||||
|
||||
foreach ($configDirs as $configDir) {
|
||||
if (@\is_dir($configDir)) {
|
||||
return $configDir;
|
||||
@@ -76,19 +174,32 @@ class ConfigPaths
|
||||
return $configDirs[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getCurrentConfigDir(): string
|
||||
{
|
||||
return (new self())->currentConfigDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find real config files in config directories.
|
||||
*
|
||||
* @param string[] $names Config file names
|
||||
* @param string $configDir Optionally use a specific config directory
|
||||
* @param string[] $names Config file names
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getConfigFiles(array $names, $configDir = null)
|
||||
public function configFiles(array $names): array
|
||||
{
|
||||
$dirs = ($configDir === null) ? self::getConfigDirs() : [$configDir];
|
||||
return $this->allRealFiles($this->configDirs(), $names);
|
||||
}
|
||||
|
||||
return self::getRealFiles($dirs, $names);
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getConfigFiles(array $names, $configDir = null): array
|
||||
{
|
||||
return (new self(['configDir' => $configDir]))->configFiles($names);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,90 +214,159 @@ class ConfigPaths
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getDataDirs()
|
||||
public function dataDirs(): array
|
||||
{
|
||||
$xdg = new Xdg();
|
||||
if ($this->dataDir !== null) {
|
||||
return [$this->dataDir];
|
||||
}
|
||||
|
||||
return self::getDirNames($xdg->getDataDirs());
|
||||
$homeDataDir = $this->getEnv('XDG_DATA_HOME') ?: $this->homeDir().'/.local/share';
|
||||
$dataDirs = $this->getEnvArray('XDG_DATA_DIRS') ?: ['/usr/local/share', '/usr/share'];
|
||||
|
||||
return $this->allDirNames(\array_merge([$homeDataDir], $dataDirs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getDataDirs(): array
|
||||
{
|
||||
return (new self())->dataDirs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find real data files in config directories.
|
||||
*
|
||||
* @param string[] $names Config file names
|
||||
* @param string $dataDir Optionally use a specific config directory
|
||||
* @param string[] $names Config file names
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getDataFiles(array $names, $dataDir = null)
|
||||
public function dataFiles(array $names): array
|
||||
{
|
||||
$dirs = ($dataDir === null) ? self::getDataDirs() : [$dataDir];
|
||||
return $this->allRealFiles($this->dataDirs(), $names);
|
||||
}
|
||||
|
||||
return self::getRealFiles($dirs, $names);
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getDataFiles(array $names, $dataDir = null): array
|
||||
{
|
||||
return (new self(['dataDir' => $dataDir]))->dataFiles($names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a runtime directory.
|
||||
*
|
||||
* Defaults to `/psysh` inside the system's temp dir.
|
||||
* Defaults to `/psysh` inside the system's temp dir.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRuntimeDir()
|
||||
public function runtimeDir(): string
|
||||
{
|
||||
$xdg = new Xdg();
|
||||
|
||||
\set_error_handler(['Psy\Exception\ErrorException', 'throwException']);
|
||||
|
||||
try {
|
||||
// XDG doesn't really work on Windows, sometimes complains about
|
||||
// permissions, sometimes tries to remove non-empty directories.
|
||||
// It's a bit flaky. So we'll give this a shot first...
|
||||
$runtimeDir = $xdg->getRuntimeDir(false);
|
||||
} catch (\Exception $e) {
|
||||
// Well. That didn't work. Fall back to a boring old folder in the
|
||||
// system temp dir.
|
||||
$runtimeDir = \sys_get_temp_dir();
|
||||
if ($this->runtimeDir !== null) {
|
||||
return $this->runtimeDir;
|
||||
}
|
||||
|
||||
\restore_error_handler();
|
||||
// Fallback to a boring old folder in the system temp dir.
|
||||
$runtimeDir = $this->getEnv('XDG_RUNTIME_DIR') ?: \sys_get_temp_dir();
|
||||
|
||||
return \strtr($runtimeDir, '\\', '/') . '/psysh';
|
||||
return \strtr($runtimeDir, '\\', '/').'/psysh';
|
||||
}
|
||||
|
||||
private static function getDirNames(array $baseDirs)
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getRuntimeDir(): string
|
||||
{
|
||||
return (new self())->runtimeDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of directories in PATH.
|
||||
*
|
||||
* If $PATH is unset/empty it defaults to '/usr/sbin:/usr/bin:/sbin:/bin'.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function pathDirs(): array
|
||||
{
|
||||
return $this->getEnvArray('PATH') ?: ['/usr/sbin', '/usr/bin', '/sbin', '/bin'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a command (an executable) in $PATH.
|
||||
*
|
||||
* Behaves like 'command -v COMMAND' or 'which COMMAND'.
|
||||
* If $PATH is unset/empty it defaults to '/usr/sbin:/usr/bin:/sbin:/bin'.
|
||||
*
|
||||
* @param string $command the executable to locate
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function which($command)
|
||||
{
|
||||
foreach ($this->pathDirs() as $path) {
|
||||
$fullpath = $path.\DIRECTORY_SEPARATOR.$command;
|
||||
if (@\is_file($fullpath) && @\is_executable($fullpath)) {
|
||||
return $fullpath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all PsySH directory name candidates given a list of base directories.
|
||||
*
|
||||
* This expects that XDG-compatible directory paths will be passed in.
|
||||
* `psysh` will be added to each of $baseDirs, and we'll throw in `~/.psysh`
|
||||
* and a couple of Windows-friendly paths as well.
|
||||
*
|
||||
* @param string[] $baseDirs base directory paths
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function allDirNames(array $baseDirs): array
|
||||
{
|
||||
$dirs = \array_map(function ($dir) {
|
||||
return \strtr($dir, '\\', '/') . '/psysh';
|
||||
return \strtr($dir, '\\', '/').'/psysh';
|
||||
}, $baseDirs);
|
||||
|
||||
// Add ~/.psysh
|
||||
if ($home = \getenv('HOME')) {
|
||||
$dirs[] = \strtr($home, '\\', '/') . '/.psysh';
|
||||
if ($home = $this->getEnv('HOME')) {
|
||||
$dirs[] = \strtr($home, '\\', '/').'/.psysh';
|
||||
}
|
||||
|
||||
// Add some Windows specific ones :)
|
||||
if (\defined('PHP_WINDOWS_VERSION_MAJOR')) {
|
||||
if ($appData = \getenv('APPDATA')) {
|
||||
if ($appData = $this->getEnv('APPDATA')) {
|
||||
// AppData gets preference
|
||||
\array_unshift($dirs, \strtr($appData, '\\', '/') . '/PsySH');
|
||||
\array_unshift($dirs, \strtr($appData, '\\', '/').'/PsySH');
|
||||
}
|
||||
|
||||
$dir = \strtr(\getenv('HOMEDRIVE') . '/' . \getenv('HOMEPATH'), '\\', '/') . '/.psysh';
|
||||
if (!\in_array($dir, $dirs)) {
|
||||
$dirs[] = $dir;
|
||||
if ($windowsHomeDir = $this->windowsHomeDir()) {
|
||||
$dir = \strtr($windowsHomeDir, '\\', '/').'/.psysh';
|
||||
if (!\in_array($dir, $dirs)) {
|
||||
$dirs[] = $dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $dirs;
|
||||
}
|
||||
|
||||
private static function getRealFiles(array $dirNames, array $fileNames)
|
||||
/**
|
||||
* Given a list of directories, and a list of filenames, find the ones that
|
||||
* are real files.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function allRealFiles(array $dirNames, array $fileNames): array
|
||||
{
|
||||
$files = [];
|
||||
foreach ($dirNames as $dir) {
|
||||
foreach ($fileNames as $name) {
|
||||
$file = $dir . '/' . $name;
|
||||
$file = $dir.'/'.$name;
|
||||
if (@\is_file($file)) {
|
||||
$files[] = $file;
|
||||
}
|
||||
@@ -196,6 +376,31 @@ class ConfigPaths
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that $dir exists and is writable.
|
||||
*
|
||||
* Generates E_USER_NOTICE error if the directory is not writable or creatable.
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return bool False if directory exists but is not writeable, or cannot be created
|
||||
*/
|
||||
public static function ensureDir(string $dir): bool
|
||||
{
|
||||
if (!\is_dir($dir)) {
|
||||
// Just try making it and see if it works
|
||||
@\mkdir($dir, 0700, true);
|
||||
}
|
||||
|
||||
if (!\is_dir($dir) || !\is_writable($dir)) {
|
||||
\trigger_error(\sprintf('Writing to directory %s is not allowed.', $dir), \E_USER_NOTICE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that $file exists and is writable, make the parent directory if necessary.
|
||||
*
|
||||
@@ -205,28 +410,19 @@ class ConfigPaths
|
||||
*
|
||||
* @return string|false Full path to $file, or false if file is not writable
|
||||
*/
|
||||
public static function touchFileWithMkdir($file)
|
||||
public static function touchFileWithMkdir(string $file)
|
||||
{
|
||||
if (\file_exists($file)) {
|
||||
if (\is_writable($file)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
\trigger_error(\sprintf('Writing to %s is not allowed.', $file), E_USER_NOTICE);
|
||||
\trigger_error(\sprintf('Writing to %s is not allowed.', $file), \E_USER_NOTICE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$dir = \dirname($file);
|
||||
|
||||
if (!\is_dir($dir)) {
|
||||
// Just try making it and see if it works
|
||||
@\mkdir($dir, 0700, true);
|
||||
}
|
||||
|
||||
if (!\is_dir($dir) || !\is_writable($dir)) {
|
||||
\trigger_error(\sprintf('Writing to %s is not allowed.', $dir), E_USER_NOTICE);
|
||||
|
||||
if (!self::ensureDir(\dirname($file))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -234,4 +430,18 @@ class ConfigPaths
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function getEnv($key)
|
||||
{
|
||||
return $this->env->get($key);
|
||||
}
|
||||
|
||||
private function getEnvArray($key)
|
||||
{
|
||||
if ($value = $this->getEnv($key)) {
|
||||
return \explode(\PATH_SEPARATOR, $value);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
881
vendor/psy/psysh/src/Configuration.php
vendored
881
vendor/psy/psysh/src/Configuration.php
vendored
File diff suppressed because it is too large
Load Diff
82
vendor/psy/psysh/src/ConsoleColorFactory.php
vendored
82
vendor/psy/psysh/src/ConsoleColorFactory.php
vendored
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy;
|
||||
|
||||
use JakubOnderka\PhpConsoleColor\ConsoleColor;
|
||||
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
|
||||
|
||||
/**
|
||||
* Builds `ConsoleColor` instances configured according to the given color mode.
|
||||
*/
|
||||
class ConsoleColorFactory
|
||||
{
|
||||
private $colorMode;
|
||||
|
||||
/**
|
||||
* @param string $colorMode
|
||||
*/
|
||||
public function __construct($colorMode)
|
||||
{
|
||||
$this->colorMode = $colorMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a `ConsoleColor` instance configured according to the given color
|
||||
* mode.
|
||||
*
|
||||
* @return ConsoleColor
|
||||
*/
|
||||
public function getConsoleColor()
|
||||
{
|
||||
if ($this->colorMode === Configuration::COLOR_MODE_AUTO) {
|
||||
return $this->getDefaultConsoleColor();
|
||||
} elseif ($this->colorMode === Configuration::COLOR_MODE_FORCED) {
|
||||
return $this->getForcedConsoleColor();
|
||||
} elseif ($this->colorMode === Configuration::COLOR_MODE_DISABLED) {
|
||||
return $this->getDisabledConsoleColor();
|
||||
}
|
||||
}
|
||||
|
||||
private function getDefaultConsoleColor()
|
||||
{
|
||||
$color = new ConsoleColor();
|
||||
$color->addTheme(Highlighter::LINE_NUMBER, ['blue']);
|
||||
$color->addTheme(Highlighter::TOKEN_KEYWORD, ['yellow']);
|
||||
$color->addTheme(Highlighter::TOKEN_STRING, ['green']);
|
||||
$color->addTheme(Highlighter::TOKEN_COMMENT, ['dark_gray']);
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
private function getForcedConsoleColor()
|
||||
{
|
||||
$color = $this->getDefaultConsoleColor();
|
||||
$color->setForceStyle(true);
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
private function getDisabledConsoleColor()
|
||||
{
|
||||
$color = new ConsoleColor();
|
||||
|
||||
$color->addTheme(Highlighter::TOKEN_STRING, ['none']);
|
||||
$color->addTheme(Highlighter::TOKEN_COMMENT, ['none']);
|
||||
$color->addTheme(Highlighter::TOKEN_KEYWORD, ['none']);
|
||||
$color->addTheme(Highlighter::TOKEN_DEFAULT, ['none']);
|
||||
$color->addTheme(Highlighter::TOKEN_HTML, ['none']);
|
||||
$color->addTheme(Highlighter::ACTUAL_LINE_MARK, ['none']);
|
||||
$color->addTheme(Highlighter::LINE_NUMBER, ['none']);
|
||||
|
||||
return $color;
|
||||
}
|
||||
}
|
34
vendor/psy/psysh/src/Context.php
vendored
34
vendor/psy/psysh/src/Context.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,7 +21,7 @@ class Context
|
||||
{
|
||||
private static $specialNames = ['_', '_e', '__out', '__psysh__', 'this'];
|
||||
|
||||
// Whitelist a very limited number of command-scope magic variable names.
|
||||
// Include a very limited number of command-scope magic variable names.
|
||||
// This might be a bad idea, but future me can sort it out.
|
||||
private static $commandScopeNames = [
|
||||
'__function', '__method', '__class', '__namespace', '__file', '__line', '__dir',
|
||||
@@ -38,13 +38,13 @@ class Context
|
||||
/**
|
||||
* Get a context variable.
|
||||
*
|
||||
* @throws InvalidArgumentException If the variable is not found in the current context
|
||||
* @throws \InvalidArgumentException If the variable is not found in the current context
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name)
|
||||
public function get(string $name)
|
||||
{
|
||||
switch ($name) {
|
||||
case '_':
|
||||
@@ -87,7 +87,7 @@ class Context
|
||||
break;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Unknown variable: $' . $name);
|
||||
throw new \InvalidArgumentException('Unknown variable: $'.$name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +95,7 @@ class Context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAll()
|
||||
public function getAll(): array
|
||||
{
|
||||
return \array_merge($this->scopeVariables, $this->getSpecialVariables());
|
||||
}
|
||||
@@ -105,7 +105,7 @@ class Context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSpecialVariables()
|
||||
public function getSpecialVariables(): array
|
||||
{
|
||||
$vars = [
|
||||
'_' => $this->returnValue,
|
||||
@@ -168,21 +168,21 @@ class Context
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the most recent Exception.
|
||||
* Set the most recent Exception or Error.
|
||||
*
|
||||
* @param \Exception $e
|
||||
* @param \Throwable $e
|
||||
*/
|
||||
public function setLastException(\Exception $e)
|
||||
public function setLastException(\Throwable $e)
|
||||
{
|
||||
$this->lastException = $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most recent Exception.
|
||||
* Get the most recent Exception or Error.
|
||||
*
|
||||
* @throws \InvalidArgumentException If no Exception has been caught
|
||||
*
|
||||
* @return null|\Exception
|
||||
* @return \Throwable|null
|
||||
*/
|
||||
public function getLastException()
|
||||
{
|
||||
@@ -198,7 +198,7 @@ class Context
|
||||
*
|
||||
* @param string $lastStdout
|
||||
*/
|
||||
public function setLastStdout($lastStdout)
|
||||
public function setLastStdout(string $lastStdout)
|
||||
{
|
||||
$this->lastStdout = $lastStdout;
|
||||
}
|
||||
@@ -208,7 +208,7 @@ class Context
|
||||
*
|
||||
* @throws \InvalidArgumentException If no output has happened yet
|
||||
*
|
||||
* @return null|string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLastStdout()
|
||||
{
|
||||
@@ -288,7 +288,7 @@ class Context
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCommandScopeVariables()
|
||||
public function getCommandScopeVariables(): array
|
||||
{
|
||||
return $this->commandScopeVariables;
|
||||
}
|
||||
@@ -301,7 +301,7 @@ class Context
|
||||
*
|
||||
* @return array Array of unused variable names
|
||||
*/
|
||||
public function getUnusedCommandScopeVariableNames()
|
||||
public function getUnusedCommandScopeVariableNames(): array
|
||||
{
|
||||
return \array_diff(self::$commandScopeNames, \array_keys($this->commandScopeVariables));
|
||||
}
|
||||
@@ -313,7 +313,7 @@ class Context
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSpecialVariableName($name)
|
||||
public static function isSpecialVariableName(string $name): bool
|
||||
{
|
||||
return \in_array($name, self::$specialNames) || \in_array($name, self::$commandScopeNames);
|
||||
}
|
||||
|
2
vendor/psy/psysh/src/ContextAware.php
vendored
2
vendor/psy/psysh/src/ContextAware.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
25
vendor/psy/psysh/src/EnvInterface.php
vendored
Normal file
25
vendor/psy/psysh/src/EnvInterface.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy;
|
||||
|
||||
/**
|
||||
* Abstraction around environment variables.
|
||||
*/
|
||||
interface EnvInterface
|
||||
{
|
||||
/**
|
||||
* Get an environment variable by name.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get(string $key);
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,7 +21,7 @@ class BreakException extends \Exception implements Exception
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($message = '', $code = 0, \Exception $previous = null)
|
||||
public function __construct($message = '', $code = 0, \Throwable $previous = null)
|
||||
{
|
||||
$this->rawMessage = $message;
|
||||
parent::__construct(\sprintf('Exit: %s', $message), $code, $previous);
|
||||
@@ -32,7 +32,7 @@ class BreakException extends \Exception implements Exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
public function getRawMessage(): string
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,14 +21,14 @@ class ErrorException extends \ErrorException implements Exception
|
||||
/**
|
||||
* Construct a Psy ErrorException.
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param int $severity (default: 1)
|
||||
* @param string $filename (default: null)
|
||||
* @param int $lineno (default: null)
|
||||
* @param Exception $previous (default: null)
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param int $severity (default: 1)
|
||||
* @param string|null $filename (default: null)
|
||||
* @param int|null $lineno (default: null)
|
||||
* @param \Throwable|null $previous (default: null)
|
||||
*/
|
||||
public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, $previous = null)
|
||||
public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, \Throwable $previous = null)
|
||||
{
|
||||
$this->rawMessage = $message;
|
||||
|
||||
@@ -37,28 +37,28 @@ class ErrorException extends \ErrorException implements Exception
|
||||
}
|
||||
|
||||
switch ($severity) {
|
||||
case E_STRICT:
|
||||
case \E_STRICT:
|
||||
$type = 'Strict error';
|
||||
break;
|
||||
|
||||
case E_NOTICE:
|
||||
case E_USER_NOTICE:
|
||||
case \E_NOTICE:
|
||||
case \E_USER_NOTICE:
|
||||
$type = 'Notice';
|
||||
break;
|
||||
|
||||
case E_WARNING:
|
||||
case E_CORE_WARNING:
|
||||
case E_COMPILE_WARNING:
|
||||
case E_USER_WARNING:
|
||||
case \E_WARNING:
|
||||
case \E_CORE_WARNING:
|
||||
case \E_COMPILE_WARNING:
|
||||
case \E_USER_WARNING:
|
||||
$type = 'Warning';
|
||||
break;
|
||||
|
||||
case E_DEPRECATED:
|
||||
case E_USER_DEPRECATED:
|
||||
case \E_DEPRECATED:
|
||||
case \E_USER_DEPRECATED:
|
||||
$type = 'Deprecated';
|
||||
break;
|
||||
|
||||
case E_RECOVERABLE_ERROR:
|
||||
case \E_RECOVERABLE_ERROR:
|
||||
$type = 'Recoverable fatal error';
|
||||
break;
|
||||
|
||||
@@ -67,7 +67,7 @@ class ErrorException extends \ErrorException implements Exception
|
||||
break;
|
||||
}
|
||||
|
||||
$message = \sprintf('PHP %s: %s%s on line %d', $type, $message, $filename ? ' in ' . $filename : '', $lineno);
|
||||
$message = \sprintf('PHP %s: %s%s on line %d', $type, $message, $filename ? ' in '.$filename : '', $lineno);
|
||||
parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ class ErrorException extends \ErrorException implements Exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
public function getRawMessage(): string
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
@@ -86,9 +86,9 @@ class ErrorException extends \ErrorException implements Exception
|
||||
*
|
||||
* This allows us to:
|
||||
*
|
||||
* set_error_handler(array('Psy\Exception\ErrorException', 'throwException'));
|
||||
* set_error_handler([ErrorException::class, 'throwException']);
|
||||
*
|
||||
* @throws ErrorException
|
||||
* @throws self
|
||||
*
|
||||
* @param int $errno Error type
|
||||
* @param string $errstr Message
|
||||
@@ -103,11 +103,13 @@ class ErrorException extends \ErrorException implements Exception
|
||||
/**
|
||||
* Create an ErrorException from an Error.
|
||||
*
|
||||
* @deprecated psySH no longer wraps Errors
|
||||
*
|
||||
* @param \Error $e
|
||||
*
|
||||
* @return ErrorException
|
||||
* @return self
|
||||
*/
|
||||
public static function fromError(\Error $e)
|
||||
public static function fromError(\Error $e): self
|
||||
{
|
||||
return new self($e->getMessage(), $e->getCode(), 1, $e->getFile(), $e->getLine(), $e);
|
||||
}
|
||||
|
2
vendor/psy/psysh/src/Exception/Exception.php
vendored
2
vendor/psy/psysh/src/Exception/Exception.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,14 +21,14 @@ class FatalErrorException extends \ErrorException implements Exception
|
||||
/**
|
||||
* Create a fatal error.
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param int $severity (default: 1)
|
||||
* @param string $filename (default: null)
|
||||
* @param int $lineno (default: null)
|
||||
* @param \Exception $previous (default: null)
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param int $severity (default: 1)
|
||||
* @param string|null $filename (default: null)
|
||||
* @param int|null $lineno (default: null)
|
||||
* @param \Throwable|null $previous (default: null)
|
||||
*/
|
||||
public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, $previous = null)
|
||||
public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, \Throwable $previous = null)
|
||||
{
|
||||
// Since these are basically always PHP Parser Node line numbers, treat -1 as null.
|
||||
if ($lineno === -1) {
|
||||
@@ -45,7 +45,7 @@ class FatalErrorException extends \ErrorException implements Exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
public function getRawMessage(): string
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -22,7 +22,7 @@ class ParseErrorException extends \PhpParser\Error implements Exception
|
||||
* @param string $message (default: "")
|
||||
* @param int $line (default: -1)
|
||||
*/
|
||||
public function __construct($message = '', $line = -1)
|
||||
public function __construct(string $message = '', int $line = -1)
|
||||
{
|
||||
$message = \sprintf('PHP Parse error: %s', $message);
|
||||
parent::__construct($message, $line);
|
||||
@@ -33,9 +33,9 @@ class ParseErrorException extends \PhpParser\Error implements Exception
|
||||
*
|
||||
* @param \PhpParser\Error $e
|
||||
*
|
||||
* @return ParseErrorException
|
||||
* @return self
|
||||
*/
|
||||
public static function fromParseError(\PhpParser\Error $e)
|
||||
public static function fromParseError(\PhpParser\Error $e): self
|
||||
{
|
||||
return new self($e->getRawMessage(), $e->getStartLine());
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,11 +21,11 @@ class RuntimeException extends \RuntimeException implements Exception
|
||||
/**
|
||||
* Make this bad boy.
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param \Exception $previous (default: null)
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param \Throwable|null $previous (default: null)
|
||||
*/
|
||||
public function __construct($message = '', $code = 0, \Exception $previous = null)
|
||||
public function __construct(string $message = '', int $code = 0, \Throwable $previous = null)
|
||||
{
|
||||
$this->rawMessage = $message;
|
||||
parent::__construct($message, $code, $previous);
|
||||
@@ -36,7 +36,7 @@ class RuntimeException extends \RuntimeException implements Exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
public function getRawMessage(): string
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -19,10 +19,10 @@ class ThrowUpException extends \Exception implements Exception
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(\Exception $exception)
|
||||
public function __construct(\Throwable $throwable)
|
||||
{
|
||||
$message = \sprintf("Throwing %s with message '%s'", \get_class($exception), $exception->getMessage());
|
||||
parent::__construct($message, $exception->getCode(), $exception);
|
||||
$message = \sprintf("Throwing %s with message '%s'", \get_class($throwable), $throwable->getMessage());
|
||||
parent::__construct($message, $throwable->getCode(), $throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,7 +30,7 @@ class ThrowUpException extends \Exception implements Exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
public function getRawMessage(): string
|
||||
{
|
||||
return $this->getPrevious()->getMessage();
|
||||
}
|
||||
@@ -38,11 +38,13 @@ class ThrowUpException extends \Exception implements Exception
|
||||
/**
|
||||
* Create a ThrowUpException from a Throwable.
|
||||
*
|
||||
* @deprecated psySH no longer wraps Throwables
|
||||
*
|
||||
* @param \Throwable $throwable
|
||||
*
|
||||
* @return ThrowUpException
|
||||
* @return self
|
||||
*/
|
||||
public static function fromThrowable($throwable)
|
||||
public static function fromThrowable($throwable): self
|
||||
{
|
||||
if ($throwable instanceof \Error) {
|
||||
$throwable = ErrorException::fromError($throwable);
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -21,14 +21,17 @@ class TypeErrorException extends \Exception implements Exception
|
||||
/**
|
||||
* Constructor!
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @deprecated psySH no longer wraps TypeErrors
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param \Throwable|null $previous (default: null)
|
||||
*/
|
||||
public function __construct($message = '', $code = 0)
|
||||
public function __construct(string $message = '', int $code = 0, \Throwable $previous = null)
|
||||
{
|
||||
$this->rawMessage = $message;
|
||||
$message = \preg_replace('/, called in .*?: eval\\(\\)\'d code/', '', $message);
|
||||
parent::__construct(\sprintf('TypeError: %s', $message), $code);
|
||||
parent::__construct(\sprintf('TypeError: %s', $message), $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,7 +39,7 @@ class TypeErrorException extends \Exception implements Exception
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
public function getRawMessage(): string
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
@@ -44,12 +47,14 @@ class TypeErrorException extends \Exception implements Exception
|
||||
/**
|
||||
* Create a TypeErrorException from a TypeError.
|
||||
*
|
||||
* @deprecated psySH no longer wraps TypeErrors
|
||||
*
|
||||
* @param \TypeError $e
|
||||
*
|
||||
* @return TypeErrorException
|
||||
* @return self
|
||||
*/
|
||||
public static function fromTypeError(\TypeError $e)
|
||||
public static function fromTypeError(\TypeError $e): self
|
||||
{
|
||||
return new self($e->getMessage(), $e->getCode());
|
||||
return new self($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
37
vendor/psy/psysh/src/Exception/UnexpectedTargetException.php
vendored
Normal file
37
vendor/psy/psysh/src/Exception/UnexpectedTargetException.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\Exception;
|
||||
|
||||
class UnexpectedTargetException extends RuntimeException
|
||||
{
|
||||
private $target;
|
||||
|
||||
/**
|
||||
* @param mixed $target
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param \Throwable|null $previous (default: null)
|
||||
*/
|
||||
public function __construct($target, string $message = '', int $code = 0, \Throwable $previous = null)
|
||||
{
|
||||
$this->target = $target;
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTarget()
|
||||
{
|
||||
return $this->target;
|
||||
}
|
||||
}
|
50
vendor/psy/psysh/src/ExecutionClosure.php
vendored
50
vendor/psy/psysh/src/ExecutionClosure.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -37,28 +37,19 @@ class ExecutionClosure
|
||||
\set_error_handler([$__psysh__, 'handleError']);
|
||||
|
||||
// Evaluate the current code buffer
|
||||
$_ = eval($__psysh__->onExecute($__psysh__->flushCode() ?: ExecutionClosure::NOOP_INPUT));
|
||||
$_ = eval($__psysh__->onExecute($__psysh__->flushCode() ?: self::NOOP_INPUT));
|
||||
} catch (\Throwable $_e) {
|
||||
// Clean up on our way out.
|
||||
\restore_error_handler();
|
||||
if (\ob_get_level() > 0) {
|
||||
\ob_end_clean();
|
||||
}
|
||||
|
||||
throw $_e;
|
||||
} catch (\Exception $_e) {
|
||||
// Clean up on our way out.
|
||||
} finally {
|
||||
// Won't be needing this anymore
|
||||
\restore_error_handler();
|
||||
if (\ob_get_level() > 0) {
|
||||
\ob_end_clean();
|
||||
}
|
||||
|
||||
throw $_e;
|
||||
}
|
||||
|
||||
// Won't be needing this anymore
|
||||
\restore_error_handler();
|
||||
|
||||
// Flush stdout (write to shell output, plus save to magic variable)
|
||||
\ob_end_flush();
|
||||
|
||||
@@ -72,21 +63,18 @@ class ExecutionClosure
|
||||
/**
|
||||
* Set the closure instance.
|
||||
*
|
||||
* @param Shell $psysh
|
||||
* @param Shell $shell
|
||||
* @param \Closure $closure
|
||||
*/
|
||||
protected function setClosure(Shell $shell, \Closure $closure)
|
||||
{
|
||||
if (self::shouldBindClosure()) {
|
||||
$that = $shell->getBoundObject();
|
||||
if (\is_object($that)) {
|
||||
$closure = $closure->bindTo($that, \get_class($that));
|
||||
} else {
|
||||
$closure = $closure->bindTo(null, $shell->getBoundClass());
|
||||
}
|
||||
}
|
||||
$that = $shell->getBoundObject();
|
||||
|
||||
$this->closure = $closure;
|
||||
if (\is_object($that)) {
|
||||
$this->closure = $closure->bindTo($that, \get_class($that));
|
||||
} else {
|
||||
$this->closure = $closure->bindTo(null, $shell->getBoundClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,20 +88,4 @@ class ExecutionClosure
|
||||
|
||||
return $closure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide whether to bind the execution closure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function shouldBindClosure()
|
||||
{
|
||||
// skip binding on HHVM < 3.5.0
|
||||
// see https://github.com/facebook/hhvm/issues/1203
|
||||
if (\defined('HHVM_VERSION')) {
|
||||
return \version_compare(HHVM_VERSION, '3.5.0', '>=');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
67
vendor/psy/psysh/src/ExecutionLoop.php
vendored
67
vendor/psy/psysh/src/ExecutionLoop.php
vendored
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy;
|
||||
|
||||
use Psy\Exception\ErrorException;
|
||||
|
||||
/**
|
||||
* The Psy Shell execution loop.
|
||||
*/
|
||||
class ExecutionLoop
|
||||
{
|
||||
/**
|
||||
* Run the execution loop.
|
||||
*
|
||||
* @throws ThrowUpException if thrown by the `throw-up` command
|
||||
*
|
||||
* @param Shell $shell
|
||||
*/
|
||||
public function run(Shell $shell)
|
||||
{
|
||||
$this->loadIncludes($shell);
|
||||
|
||||
$closure = new ExecutionLoopClosure($shell);
|
||||
$closure->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user-defined includes.
|
||||
*
|
||||
* @param Shell $shell
|
||||
*/
|
||||
protected function loadIncludes(Shell $shell)
|
||||
{
|
||||
// Load user-defined includes
|
||||
$load = function (Shell $__psysh__) {
|
||||
\set_error_handler([$__psysh__, 'handleError']);
|
||||
foreach ($__psysh__->getIncludes() as $__psysh_include__) {
|
||||
try {
|
||||
include $__psysh_include__;
|
||||
} catch (\Error $_e) {
|
||||
$__psysh__->writeException(ErrorException::fromError($_e));
|
||||
} catch (\Exception $_e) {
|
||||
$__psysh__->writeException($_e);
|
||||
}
|
||||
}
|
||||
\restore_error_handler();
|
||||
unset($__psysh_include__);
|
||||
|
||||
// Override any new local variables with pre-defined scope variables
|
||||
\extract($__psysh__->getScopeVariables(false));
|
||||
|
||||
// ... then add the whole mess of variables back.
|
||||
$__psysh__->setScopeVariables(\get_defined_vars());
|
||||
};
|
||||
|
||||
$load($shell);
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -35,14 +35,14 @@ abstract class AbstractListener implements Listener
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onInput(Shell $shell, $input)
|
||||
public function onInput(Shell $shell, string $input)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onExecute(Shell $shell, $code)
|
||||
public function onExecute(Shell $shell, string $code)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -23,7 +23,7 @@ interface Listener
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported();
|
||||
public static function isSupported(): bool;
|
||||
|
||||
/**
|
||||
* Called once before the REPL session starts.
|
||||
@@ -49,7 +49,7 @@ interface Listener
|
||||
*
|
||||
* @return string|null User input override
|
||||
*/
|
||||
public function onInput(Shell $shell, $input);
|
||||
public function onInput(Shell $shell, string $input);
|
||||
|
||||
/**
|
||||
* Called before executing user code.
|
||||
@@ -65,7 +65,7 @@ interface Listener
|
||||
*
|
||||
* @return string|null User code override
|
||||
*/
|
||||
public function onExecute(Shell $shell, $code);
|
||||
public function onExecute(Shell $shell, string $code);
|
||||
|
||||
/**
|
||||
* Called at the end of each loop.
|
||||
|
102
vendor/psy/psysh/src/ExecutionLoop/ProcessForker.php
vendored
102
vendor/psy/psysh/src/ExecutionLoop/ProcessForker.php
vendored
@@ -3,7 +3,7 @@
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2018 Justin Hileman
|
||||
* (c) 2012-2022 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -26,18 +26,80 @@ class ProcessForker extends AbstractListener
|
||||
private $savegame;
|
||||
private $up;
|
||||
|
||||
private static $pcntlFunctions = [
|
||||
'pcntl_fork',
|
||||
'pcntl_signal_dispatch',
|
||||
'pcntl_signal',
|
||||
'pcntl_waitpid',
|
||||
'pcntl_wexitstatus',
|
||||
];
|
||||
|
||||
private static $posixFunctions = [
|
||||
'posix_getpid',
|
||||
'posix_kill',
|
||||
];
|
||||
|
||||
/**
|
||||
* Process forker is supported if pcntl and posix extensions are available.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported()
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return \function_exists('pcntl_signal') && \function_exists('posix_getpid');
|
||||
return self::isPcntlSupported() && !self::disabledPcntlFunctions() && self::isPosixSupported() && !self::disabledPosixFunctions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forks into a master and a loop process.
|
||||
* Verify that all required pcntl functions are, in fact, available.
|
||||
*/
|
||||
public static function isPcntlSupported(): bool
|
||||
{
|
||||
foreach (self::$pcntlFunctions as $func) {
|
||||
if (!\function_exists($func)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether required pcntl functions are disabled.
|
||||
*/
|
||||
public static function disabledPcntlFunctions()
|
||||
{
|
||||
return self::checkDisabledFunctions(self::$pcntlFunctions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that all required posix functions are, in fact, available.
|
||||
*/
|
||||
public static function isPosixSupported(): bool
|
||||
{
|
||||
foreach (self::$posixFunctions as $func) {
|
||||
if (!\function_exists($func)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether required posix functions are disabled.
|
||||
*/
|
||||
public static function disabledPosixFunctions()
|
||||
{
|
||||
return self::checkDisabledFunctions(self::$posixFunctions);
|
||||
}
|
||||
|
||||
private static function checkDisabledFunctions(array $functions): array
|
||||
{
|
||||
return \array_values(\array_intersect($functions, \array_map('strtolower', \array_map('trim', \explode(',', \ini_get('disable_functions'))))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Forks into a main and a loop process.
|
||||
*
|
||||
* The loop process will handle the evaluation of all instructions, then
|
||||
* return its state via a socket upon completion.
|
||||
@@ -46,7 +108,7 @@ class ProcessForker extends AbstractListener
|
||||
*/
|
||||
public function beforeRun(Shell $shell)
|
||||
{
|
||||
list($up, $down) = \stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
|
||||
list($up, $down) = \stream_socket_pair(\STREAM_PF_UNIX, \STREAM_SOCK_STREAM, \STREAM_IPPROTO_IP);
|
||||
|
||||
if (!$up) {
|
||||
throw new \RuntimeException('Unable to create socket pair');
|
||||
@@ -62,8 +124,8 @@ class ProcessForker extends AbstractListener
|
||||
\fclose($up);
|
||||
|
||||
// Wait for a return value from the loop process.
|
||||
$read = [$down];
|
||||
$write = null;
|
||||
$read = [$down];
|
||||
$write = null;
|
||||
$except = null;
|
||||
|
||||
do {
|
||||
@@ -95,8 +157,11 @@ class ProcessForker extends AbstractListener
|
||||
}
|
||||
|
||||
// This is the child process. It's going to do all the work.
|
||||
if (\function_exists('setproctitle')) {
|
||||
setproctitle('psysh (loop)');
|
||||
if (!@\cli_set_process_title('psysh (loop)')) {
|
||||
// Fall back to `setproctitle` if that wasn't succesful.
|
||||
if (\function_exists('setproctitle')) {
|
||||
@\setproctitle('psysh (loop)');
|
||||
}
|
||||
}
|
||||
|
||||
// We won't be needing this one.
|
||||
@@ -125,7 +190,7 @@ class ProcessForker extends AbstractListener
|
||||
{
|
||||
// if there's an old savegame hanging around, let's kill it.
|
||||
if (isset($this->savegame)) {
|
||||
\posix_kill($this->savegame, SIGKILL);
|
||||
\posix_kill($this->savegame, \SIGKILL);
|
||||
\pcntl_signal_dispatch();
|
||||
}
|
||||
}
|
||||
@@ -143,7 +208,7 @@ class ProcessForker extends AbstractListener
|
||||
\fwrite($this->up, $this->serializeReturn($shell->getScopeVariables(false)));
|
||||
\fclose($this->up);
|
||||
|
||||
\posix_kill(\posix_getpid(), SIGKILL);
|
||||
\posix_kill(\posix_getpid(), \SIGKILL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +233,7 @@ class ProcessForker extends AbstractListener
|
||||
|
||||
// worker exited cleanly, let's bail
|
||||
if (!\pcntl_wexitstatus($status)) {
|
||||
\posix_kill(\posix_getpid(), SIGKILL);
|
||||
\posix_kill(\posix_getpid(), \SIGKILL);
|
||||
}
|
||||
|
||||
// worker didn't exit cleanly, we'll need to have another go
|
||||
@@ -188,7 +253,7 @@ class ProcessForker extends AbstractListener
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function serializeReturn(array $return)
|
||||
private function serializeReturn(array $return): string
|
||||
{
|
||||
$serializable = [];
|
||||
|
||||
@@ -203,14 +268,19 @@ class ProcessForker extends AbstractListener
|
||||
continue;
|
||||
}
|
||||
|
||||
if (\version_compare(\PHP_VERSION, '8.1', '>=') && $value instanceof \UnitEnum) {
|
||||
// Enums defined in the REPL session can't be unserialized.
|
||||
$ref = new \ReflectionObject($value);
|
||||
if (\strpos($ref->getFileName(), ": eval()'d code") !== false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@\serialize($value);
|
||||
$serializable[$key] = $value;
|
||||
} catch (\Throwable $e) {
|
||||
// we'll just ignore this one...
|
||||
} catch (\Exception $e) {
|
||||
// and this one too...
|
||||
// @todo remove this once we don't support PHP 5.x anymore :)
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user