Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Add rules doc generator #30

Merged
merged 12 commits into from
Apr 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint_test_pull_requests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
command: test:php
- name: Rector
command: 'rector --dry-run'
directory: ['extension-installer', 'fractor', 'fractor-xml', 'typo3-fractor']
directory: [ 'extension-installer', 'fractor', 'fractor-xml', 'typo3-fractor', 'fractor-doc-generator' ]
exclude:
- directory: extension-installer
composer-command: {name: 'PHPUnit', command: 'test:php'}
Expand Down
3 changes: 3 additions & 0 deletions fractor-doc-generator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/vendor/
/composer.lock
.phpunit.cache
4 changes: 4 additions & 0 deletions fractor-doc-generator/bin/fractor-doc-generator
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env php
<?php

include __DIR__ . '/fractor-doc-generator.php';
31 changes: 31 additions & 0 deletions fractor-doc-generator/bin/fractor-doc-generator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php


use a9f\FractorDocGenerator\DependencyInjection\ContainerBuilderFactory;
use a9f\FractorDocGenerator\FractorDocGeneratorApplication;

$autoloadFile = (static function (): ?string {
$candidates = [
getcwd() . '/vendor/autoload.php',
__DIR__ . '/../../../autoload.php',
__DIR__ . '/../vendor/autoload.php',
];
foreach ($candidates as $candidate) {
if (file_exists($candidate)) {
return $candidate;
}
}
return null;
})();
if ($autoloadFile === null) {
echo "Could not find autoload.php file";
exit(1);
}

include $autoloadFile;

$container = (new ContainerBuilderFactory())->createDependencyInjectionContainer();

/** @var FractorDocGeneratorApplication $application */
$application = $container->get(FractorDocGeneratorApplication::class);
$application->run();
59 changes: 59 additions & 0 deletions fractor-doc-generator/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"name": "a9f/fractor-doc-generator",
"description": "Generate docs for Fractor",
"license": "MIT",
"type": "library",
"authors": [
{
"name": "Andreas Wolf",
"email": "dev@a-w.io",
"role": "Lead Developer"
}
],
"require": {
"php": "^8.2",
"nette/utils": "^4.0",
"sebastian/diff": "^5.0",
"symfony/config": "^6.4",
"symfony/console": "^6.4",
"symfony/dependency-injection": "^6.4",
"symplify/rule-doc-generator": "12.1.3"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.42",
"phpstan/phpstan": "^1.10",
"phpstan/phpstan-phpunit": "^1.3",
"phpunit/phpunit": "^10.5",
"rector/rector": "^1.0",
"symplify/easy-coding-standard": "^12.1"
},
"autoload": {
"psr-4": {
"a9f\\FractorDocGenerator\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"a9f\\FractorDocGenerator\\Tests\\": "tests/"
},
"classmap": [
"stubs"
]
},
"bin": [
"bin/fractor-doc-generator"
],
"config": {
"allow-plugins": {
"ergebnis/composer-normalize": true
},
"sort-packages": true
},
"scripts": {
"analyze:php": "phpstan analyze",
"rector": "rector",
"style:php:check": "ecs",
"style:php:fix": "ecs --fix",
"test:php": "phpunit"
}
}
82 changes: 82 additions & 0 deletions fractor-doc-generator/config/config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

use a9f\FractorDocGenerator\Console\Factory\SymfonyStyleFactory;
use a9f\FractorDocGenerator\Differ\DifferFactory;
use a9f\FractorDocGenerator\FractorDocGeneratorApplication;
use a9f\FractorDocGenerator\Printer\CodeSamplePrinter;
use SebastianBergmann\Diff\Differ;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\RuleDocGenerator\Contract\RuleCodeSamplePrinterInterface;
use Symplify\RuleDocGenerator\FileSystem\ClassByTypeFinder;
use Symplify\RuleDocGenerator\RuleDefinitionsResolver;
use Symplify\RuleDocGenerator\Text\KeywordHighlighter;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
use function Symfony\Component\DependencyInjection\Loader\Configurator\tagged_iterator;

