debug
This commit is contained in:
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
Condorcet PHP - Election manager and results calculator.
|
||||
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||
|
||||
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||
https://github.com/julien-boudry/Condorcet
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class Description
|
||||
{
|
||||
public readonly string $text;
|
||||
|
||||
public function __construct(string $text)
|
||||
{
|
||||
$this->text = $text;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/*
|
||||
Condorcet PHP - Election manager and results calculator.
|
||||
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||
|
||||
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||
https://github.com/julien-boudry/Condorcet
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Example
|
||||
{
|
||||
public readonly string $name;
|
||||
public readonly string $link;
|
||||
|
||||
public function __construct(string $name, string $link)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->link = $link;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
Condorcet PHP - Election manager and results calculator.
|
||||
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||
|
||||
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||
https://github.com/julien-boudry/Condorcet
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||
class FunctionParameter
|
||||
{
|
||||
public readonly string $text;
|
||||
|
||||
public function __construct(string $text)
|
||||
{
|
||||
$this->text = (mb_substr($text, -1) === '.') ? $text : $text.'.';
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
Condorcet PHP - Election manager and results calculator.
|
||||
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||
|
||||
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||
https://github.com/julien-boudry/Condorcet
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class FunctionReturn
|
||||
{
|
||||
public readonly string $text;
|
||||
|
||||
public function __construct(string $text)
|
||||
{
|
||||
$this->text = $text;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/*
|
||||
Condorcet PHP - Election manager and results calculator.
|
||||
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||
|
||||
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||
https://github.com/julien-boudry/Condorcet
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS_CONSTANT | Attribute::TARGET_CLASS)]
|
||||
class InternalModulesAPI
|
||||
{
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/*
|
||||
Condorcet PHP - Election manager and results calculator.
|
||||
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||
|
||||
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||
https://github.com/julien-boudry/Condorcet
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS_CONSTANT | Attribute::TARGET_CLASS)]
|
||||
class PublicAPI extends InternalModulesAPI
|
||||
{
|
||||
public function __construct(string ...$class)
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
Condorcet PHP - Election manager and results calculator.
|
||||
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||
|
||||
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||
https://github.com/julien-boudry/Condorcet
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class Related
|
||||
{
|
||||
public readonly array $relatedList;
|
||||
|
||||
public function __construct(string ...$relatedList)
|
||||
{
|
||||
$this->relatedList = $relatedList;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/*
|
||||
Condorcet PHP - Election manager and results calculator.
|
||||
Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
|
||||
|
||||
By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
|
||||
https://github.com/julien-boudry/Condorcet
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class Throws
|
||||
{
|
||||
public array $exceptionList;
|
||||
|
||||
public function __construct(string ...$exceptionList)
|
||||
{
|
||||
$this->exceptionList = $exceptionList;
|
||||
}
|
||||
}
|
@ -0,0 +1,580 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator;
|
||||
|
||||
use CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes\{Description, Example, FunctionParameter, FunctionReturn, PublicAPI, Related, Throws};
|
||||
use HaydenPierce\ClassFinder\ClassFinder;
|
||||
|
||||
class Generate
|
||||
{
|
||||
// Static - Translators
|
||||
|
||||
public static function makeFilename(\ReflectionMethod $method): string
|
||||
{
|
||||
return self::getModifiersName($method).
|
||||
' '.
|
||||
str_replace('\\', '_', self::simpleClass($method->class)).'--'.$method->name.
|
||||
'.md';
|
||||
}
|
||||
|
||||
public static function simpleClass(string $fullClassName): string
|
||||
{
|
||||
return str_replace('CondorcetPHP\\Condorcet\\', '', $fullClassName);
|
||||
}
|
||||
|
||||
public static function speakBool($c): string
|
||||
{
|
||||
if ($c === true || $c === 'true') {
|
||||
return 'true';
|
||||
}
|
||||
if ($c === false || $c === 'false') {
|
||||
return 'false';
|
||||
}
|
||||
if ($c === null || $c === 'null') {
|
||||
return 'null';
|
||||
}
|
||||
if (\is_array($c)) {
|
||||
return '['.implode(',', $c).']';
|
||||
}
|
||||
if (\is_object($c)) {
|
||||
return 'new '.$c::class;
|
||||
}
|
||||
|
||||
return (string) $c;
|
||||
}
|
||||
|
||||
public static function getTypeAsString(?\ReflectionType $rf_rt, bool $codeBlock = false): ?string
|
||||
{
|
||||
if ($rf_rt !== null) {
|
||||
if ($codeBlock) {
|
||||
return '```'.((string) $rf_rt).'```';
|
||||
} else {
|
||||
return (string) $rf_rt;
|
||||
}
|
||||
}
|
||||
|
||||
return $rf_rt;
|
||||
}
|
||||
|
||||
public static function getModifiersName(\ReflectionMethod $method): string
|
||||
{
|
||||
return implode(' ', \Reflection::getModifierNames($method->getModifiers()));
|
||||
}
|
||||
|
||||
// Static - Builder
|
||||
|
||||
public static function cleverRelated(string $name): string
|
||||
{
|
||||
$infos = explode('::', $name);
|
||||
$infos[0] = str_replace('static ', '', $infos[0]);
|
||||
|
||||
$url = '../'.$infos[0].' Class/public '.str_replace('::', '--', $name) . '.md';
|
||||
$url = str_replace(' ', '%20', $url);
|
||||
|
||||
return '['.$name.']('.$url.')';
|
||||
}
|
||||
|
||||
public static function computeRepresentationAsForIndex(\ReflectionMethod $method): string
|
||||
{
|
||||
return self::getModifiersName($method).
|
||||
' '.
|
||||
self::simpleClass($method->class).
|
||||
(($method->isStatic()) ? '::' : '->').
|
||||
$method->name.
|
||||
' ('.(($method->getNumberOfParameters() > 0) ? '...' : '').')';
|
||||
}
|
||||
|
||||
public static function computeRepresentationAsPHP(\ReflectionMethod $method): string
|
||||
{
|
||||
$option = false;
|
||||
$str = '(';
|
||||
$i = 0;
|
||||
|
||||
|
||||
if ($method->getNumberOfParameters() > 0) {
|
||||
foreach ($method->getParameters() as $value) {
|
||||
$str .= ' ';
|
||||
$str .= ($value->isOptional() && !$option) ? '[' : '';
|
||||
$str .= ($i > 0) ? ', ' : '';
|
||||
$str .= self::getTypeAsString($value->getType());
|
||||
$str .= ' ';
|
||||
$str .= $value->isPassedByReference() ? '&' : '';
|
||||
$str .= '$'.$value->getName();
|
||||
$str .= $value->isDefaultValueAvailable() ? ' = '.self::speakBool($value->getDefaultValue()) : '';
|
||||
|
||||
($value->isOptional() && !$option) ? $option = true : null;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($option) {
|
||||
$str .= ']';
|
||||
}
|
||||
|
||||
$str .= ' )';
|
||||
|
||||
return "```php\n".
|
||||
self::getModifiersName($method).' '.self::simpleClass($method->class).(($method->isStatic()) ? '::' : '->').$method->name.' '.$str. ((self::getTypeAsString($method->getReturnType()) !== null) ? ': '.self::getTypeAsString($method->getReturnType()) : '').
|
||||
"\n```";
|
||||
}
|
||||
|
||||
|
||||
// Script
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$start_time = microtime(true);
|
||||
|
||||
$pathDirectory = $path.\DIRECTORY_SEPARATOR;
|
||||
|
||||
//
|
||||
$FullClassList = ClassFinder::getClassesInNamespace('CondorcetPHP\Condorcet\\', ClassFinder::RECURSIVE_MODE);
|
||||
$FullClassList = array_filter($FullClassList, static function (string $value) {
|
||||
return (mb_strpos($value, 'Condorcet\Test') === false) && (mb_strpos($value, 'Condorcet\Dev') === false);
|
||||
});
|
||||
|
||||
$inDoc = 0;
|
||||
$non_inDoc = 0;
|
||||
$total_methods = 0;
|
||||
$total_nonInternal_methods = 0;
|
||||
|
||||
// Warnings
|
||||
foreach ($FullClassList as $FullClass) {
|
||||
$methods = (new \ReflectionClass($FullClass))->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||
|
||||
foreach ($methods as $oneMethod) {
|
||||
if ($oneMethod->isInternal()) {
|
||||
} elseif (!empty($oneMethod->getAttributes(PublicAPI::class))) {
|
||||
$inDoc++;
|
||||
|
||||
if ($oneMethod->getNumberOfParameters() > 0) {
|
||||
foreach ($oneMethod->getParameters() as $oneParameter) {
|
||||
if (empty($oneParameter->getAttributes(FunctionParameter::class))) {
|
||||
var_dump('Method Has Public API attribute but parameter $'.$oneParameter->getName().' is undocumented '.$oneMethod->getDeclaringClass()->getName().'->'.$oneMethod->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($oneMethod->getAttributes(Description::class)) && $oneMethod->getDeclaringClass()->getNamespaceName() !== '') {
|
||||
var_dump('Description Attribute is empty: '.$oneMethod->getDeclaringClass()->getName().'->'.$oneMethod->getName());
|
||||
}
|
||||
} else {
|
||||
$non_inDoc++;
|
||||
|
||||
if (empty($oneMethod->getAttributes(PublicAPI::class)) && $oneMethod->getDeclaringClass()->getNamespaceName() !== '') {
|
||||
// var_dump('Method not has API attribute: '.$oneMethod->getDeclaringClass()->getName().'->'.$oneMethod->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$full_methods_list = [];
|
||||
|
||||
// generate .md
|
||||
foreach ($FullClassList as $FullClass) {
|
||||
$reflectionClass = new \ReflectionClass($FullClass);
|
||||
$methods = ($reflectionClass)->getMethods();
|
||||
$shortClass = str_replace('CondorcetPHP\Condorcet\\', '', $FullClass);
|
||||
|
||||
$full_methods_list[$shortClass] = [
|
||||
'FullClass' => $FullClass,
|
||||
'shortClass' => $shortClass,
|
||||
'ReflectionClass' => $reflectionClass,
|
||||
'methods' => [],
|
||||
];
|
||||
|
||||
foreach ($methods as $oneMethod) {
|
||||
$method_array = $full_methods_list[$shortClass]['methods'][$oneMethod->name] = [
|
||||
'FullClass' => $FullClass,
|
||||
'shortClass' => $shortClass,
|
||||
'name' => $oneMethod->name,
|
||||
'static' => $oneMethod->isStatic(),
|
||||
'visibility_public' => $oneMethod->isPublic(),
|
||||
'visibility_protected' => $oneMethod->isProtected(),
|
||||
'visibility_private' => $oneMethod->isPrivate(),
|
||||
'ReflectionMethod' => $oneMethod,
|
||||
'ReflectionClass' => $oneMethod->getDeclaringClass(),
|
||||
];
|
||||
|
||||
$total_methods++;
|
||||
|
||||
if (!$oneMethod->isInternal()) {
|
||||
$total_nonInternal_methods++;
|
||||
}
|
||||
|
||||
// Write Markdown
|
||||
if (!empty($apiAttribute = $oneMethod->getAttributes(PublicAPI::class)) && (empty($apiAttribute[0]->getArguments()) || \in_array(self::simpleClass($oneMethod->class), $apiAttribute[0]->getArguments(), true))) {
|
||||
$path = $pathDirectory . str_replace('\\', '_', self::simpleClass($oneMethod->class)) . ' Class/';
|
||||
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path);
|
||||
}
|
||||
|
||||
file_put_contents($path.self::makeFilename($oneMethod), $this->createMarkdownContent($oneMethod, $method_array));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
print 'Public methods in doc: '.$inDoc.' / '.($inDoc + $non_inDoc).' | Total non-internal methods count: '.$total_nonInternal_methods.' | Number of Class: '.\count($FullClassList).' | Number of Methods including internals: '.$total_methods."\n";
|
||||
|
||||
// Add Index
|
||||
$file_content = "> **[Presentation](../README.md) | [Manual](https://github.com/julien-boudry/Condorcet/wiki) | Methods References | [Tests](../Tests)**\n\n".
|
||||
|
||||
"# Public API Index*_\n".
|
||||
|
||||
"_*: I try to update and complete the documentation. See also [the manual](https://github.com/julien-boudry/Condorcet/wiki), [the tests](../Tests) also produce many examples. And create issues for questions or fixing documentation!_\n\n";
|
||||
|
||||
|
||||
$file_content .= $this->makeIndex($full_methods_list);
|
||||
|
||||
$file_content .= "\n\n\n";
|
||||
|
||||
uksort($full_methods_list, 'strnatcmp');
|
||||
$file_content .= "# Full Class & Methods References\n".
|
||||
"_Including above methods from public API_\n\n";
|
||||
|
||||
$file_content .= $this->makeProfundis($full_methods_list);
|
||||
|
||||
|
||||
// Write file
|
||||
file_put_contents($pathDirectory.'README.md', $file_content);
|
||||
|
||||
|
||||
echo 'YAH ! <br>' . (microtime(true) - $start_time) .'s';
|
||||
}
|
||||
|
||||
|
||||
// Build Methods
|
||||
|
||||
protected function createMarkdownContent(\ReflectionMethod $method, array $entry): string
|
||||
{
|
||||
// Header
|
||||
$md = '## '.self::getModifiersName($method).' '. self::simpleClass($method->class).'::'.$method->name."\n\n".
|
||||
"### Description \n\n".
|
||||
self::computeRepresentationAsPHP($method)."\n\n".
|
||||
$method->getAttributes(Description::class)[0]->getArguments()[0]."\n ";
|
||||
|
||||
// Input
|
||||
if ($method->getNumberOfParameters() > 0) {
|
||||
foreach ($method->getParameters() as $key => $value) {
|
||||
if (!empty($attributes = $value->getAttributes(FunctionParameter::class))) {
|
||||
$pt = $attributes[0]->newInstance()->text;
|
||||
} elseif (isset($entry['input'][$value->getName()]['text'])) {
|
||||
$pt = $entry['input'][$value->getName()]['text'];
|
||||
} else {
|
||||
$pt = '';
|
||||
}
|
||||
|
||||
$md .= "\n\n".
|
||||
'##### **'.$value->getName().':** *'.self::getTypeAsString($value->getType(), true)."* \n".
|
||||
$pt." \n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return Value
|
||||
|
||||
if (!empty($method->getAttributes(FunctionReturn::class))) {
|
||||
$md .= "\n\n".
|
||||
"### Return value: \n\n".
|
||||
'*('.self::getTypeAsString($method->getReturnType(), true).')* '.$method->getAttributes(FunctionReturn::class)[0]->getArguments()[0]."\n\n";
|
||||
}
|
||||
|
||||
// Throw
|
||||
if (!empty($method->getAttributes(Throws::class))) {
|
||||
$md .= "\n\n".
|
||||
"### Throws: \n\n";
|
||||
|
||||
foreach ($method->getAttributes(Throws::class)[0]->getArguments() as $arg) {
|
||||
$md .= '* ```'.$arg."```\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Related methods
|
||||
|
||||
if (!empty($method->getAttributes(Related::class))) {
|
||||
$md .= "\n".
|
||||
"---------------------------------------\n\n".
|
||||
"### Related method(s) \n\n";
|
||||
|
||||
foreach ($method->getAttributes(Related::class) as $RelatedAttribute) {
|
||||
foreach ($RelatedAttribute->newInstance()->relatedList as $value) {
|
||||
if ($value === self::simpleClass($method->class).'::'.$method->name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$md .= '* '.self::cleverRelated($value)." \n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($method->getAttributes(Example::class))) {
|
||||
$md .= "\n".
|
||||
"---------------------------------------\n\n".
|
||||
"### Examples and explanation\n\n";
|
||||
|
||||
foreach ($method->getAttributes(Example::class) as $ExampleAttribute) {
|
||||
$ExampleAttribute = $ExampleAttribute->newInstance();
|
||||
|
||||
$md .= '* **['.$ExampleAttribute->name.']('.$ExampleAttribute->link.")** \n";
|
||||
}
|
||||
}
|
||||
|
||||
return $md;
|
||||
}
|
||||
|
||||
protected function makeIndex(array $index): string
|
||||
{
|
||||
$file_content = '';
|
||||
|
||||
$testPublicAttribute = static function (\ReflectionMethod $reflectionMethod): bool {
|
||||
return !(empty($apiAttribute = $reflectionMethod->getAttributes(PublicAPI::class)) || (!empty($apiAttribute[0]->getArguments()) && !\in_array(self::simpleClass($reflectionMethod->class), $apiAttribute[0]->getArguments(), true)));
|
||||
};
|
||||
|
||||
foreach ($index as $class => &$classMeta) {
|
||||
usort($classMeta['methods'], static function (array $a, array $b): int {
|
||||
if ($a['ReflectionMethod']->isStatic() === $b['ReflectionMethod']->isStatic()) {
|
||||
return strnatcmp($a['ReflectionMethod']->name, $b['ReflectionMethod']->name);
|
||||
} elseif ($a['ReflectionMethod']->isStatic() && !$b['ReflectionMethod']->isStatic()) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
$classWillBePublic = false;
|
||||
|
||||
if ($classMeta['ReflectionClass']->getAttributes(PublicAPI::class)) {
|
||||
$classWillBePublic = true;
|
||||
} else {
|
||||
foreach ($classMeta['methods'] as $oneMethod) {
|
||||
if ($testPublicAttribute($oneMethod['ReflectionMethod'])) {
|
||||
$classWillBePublic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($classMeta['ReflectionClass']->getReflectionConstants() as $oneConstant) {
|
||||
if (!empty($oneConstant->getAttributes(PublicAPI::class))) {
|
||||
$classWillBePublic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($classMeta['ReflectionClass']->getProperties() as $onePropertie) {
|
||||
if (!empty($onePropertie->getAttributes(PublicAPI::class))) {
|
||||
$classWillBePublic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($classWillBePublic) {
|
||||
$isEnum = enum_exists(($enumCases = $classMeta['ReflectionClass'])->name);
|
||||
|
||||
$file_content .= "\n";
|
||||
$file_content .= '### CondorcetPHP\Condorcet\\'.$class.' '.((!$isEnum) ? 'Class' : 'Enum')." \n\n";
|
||||
|
||||
if ($isEnum) {
|
||||
$file_content .= $this->makeEnumeCases(new \ReflectionEnum($enumCases->name), false);
|
||||
$file_content .= "\n";
|
||||
} else {
|
||||
$file_content .= $this->makeConstants($classMeta['ReflectionClass'], \ReflectionClassConstant::IS_PUBLIC, true);
|
||||
}
|
||||
|
||||
$file_content .= $this->makeProperties($classMeta['ReflectionClass'], null, true);
|
||||
}
|
||||
|
||||
|
||||
foreach ($classMeta['methods'] as $oneMethod) {
|
||||
if (!$testPublicAttribute($oneMethod['ReflectionMethod']) || !$oneMethod['ReflectionMethod']->isUserDefined()) {
|
||||
continue;
|
||||
} else {
|
||||
$url = str_replace('\\', '_', self::simpleClass($oneMethod['ReflectionMethod']->class)).' Class/'.self::getModifiersName($oneMethod['ReflectionMethod']).' '. str_replace('\\', '_', self::simpleClass($oneMethod['ReflectionMethod']->class).'--'. $oneMethod['ReflectionMethod']->name) . '.md';
|
||||
$url = str_replace(' ', '%20', $url);
|
||||
|
||||
$file_content .= '* ['.self::computeRepresentationAsForIndex($oneMethod['ReflectionMethod']).']('.$url.')';
|
||||
|
||||
if (isset($oneMethod['ReflectionMethod']) && $oneMethod['ReflectionMethod']->hasReturnType()) {
|
||||
$file_content .= ': '.self::getTypeAsString($oneMethod['ReflectionMethod']->getReturnType(), true);
|
||||
}
|
||||
|
||||
$file_content .= " \n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $file_content;
|
||||
}
|
||||
|
||||
protected function makeEnumeCases(\ReflectionEnum $enumReflection, bool $shortName = false): string
|
||||
{
|
||||
$cases = $enumReflection->getCases();
|
||||
|
||||
$r = '';
|
||||
|
||||
foreach ($cases as $oneCase) {
|
||||
$name = ($shortName) ? $enumReflection->getShortName() : self::simpleClass($enumReflection->getName());
|
||||
$r .= '* ```case '.$name.'::'.$oneCase->getName()."``` \n";
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
protected function makeConstants(\ReflectionClass $class, ?int $type = null, bool $mustHaveApiAttribute = false, bool $addMdCodeTag = true): string
|
||||
{
|
||||
$file_content = '';
|
||||
|
||||
$hasConstants = false;
|
||||
|
||||
foreach ($class->getReflectionConstants($type) as $constant) {
|
||||
if (!$mustHaveApiAttribute || !empty($constant->getAttributes(PublicAPI::class))) {
|
||||
$file_content .= '* ';
|
||||
$file_content .= $addMdCodeTag ? '```' : '';
|
||||
|
||||
$file_content .= $constant->isFinal() ? 'final ' : '';
|
||||
|
||||
$file_content .= $constant->isPublic() ? 'public' : '';
|
||||
$file_content .= $constant->isProtected() ? 'protected' : '';
|
||||
$file_content .= $constant->isPrivate() ? 'private' : '';
|
||||
|
||||
$file_content .= ' const '.$constant->getName().': ('.\gettype($constant->getValue()).')';
|
||||
$file_content .= $addMdCodeTag ? '``` ' : '';
|
||||
$file_content .= "\n";
|
||||
$hasConstants = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasConstants) {
|
||||
$file_content .= "\n";
|
||||
}
|
||||
|
||||
return $file_content;
|
||||
}
|
||||
|
||||
protected function makeProperties(\ReflectionClass $class, ?int $type = null, bool $mustHaveApiAttribute = false, bool $addMdCodeTag = true): string
|
||||
{
|
||||
$file_content = '';
|
||||
|
||||
$hasConstants = false;
|
||||
|
||||
foreach ($class->getProperties($type) as $propertie) {
|
||||
if (!$mustHaveApiAttribute || !empty($propertie->getAttributes(PublicAPI::class))) {
|
||||
$file_content .= '* ';
|
||||
$file_content .= $addMdCodeTag ? '```' : '';
|
||||
|
||||
$file_content .= $propertie->isReadOnly() ? 'readonly ' : '';
|
||||
|
||||
$file_content .= $propertie->isPublic() ? 'public ' : '';
|
||||
$file_content .= $propertie->isProtected() ? 'protected ' : '';
|
||||
$file_content .= $propertie->isPrivate() ? 'private ' : '';
|
||||
|
||||
$file_content .= $propertie->isStatic() ? 'static ' : '';
|
||||
|
||||
$file_content .= ((string) $propertie->getType()).' $'.$propertie->getName();
|
||||
$file_content .= $addMdCodeTag ? '``` ' : '';
|
||||
$file_content .= "\n";
|
||||
$hasConstants = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasConstants) {
|
||||
$file_content .= "\n";
|
||||
}
|
||||
|
||||
return $file_content;
|
||||
}
|
||||
|
||||
protected function makeProfundis(array $index): string
|
||||
{
|
||||
$file_content = '';
|
||||
|
||||
foreach ($index as $class => &$classMeta) {
|
||||
usort($classMeta['methods'], static function (array $a, array $b): int {
|
||||
if ($a['static'] === $b['static']) {
|
||||
if ($a['visibility_public'] && !$b['visibility_public']) {
|
||||
return -1;
|
||||
} elseif (!$a['visibility_public'] && $b['visibility_public']) {
|
||||
return 1;
|
||||
} else {
|
||||
if ($a['visibility_protected'] && !$b['visibility_protected']) {
|
||||
return -1;
|
||||
} elseif (!$a['visibility_protected'] && $b['visibility_protected']) {
|
||||
return 1;
|
||||
} else {
|
||||
return strnatcmp($a['name'], $b['name']);
|
||||
}
|
||||
}
|
||||
} elseif ($a['static'] && !$b['static']) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
$file_content .= "\n";
|
||||
$file_content .= '#### ';
|
||||
$file_content .= ($classMeta['ReflectionClass']->isAbstract()) ? 'Abstract ' : '';
|
||||
$file_content .= 'CondorcetPHP\Condorcet\\'.$class.' ';
|
||||
|
||||
$file_content .= ($p = $classMeta['ReflectionClass']->getParentClass()) ? 'extends '.$p->name.' ' : '';
|
||||
|
||||
$interfaces = implode(', ', $classMeta['ReflectionClass']->getInterfaceNames());
|
||||
$file_content .= (!empty($interfaces)) ? 'implements '.$interfaces : '';
|
||||
|
||||
$file_content .= " \n";
|
||||
$file_content .= "```php\n";
|
||||
|
||||
$isEnum = enum_exists(($enumCases = $classMeta['ReflectionClass'])->name);
|
||||
|
||||
if ($isEnum) {
|
||||
$file_content .= $this->makeEnumeCases(new \ReflectionEnum($enumCases->name), true);
|
||||
$file_content .= "\n";
|
||||
} else {
|
||||
$file_content .= $this->makeConstants(class: $classMeta['ReflectionClass'], addMdCodeTag: false);
|
||||
}
|
||||
|
||||
$file_content .= $this->makeProperties(class: $classMeta['ReflectionClass'], addMdCodeTag: false);
|
||||
|
||||
foreach ($classMeta['methods'] as $oneMethod) {
|
||||
if ($oneMethod['ReflectionMethod']->isUserDefined()) {
|
||||
$parameters = $oneMethod['ReflectionMethod']->getParameters();
|
||||
$parameters_string = '';
|
||||
|
||||
$i = 0;
|
||||
foreach ($parameters as $oneP) {
|
||||
$parameters_string .= (++$i > 1) ? ', ' : '';
|
||||
|
||||
if ($oneP->getType() !== null) {
|
||||
$parameters_string .= self::getTypeAsString($oneP->getType()) . ' ';
|
||||
}
|
||||
$parameters_string .= '$'.$oneP->name;
|
||||
|
||||
if ($oneP->isDefaultValueAvailable()) {
|
||||
$parameters_string .= ' = '.self::speakBool($oneP->getDefaultValue());
|
||||
}
|
||||
}
|
||||
|
||||
$representation = ($oneMethod['visibility_public']) ? 'public ' : '';
|
||||
$representation .= ($oneMethod['visibility_protected']) ? 'protected ' : '';
|
||||
$representation .= ($oneMethod['visibility_private']) ? 'private ' : '';
|
||||
|
||||
$representation .= ($oneMethod['static']) ? 'static ' : '';
|
||||
$representation .= $oneMethod['name'] . ' ('.$parameters_string.')';
|
||||
|
||||
if ($oneMethod['ReflectionMethod']->hasReturnType()) {
|
||||
$representation .= ': '.self::getTypeAsString($oneMethod['ReflectionMethod']->getReturnType());
|
||||
}
|
||||
|
||||
$file_content .= '* '.$representation." \n";
|
||||
}
|
||||
}
|
||||
|
||||
$file_content .= "```\n";
|
||||
}
|
||||
|
||||
return $file_content;
|
||||
}
|
||||
}
|
14
include/condorcet/Dev/Dockerfile.infection
Normal file
14
include/condorcet/Dev/Dockerfile.infection
Normal file
@ -0,0 +1,14 @@
|
||||
FROM condorcet
|
||||
|
||||
RUN pecl install pcov \
|
||||
&& docker-php-ext-enable pcov
|
||||
|
||||
RUN php composer.phar install --optimize-autoloader --no-progress \
|
||||
&& rm -rf /root/.composer/cache
|
||||
|
||||
ENTRYPOINT [ "vendor/bin/infection" ]
|
||||
|
||||
# Usage:
|
||||
# 1. docker build -f Dockerfile.infection -t infection .
|
||||
# 2. docker run --hostname="infection" --mount type=bind,src=$(pwd),dst=/usr/src/condorcetapp --rm -it infection:latest
|
||||
# The infection test takes a long time. You can use --filter to only test a portion of the code.
|
6
include/condorcet/Dev/Get_Some_Codes_Stats.md
Normal file
6
include/condorcet/Dev/Get_Some_Codes_Stats.md
Normal file
@ -0,0 +1,6 @@
|
||||
Get some codes stats:
|
||||
|
||||
```
|
||||
vendor/bin/phploc src Benchmarks Dev Tests Examples # With Test and Examples
|
||||
vendor/bin/phploc src Benchmarks Dev # Without Tests and Examples
|
||||
```
|
8
include/condorcet/Dev/Infection.md
Normal file
8
include/condorcet/Dev/Infection.md
Normal file
@ -0,0 +1,8 @@
|
||||
To generate Infection report:
|
||||
|
||||
_Customize with the right number of threads for your system._
|
||||
```
|
||||
php vendor/bin/infection --threads=24
|
||||
```
|
||||
|
||||
_Logs at the racine, infection.log_
|
@ -0,0 +1,83 @@
|
||||
2021-01-03 - > 7590291d
|
||||
|
||||
2479 mutations were generated:
|
||||
1872 mutants were killed
|
||||
14 mutants were not covered by tests
|
||||
427 covered mutants were not detected
|
||||
110 errors were encountered
|
||||
0 syntax errors were encountered
|
||||
56 time outs were encountered
|
||||
0 mutants required more time than configured
|
||||
|
||||
Metrics:
|
||||
Mutation Score Indicator (MSI): 82%
|
||||
Mutation Code Coverage: 99%
|
||||
Covered Code MSI: 82%
|
||||
|
||||
2021-09-28 - 9882d9c
|
||||
|
||||
2538 mutations were generated:
|
||||
1879 mutants were killed
|
||||
14 mutants were not covered by tests
|
||||
479 covered mutants were not detected
|
||||
110 errors were encountered
|
||||
0 syntax errors were encountered
|
||||
56 time outs were encountered
|
||||
0 mutants required more time than configured
|
||||
|
||||
Metrics:
|
||||
Mutation Score Indicator (MSI): 80%
|
||||
Mutation Code Coverage: 99%
|
||||
Covered Code MSI: 81%
|
||||
|
||||
|
||||
2021-09-20 - 24d4ba4
|
||||
|
||||
2586 mutations were generated:
|
||||
1892 mutants were killed
|
||||
42 mutants were not covered by tests
|
||||
479 covered mutants were not detected
|
||||
117 errors were encountered
|
||||
0 syntax errors were encountered
|
||||
56 time outs were encountered
|
||||
0 mutants required more time than configured
|
||||
|
||||
Metrics:
|
||||
Mutation Score Indicator (MSI): 79%
|
||||
Mutation Code Coverage: 98%
|
||||
Covered Code MSI: 81%
|
||||
|
||||
|
||||
2021-08-05 - 40bfb78
|
||||
|
||||
2685 mutations were generated:
|
||||
1962 mutants were killed
|
||||
53 mutants were not covered by tests
|
||||
492 covered mutants were not detected
|
||||
122 errors were encountered
|
||||
0 syntax errors were encountered
|
||||
56 time outs were encountered
|
||||
0 mutants required more time than configured
|
||||
|
||||
Metrics:
|
||||
Mutation Score Indicator (MSI): 79%
|
||||
Mutation Code Coverage: 98%
|
||||
Covered Code MSI: 81%
|
||||
|
||||
|
||||
2022-07-01 - 39b9c31
|
||||
|
||||
3207 mutations were generated:
|
||||
1229 mutants were killed
|
||||
0 mutants were configured to be ignored
|
||||
42 mutants were not covered by tests
|
||||
191 covered mutants were not detected
|
||||
1 errors were encountered
|
||||
0 syntax errors were encountered
|
||||
11 time outs were encountered
|
||||
1733 mutants required more time than configured
|
||||
|
||||
Metrics:
|
||||
Mutation Score Indicator (MSI): 84%
|
||||
Mutation Code Coverage: 97%
|
||||
Covered Code MSI: 86%
|
94
include/condorcet/Dev/bugs/JitBug.php
Normal file
94
include/condorcet/Dev/bugs/JitBug.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
// Linux: php -dzend_extension=opcache -dopcache.enable_cli=1 -dopcache.jit_buffer_size=100M -dopcache.jit=tracing Dev/bugs/JitBug.php
|
||||
// Windows: php -d zend_extension=opcache -d opcache.enable_cli=1 -d opcache.jit_buffer_size=100M -d opcache.jit=tracing Dev/bugs/JitBug.php
|
||||
|
||||
# Notes
|
||||
// Not happening on 8.1
|
||||
// Bug only with jit tracing mode (working with jit function) (test on PHP 8.0.10 NTS on x64)
|
||||
// Working with or without opcache
|
||||
|
||||
# Bugs
|
||||
// PHP Fatal error: Uncaught TypeError: CondorcetPHP\Condorcet\Result::__construct(): Argument #6 ($seats) must be of type ?int, CondorcetPHP\Condorcet\Election given, called in C:\dev_scripts\Condorcet\lib\Algo\Method.php on line 84 and defined in C:\dev_scripts\Condorcet\lib\Result.php:89
|
||||
// Stack trace:
|
||||
// #0 C:\dev_scripts\Condorcet\lib\Algo\Method.php(84): CondorcetPHP\Condorcet\Result->__construct()
|
||||
// #1 C:\dev_scripts\Condorcet\lib\Algo\Methods\STV\SingleTransferableVote.php(91): CondorcetPHP\Condorcet\Algo\Method->createResult()
|
||||
// #2 C:\dev_scripts\Condorcet\lib\Algo\Method.php(63): CondorcetPHP\Condorcet\Algo\Methods\STV\SingleTransferableVote->compute()
|
||||
// #3 C:\dev_scripts\Condorcet\lib\ElectionProcess\ResultsProcess.php(80): CondorcetPHP\Condorcet\Algo\Method->getResult()
|
||||
// #4 C:\dev_scripts\Condorcet\Dev\bugs\JitBug.php(24): CondorcetPHP\Condorcet\Election->getResult()
|
||||
// #5 {main}
|
||||
// thrown in C:\dev_scripts\Condorcet\lib\Result.php on line 89
|
||||
|
||||
# Test code
|
||||
|
||||
namespace CondorcetPHP\Condorcet;
|
||||
|
||||
require_once __DIR__.'/../../__CondorcetAutoload.php';
|
||||
|
||||
for ($i=1; $i <= 4000; $i++) {
|
||||
|
||||
# With Condorcet
|
||||
$election = new Election;
|
||||
|
||||
$election->parseCandidates('A;B;C');
|
||||
|
||||
$election->addVote('A>B>C');
|
||||
|
||||
$election->getResult('Schulze');
|
||||
$election->getResult('STV');
|
||||
|
||||
# Tentative to reproduce (impossible...)
|
||||
// $a = new A (new Bar);
|
||||
// $b = new B (new Bar);
|
||||
}
|
||||
|
||||
|
||||
# Tentative to reproduce (impossible...)
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function __construct(public string $fromMethod, public string $byClass, public Bar $election, public array $result, public $stats, public ?int $seats = null, public array $methodOptions = [])
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Bar
|
||||
{
|
||||
}
|
||||
|
||||
abstract class Base
|
||||
{
|
||||
public const IS_PROPORTIONAL = false;
|
||||
|
||||
public Foo $foo;
|
||||
|
||||
public function __construct(public Bar $barInstance)
|
||||
{
|
||||
$this->foo = new Foo(
|
||||
fromMethod: 'test',
|
||||
byClass: $this::class,
|
||||
election: $this->barInstance,
|
||||
result: [],
|
||||
stats: [],
|
||||
seats: (static::IS_PROPORTIONAL) ? $this->getSeats() : null,
|
||||
methodOptions: []
|
||||
);
|
||||
}
|
||||
|
||||
public function getSeats(): int
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
class A extends Base
|
||||
{
|
||||
public const IS_PROPORTIONAL = false;
|
||||
}
|
||||
|
||||
class B extends Base
|
||||
{
|
||||
public const IS_PROPORTIONAL = true;
|
||||
}
|
34
include/condorcet/Dev/generate-large-vote-input_file.php
Normal file
34
include/condorcet/Dev/generate-large-vote-input_file.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__.'/../__CondorcetAutoload.php';
|
||||
|
||||
///
|
||||
$number_of_votes = 100_000_000;
|
||||
$number_of_candidates = 8;
|
||||
///
|
||||
|
||||
$candidateName = 'A';
|
||||
|
||||
$candidates = [];
|
||||
|
||||
for ($i=0; $i < $number_of_candidates; $i++) {
|
||||
$candidates[] = $candidateName++;
|
||||
}
|
||||
|
||||
$file = new \SplFileObject(__DIR__.'/large.votes', 'w+');
|
||||
$cache = '';
|
||||
|
||||
for ($i=0; $i < $number_of_votes; $i++) {
|
||||
shuffle($candidates);
|
||||
|
||||
$cache .= implode('>', $candidates)."\n";
|
||||
|
||||
if (mb_strlen($cache) > 5_000_000) {
|
||||
$file->fwrite($cache);
|
||||
$cache = '';
|
||||
}
|
||||
}
|
||||
|
||||
$file->fwrite($cache);
|
@ -0,0 +1,5 @@
|
||||
To generate documentation:
|
||||
|
||||
```
|
||||
php Dev/update-documentation.php
|
||||
```
|
7
include/condorcet/Dev/interactiveShell.php
Normal file
7
include/condorcet/Dev/interactiveShell.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CondorcetPHP\Condorcet;
|
||||
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
130
include/condorcet/Dev/migrate_yamlDoc_to_attributes.php
Normal file
130
include/condorcet/Dev/migrate_yamlDoc_to_attributes.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\CondorcetDocAttributes\{PublicAPI};
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
require_once __DIR__.str_replace('/', \DIRECTORY_SEPARATOR, '/../vendor/../vendor/autoload.php');
|
||||
|
||||
|
||||
$doc = Yaml::parseFile(__DIR__.'/../Documentation/doc.yaml');
|
||||
|
||||
// Header & Prefix
|
||||
$header = $doc[0]['header'];
|
||||
unset($doc[0]);
|
||||
|
||||
$undocumented_prefix = $doc[1]['undocumented_prefix'] . "\n";
|
||||
unset($doc[1]);
|
||||
|
||||
|
||||
//
|
||||
$index = [];
|
||||
|
||||
foreach ($doc as &$entry) {
|
||||
if (!\is_array($entry['class'])) {
|
||||
$entry['class'] = [$entry['class']];
|
||||
}
|
||||
|
||||
foreach ($entry['class'] as $class) {
|
||||
$method = $entry;
|
||||
$method['class'] = $class;
|
||||
|
||||
$index[$method['class']][$method['name']] = $method;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$patternReplaceLastNewLine = '/(.*)\n$/';
|
||||
|
||||
foreach ($index as $ClassName => $ClassData) {
|
||||
$path_to_file = [
|
||||
__DIR__.'/../lib/'.str_replace('\\', '/', $ClassName).'.php',
|
||||
__DIR__.'/../lib/CondorcetVersion.php',
|
||||
__DIR__.'/../lib/Linkable.php',
|
||||
];
|
||||
|
||||
if ($ClassName === 'Election') {
|
||||
$path_to_file[] = __DIR__.'/../lib/ElectionProcess/CandidatesProcess.php';
|
||||
$path_to_file[] = __DIR__.'/../lib/ElectionProcess/VotesProcess.php';
|
||||
$path_to_file[] = __DIR__.'/../lib/ElectionProcess/ResultsProcess.php';
|
||||
}
|
||||
|
||||
|
||||
|
||||
// var_dump($path_to_file);
|
||||
|
||||
foreach ($path_to_file as $oneFile) {
|
||||
$file_contents = file_get_contents($oneFile);
|
||||
|
||||
foreach ($ClassData as $MethodName => $MethodData) {
|
||||
var_dump($ClassName.'->'.$MethodName);
|
||||
|
||||
$description = $MethodData['description'];
|
||||
$description = str_replace('$', '\\\$', $description);
|
||||
$description = preg_replace($patternReplaceLastNewLine, '$1', $description);
|
||||
$description = str_replace(["\n ", "\n"], '\\n', $description);
|
||||
$description = str_replace('"', '\"', $description);
|
||||
|
||||
$attributes = '$3#[Description("'.$description.'")]$2';
|
||||
|
||||
if (isset($MethodData['return'])) {
|
||||
$returnV = $MethodData['return'];
|
||||
$returnV = preg_replace($patternReplaceLastNewLine, '$1', $returnV);
|
||||
$returnV = str_replace(["\n ", "\n"], '\\n', $returnV);
|
||||
$returnV = str_replace('"', '\"', $returnV);
|
||||
|
||||
$attributes .= '$3#[FunctionReturn("'.$returnV.'")]$2';
|
||||
}
|
||||
|
||||
|
||||
if (isset($MethodData['examples'])) {
|
||||
$examples = $MethodData['examples'];
|
||||
$examples = preg_replace($patternReplaceLastNewLine, '$1', $examples);
|
||||
$examples = str_replace(["\n ", "\n"], '\\n', $examples);
|
||||
$examples = str_replace('"', '\"', $examples);
|
||||
|
||||
$arg = '';
|
||||
$i = 1;
|
||||
foreach ($examples as $oneExampleKey => $oneExample) {
|
||||
if ($i++ > 1) {
|
||||
$arg .= ', ';
|
||||
}
|
||||
|
||||
$arg .= '"'.$oneExampleKey.'||'.$oneExample.'"';
|
||||
}
|
||||
|
||||
$attributes .= '$3#[Examples('.$arg.')]$2';
|
||||
}
|
||||
|
||||
if (isset($MethodData['related'])) {
|
||||
$related = $MethodData['related'];
|
||||
$related = str_replace('"', '\"', $related);
|
||||
|
||||
$arg = '';
|
||||
$i = 1;
|
||||
foreach ($related as $oneRelated) {
|
||||
if ($i++ > 1) {
|
||||
$arg .= ', ';
|
||||
}
|
||||
|
||||
$arg .= '"'.$oneRelated.'"';
|
||||
}
|
||||
|
||||
$attributes .= '$3#[Related('.$arg.')]$2';
|
||||
}
|
||||
|
||||
|
||||
$pattern = '/(#\[PublicAPI\])(\n)(.*)(public.*function '.$MethodName.' *\()/';
|
||||
$replacement = '$1$2'.$attributes.'$3$4';
|
||||
|
||||
$file_contents = preg_replace(
|
||||
$pattern,
|
||||
$replacement,
|
||||
$file_contents
|
||||
);
|
||||
}
|
||||
|
||||
file_put_contents($oneFile, $file_contents);
|
||||
}
|
||||
}
|
40
include/condorcet/Dev/update-documentation.php
Normal file
40
include/condorcet/Dev/update-documentation.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use CondorcetPHP\Condorcet\Dev\CondorcetDocumentationGenerator\Generate;
|
||||
|
||||
require_once __DIR__.str_replace('/', \DIRECTORY_SEPARATOR, '/../vendor/../vendor/autoload.php');
|
||||
|
||||
// Build command
|
||||
|
||||
$path = mb_substr(__DIR__, 0, mb_strlen(__DIR__) - 4);
|
||||
$path .= \DIRECTORY_SEPARATOR.'Documentation';
|
||||
|
||||
// Clear folder
|
||||
|
||||
function rrmdir(string $dir, string $path): void
|
||||
{
|
||||
if (is_dir($dir)) {
|
||||
$objects = scandir($dir);
|
||||
foreach ($objects as $object) {
|
||||
if ($object !== '.' && $object !== '..') {
|
||||
if (filetype($dir.\DIRECTORY_SEPARATOR.$object) === 'dir') {
|
||||
rrmdir($dir.\DIRECTORY_SEPARATOR.$object, $path);
|
||||
} else {
|
||||
unlink($dir.\DIRECTORY_SEPARATOR.$object);
|
||||
}
|
||||
}
|
||||
}
|
||||
reset($objects);
|
||||
if ($dir !== $path) {
|
||||
rmdir($dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rrmdir($path, $path);
|
||||
|
||||
// Execute command
|
||||
|
||||
new Generate($path);
|
Reference in New Issue
Block a user