mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-05 19:42:38 +02:00
288 lines
8.2 KiB
PHP
288 lines
8.2 KiB
PHP
#!/usr/bin/env php
|
|
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace JetBrains\PHPStormStub;
|
|
|
|
use DirectoryIterator;
|
|
use RecursiveDirectoryIterator;
|
|
use RecursiveIteratorIterator;
|
|
use SplFileInfo;
|
|
use Exception;
|
|
use PhpParser\Node;
|
|
use PhpParser\NodeTraverser;
|
|
use PhpParser\NodeVisitor\NameResolver;
|
|
use PhpParser\NodeVisitorAbstract;
|
|
use PhpParser\ParserFactory;
|
|
use PhpParser\PrettyPrinter\Standard;
|
|
use RuntimeException;
|
|
use function array_map;
|
|
use function count;
|
|
use function file_get_contents;
|
|
use function file_put_contents;
|
|
use function in_array;
|
|
use function ksort;
|
|
use function preg_match;
|
|
use function sprintf;
|
|
use function str_replace;
|
|
use function strlen;
|
|
use function strtolower;
|
|
use function substr;
|
|
use function var_export;
|
|
use const PHP_EOL;
|
|
|
|
(function (): void {
|
|
require __DIR__ . '/vendor/autoload.php';
|
|
|
|
$mapFile = __DIR__ . '/PhpStormStubsMap.php';
|
|
|
|
class InvalidConstantNode extends RuntimeException
|
|
{
|
|
public static function create(Node $node): self
|
|
{
|
|
return new self(sprintf(
|
|
'Invalid constant node (first 50 characters: %s)',
|
|
substr((new Standard())->prettyPrint([$node]), 0, 50)
|
|
));
|
|
}
|
|
}
|
|
|
|
class InvalidFileLocation extends RuntimeException
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @throws InvalidFileLocation
|
|
*/
|
|
function assertReadableFile(string $filename): void
|
|
{
|
|
if (empty($filename)) {
|
|
throw new InvalidFileLocation('Filename was empty');
|
|
}
|
|
if (!file_exists($filename)) {
|
|
throw new InvalidFileLocation(sprintf('File "%s" does not exist', $filename));
|
|
}
|
|
if (!is_readable($filename)) {
|
|
throw new InvalidFileLocation(sprintf('File "%s" is not readable', $filename));
|
|
}
|
|
if (!is_file($filename)) {
|
|
throw new InvalidFileLocation(sprintf('"%s" is not a file', $filename));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @throws InvalidConstantNode
|
|
*/
|
|
function assertValidDefineFunctionCall(Node\Expr\FuncCall $node): void
|
|
{
|
|
if (!($node->name instanceof Node\Name)) {
|
|
throw InvalidConstantNode::create($node);
|
|
}
|
|
if ($node->name->toLowerString() !== 'define') {
|
|
throw InvalidConstantNode::create($node);
|
|
}
|
|
if (!in_array(count($node->args), [2, 3], true)) {
|
|
throw InvalidConstantNode::create($node);
|
|
}
|
|
if (!($node->args[0]->value instanceof Node\Scalar\String_)) {
|
|
throw InvalidConstantNode::create($node);
|
|
}
|
|
$valueNode = $node->args[1]->value;
|
|
if ($valueNode instanceof Node\Expr\FuncCall) {
|
|
throw InvalidConstantNode::create($node);
|
|
}
|
|
if ($valueNode instanceof Node\Expr\Variable) {
|
|
throw InvalidConstantNode::create($node);
|
|
}
|
|
}
|
|
|
|
$phpStormStubsDirectory = __DIR__;
|
|
|
|
$fileVisitor = new class() extends NodeVisitorAbstract
|
|
{
|
|
/** @var string[] */
|
|
private $classNames = [];
|
|
|
|
/** @var string[] */
|
|
private $functionNames = [];
|
|
|
|
/** @var string[] */
|
|
private $constantNames = [];
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function enterNode(Node $node): ?int
|
|
{
|
|
if ($node instanceof Node\Stmt\ClassLike) {
|
|
$this->classNames[] = $node->namespacedName->toString();
|
|
|
|
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
|
|
}
|
|
|
|
if ($node instanceof Node\Stmt\Function_) {
|
|
$this->functionNames[] = $node->namespacedName->toString();
|
|
|
|
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
|
|
}
|
|
|
|
if ($node instanceof Node\Const_) {
|
|
$this->constantNames[] = $node->namespacedName->toString();
|
|
|
|
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
|
|
}
|
|
|
|
if ($node instanceof Node\Expr\FuncCall) {
|
|
try {
|
|
assertValidDefineFunctionCall($node);
|
|
} catch (InvalidConstantNode $e) {
|
|
return null;
|
|
}
|
|
|
|
/** @var Node\Scalar\String_ $nameNode */
|
|
$nameNode = $node->args[0]->value;
|
|
|
|
if (count($node->args) === 3
|
|
&& $node->args[2]->value instanceof Node\Expr\ConstFetch
|
|
&& $node->args[2]->value->name->toLowerString() === 'true'
|
|
) {
|
|
$this->constantNames[] = strtolower($nameNode->value);
|
|
}
|
|
|
|
$this->constantNames[] = $nameNode->value;
|
|
|
|
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getClassNames(): array
|
|
{
|
|
return $this->classNames;
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getFunctionNames(): array
|
|
{
|
|
return $this->functionNames;
|
|
}
|
|
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
public function getConstantNames(): array
|
|
{
|
|
return $this->constantNames;
|
|
}
|
|
|
|
public function clear(): void
|
|
{
|
|
$this->classNames = [];
|
|
$this->functionNames = [];
|
|
$this->constantNames = [];
|
|
}
|
|
};
|
|
|
|
$phpParser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
|
|
|
|
$nodeTraverser = new NodeTraverser();
|
|
$nodeTraverser->addVisitor(new NameResolver());
|
|
$nodeTraverser->addVisitor($fileVisitor);
|
|
|
|
$map = ['classes' => [], 'functions' => [], 'constants' => []];
|
|
|
|
foreach (new DirectoryIterator($phpStormStubsDirectory) as $directoryInfo) {
|
|
/** @var DirectoryIterator $directoryInfo */
|
|
if ($directoryInfo->isDot()) {
|
|
continue;
|
|
}
|
|
|
|
if (!$directoryInfo->isDir()) {
|
|
continue;
|
|
}
|
|
|
|
if (in_array($directoryInfo->getBasename(), ['tests', 'meta', 'vendor'], true)) {
|
|
continue;
|
|
}
|
|
|
|
$iterator = new RecursiveIteratorIterator(
|
|
new RecursiveDirectoryIterator($directoryInfo->getPathName(), RecursiveDirectoryIterator::SKIP_DOTS)
|
|
);
|
|
|
|
/** @var SplFileInfo $fileInfo */
|
|
foreach ($iterator as $fileInfo) {
|
|
if (!preg_match('/\.php$/', $fileInfo->getBasename())) {
|
|
continue;
|
|
}
|
|
|
|
assertReadableFile($fileInfo->getPathname());
|
|
|
|
echo sprintf('Parsing "%s"', $fileInfo->getPathname()) . PHP_EOL;
|
|
|
|
$ast = $phpParser->parse(file_get_contents($fileInfo->getPathname()));
|
|
|
|
$nodeTraverser->traverse($ast);
|
|
|
|
foreach ($fileVisitor->getClassNames() as $className) {
|
|
$map['classes'][$className] = $fileInfo->getPathname();
|
|
}
|
|
|
|
foreach ($fileVisitor->getFunctionNames() as $functionName) {
|
|
$map['functions'][$functionName] = $fileInfo->getPathname();
|
|
}
|
|
|
|
foreach ($fileVisitor->getConstantNames() as $constantName) {
|
|
$map['constants'][$constantName] = $fileInfo->getPathname();
|
|
}
|
|
|
|
$fileVisitor->clear();
|
|
}
|
|
}
|
|
|
|
$mapWithRelativeFilePaths = array_map(static function (array $files) use ($phpStormStubsDirectory) : array {
|
|
ksort($files);
|
|
|
|
return array_map(static function (string $filePath) use ($phpStormStubsDirectory) : string {
|
|
return str_replace('\\', '/', substr($filePath, strlen($phpStormStubsDirectory) + 1));
|
|
}, $files);
|
|
}, $map);
|
|
|
|
$exportedClasses = var_export($mapWithRelativeFilePaths['classes'], true);
|
|
$exportedFunctions = var_export($mapWithRelativeFilePaths['functions'], true);
|
|
$exportedConstants = var_export($mapWithRelativeFilePaths['constants'], true);
|
|
|
|
$output = <<<"PHP"
|
|
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace JetBrains\PHPStormStub;
|
|
|
|
/**
|
|
* This is a generated file, do not modify it directly!
|
|
*/
|
|
final class PhpStormStubsMap
|
|
{
|
|
const CLASSES = {$exportedClasses};
|
|
|
|
const FUNCTIONS = {$exportedFunctions};
|
|
|
|
const CONSTANTS = {$exportedConstants};
|
|
}
|
|
PHP;
|
|
|
|
$bytesWritten = @file_put_contents($mapFile, $output, LOCK_EX);
|
|
|
|
if ($bytesWritten === false) {
|
|
throw new Exception(sprintf('File "%s" is not writeable.', $mapFile));
|
|
}
|
|
|
|
exit('Done' . PHP_EOL);
|
|
})();
|