return static function (ContainerConfigurator $containerConfigurator, ContainerBuilder $containerBuilder): void {
$services = $containerConfigurator->services();
$services->defaults()
->autowire()
->public()
->autoconfigure();

$services->load('a9f\\FractorDocGenerator\\', __DIR__ . '/../src/');
$services->set(ClassByTypeFinder::class);
$services->set(RuleDefinitionsResolver::class);
$services->set(KeywordHighlighter::class);
$services->set(Differ::class)->factory([service(DifferFactory::class), 'create']);

$services->set(FractorDocGeneratorApplication::class)
->call('setCommandLoader', [service('console.command_loader')])
->public();

$services->set(SymfonyStyle::class)->factory([service(SymfonyStyleFactory::class), 'create']);

$containerBuilder->registerAttributeForAutoconfiguration(
AsCommand::class,
static function (ChildDefinition $definition, AsCommand $attribute): void {
$commands = explode('|', $attribute->name);
$hidden = false;
$name = array_shift($commands);

if ($name === '') {
// Symfony AsCommand attribute encodes hidden flag as an empty command name
$hidden = true;
$name = array_shift($commands);
}

if ($name === null) {
// This happens in case no name and no aliases are given
return;
}

$definition->addTag(
'console.command',
[
'command' => $name,
'description' => $attribute->description,
'hidden' => $hidden,
]
);

foreach ($commands as $name) {
$definition->addTag(
'console.command',
[
'command' => $name,
'hidden' => $hidden,
'alias' => true,
]
);
}
}
);

$services->set(CodeSamplePrinter::class)->arg('$ruleCodeSamplePrinters', tagged_iterator('fractor_doc_generator.rule_code_sample_printer'));

$containerBuilder->registerForAutoconfiguration(RuleCodeSamplePrinterInterface::class)->addTag('fractor_doc_generator.rule_code_sample_printer');
};
11 changes: 11 additions & 0 deletions fractor-doc-generator/ecs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

return (include __DIR__ . '/../.build/ecs.php')
->withPaths([
__DIR__ . '/config',
__DIR__ . '/src',
__DIR__ . '/tests',
])
;
6 changes: 6 additions & 0 deletions fractor-doc-generator/phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
parameters:
level: 8

paths:
- src/
- tests/
13 changes: 13 additions & 0 deletions fractor-doc-generator/phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" cacheDirectory=".phpunit.cache">
<testsuites>
<testsuite name="fractor-doc-generator">
<directory>tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>./src</directory>
</include>
</source>
</phpunit>
10 changes: 10 additions & 0 deletions fractor-doc-generator/rector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

return (include __DIR__ . '/../.build/rector.php')
->withPaths([
__DIR__ . '/config',
__DIR__ . '/src',
__DIR__ . '/tests',
]);
65 changes: 65 additions & 0 deletions fractor-doc-generator/src/Console/Command/GenerateCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace a9f\FractorDocGenerator\Console\Command;

use a9f\FractorDocGenerator\Printer\DirectoryToMarkdownPrinter;
use Nette\Utils\FileSystem;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\RuleDocGenerator\ValueObject\Option;

#[AsCommand(name: 'generate', description: 'Generates Markdown documentation based on documented rules found in directory')]
final class GenerateCommand extends Command
{
public function __construct(
private readonly DirectoryToMarkdownPrinter $directoryToMarkdownPrinter,
private readonly SymfonyStyle $symfonyStyle,
) {
parent::__construct();
}
protected function configure(): void
{
$this->addArgument(
Option::PATHS,
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
'Path to directory of your project'
);

$this->addOption(
Option::OUTPUT_FILE,
null,
InputOption::VALUE_REQUIRED,
'Path to output generated markdown file',
getcwd() . '/docs/rules_overview.md'
);
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$paths = (array) $input->getArgument(Option::PATHS);

$outputFilePath = (string) $input->getOption(Option::OUTPUT_FILE);

$markdownFileDirectory = dirname($outputFilePath);

// ensure directory exists
if (!file_exists($markdownFileDirectory)) {
FileSystem::createDir($markdownFileDirectory);
}

$markdownFileContent = $this->directoryToMarkdownPrinter->print($markdownFileDirectory, $paths);

FileSystem::write($outputFilePath, $markdownFileContent);

$this->symfonyStyle->success(sprintf('File "%s" was created', $outputFilePath));

return self::SUCCESS;
}
}
35 changes: 35 additions & 0 deletions fractor-doc-generator/src/Console/Factory/SymfonyStyleFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace a9f\FractorDocGenerator\Console\Factory;

use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

final class SymfonyStyleFactory
{
public static function create(): SymfonyStyle
{
$_SERVER['argv'] ??= [];
$argvInput = new ArgvInput();
$consoleOutput = new ConsoleOutput();
// --debug is called
if ($argvInput->hasParameterOption('--debug')) {
$consoleOutput->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
}
// disable output for tests
if (self::isPHPUnitRun()) {
$consoleOutput->setVerbosity(OutputInterface::VERBOSITY_QUIET);
}

return new SymfonyStyle($argvInput, $consoleOutput);
}

private static function isPHPUnitRun(): bool
{
return \defined('PHPUNIT_COMPOSER_INSTALL') || \defined('__PHPUNIT_PHAR__');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace a9f\FractorDocGenerator\DependencyInjection;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;

final class ContainerBuilderFactory
{
public function createDependencyInjectionContainer(): ContainerInterface
{
$containerBuilder = new ContainerBuilder();

$containerBuilder->addCompilerPass(new AddConsoleCommandPass());

$configFiles = [
__DIR__ . '/../../config/config.php'
];

foreach ($configFiles as $configFile) {
if (!file_exists($configFile)) {
continue;
}

$fileLoader = new PhpFileLoader($containerBuilder, new FileLocator(dirname($configFile)));
$fileLoader->load($configFile);
}

$containerBuilder->compile();

return $containerBuilder;
}
}
Loading