Skip to content

Commit 455d53d

Browse files
committed
1. Refactor JsonConfigParser with modular plugin architecture
- Replace monolithic JsonConfigParser with modular ConfigParser - Implement plugin-based configuration parsing system - Create DocumentsParserPlugin for document configuration handling - Establish proper interfaces for parsers and plugins - Update loaders to work with the new parser architecture - Move related classes to appropriate namespaces 2. Add experimental Display command for configuration visualization - Implement DisplayCommand to show configuration in human-readable format - Create renderer classes for visualizing documents, sources, and modifiers - Add styling utilities for terminal output formatting
1 parent 293bb60 commit 455d53d

39 files changed

+1030
-1522
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1496,10 +1496,10 @@ Create a PHP configuration file (`context.php`):
14961496
```php
14971497
<?php
14981498

1499-
use Butschster\ContextGenerator\Document;
1500-
use Butschster\ContextGenerator\Document\DocumentRegistry;
1499+
use Butschster\ContextGenerator\Document\Document;
15011500
use Butschster\ContextGenerator\Source\File\FileSource;
15021501
use Butschster\ContextGenerator\Source\Text\TextSource;
1502+
use Butschster\ContextGenerator\Loader\ConfigRegistry\DocumentRegistry;
15031503

15041504
return (new DocumentRegistry())
15051505
->register(

context-generator

+7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ $vendorPath = (static function (): string {
3333
return $file;
3434
})();
3535

36+
use Butschster\ContextGenerator\Console\DisplayCommand;
3637
use Butschster\ContextGenerator\Console\GenerateCommand;
3738
use Butschster\ContextGenerator\Console\InitCommand;
3839
use Butschster\ContextGenerator\Console\SchemaCommand;
@@ -101,4 +102,10 @@ $application->add(
101102
),
102103
);
103104

105+
$application->add(
106+
new DisplayCommand(
107+
files: new Files(),
108+
),
109+
);
110+
104111
$application->run();

context.json

+47-3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,22 @@
3939
"src/Source",
4040
"src/Lib/Content"
4141
],
42-
"filePattern": "*.php"
42+
"filePattern": "*.php",
43+
"modifiers": [
44+
{
45+
"name": "sanitizer",
46+
"options": {
47+
"rules": [
48+
{
49+
"type": "keyword",
50+
"keywords": [
51+
"tet"
52+
]
53+
}
54+
]
55+
}
56+
}
57+
]
4358
}
4459
]
4560
},
@@ -50,7 +65,8 @@
5065
{
5166
"type": "file",
5267
"sourcePaths": [
53-
"src/Modifier"
68+
"src/Modifier",
69+
"src/SourceModifierInterface.php"
5470
],
5571
"filePattern": "*.php"
5672
}
@@ -63,7 +79,35 @@
6379
{
6480
"type": "file",
6581
"sourcePaths": [
66-
"src/Console"
82+
"src/Console",
83+
"src/Lib/HttpClient"
84+
],
85+
"filePattern": "*.php"
86+
}
87+
]
88+
},
89+
{
90+
"description": "Console commands",
91+
"outputPath": "api/display.md",
92+
"sources": [
93+
{
94+
"type": "file",
95+
"sourcePaths": [
96+
"src/Console/DisplayCommand.php",
97+
"src/Console/Renderer"
98+
],
99+
"filePattern": "*.php"
100+
}
101+
]
102+
},
103+
{
104+
"description": "Json Parser and loader",
105+
"outputPath": "api/json-parser.md",
106+
"sources": [
107+
{
108+
"type": "file",
109+
"sourcePaths": [
110+
"src/Loader"
67111
],
68112
"filePattern": "*.php"
69113
}

src/Console/DisplayCommand.php

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\Console;
6+
7+
use Butschster\ContextGenerator\Console\Renderer\DocumentRenderer;
8+
use Butschster\ContextGenerator\Console\Renderer\Style;
9+
use Butschster\ContextGenerator\FilesInterface;
10+
use Butschster\ContextGenerator\Loader\ConfigRegistry\ConfigParser;
11+
use Butschster\ContextGenerator\Loader\ConfigRegistry\DocumentsParserPlugin;
12+
use Butschster\ContextGenerator\Loader\JsonConfigDocumentsLoader;
13+
use Symfony\Component\Console\Attribute\AsCommand;
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputArgument;
16+
use Symfony\Component\Console\Input\InputInterface;
17+
use Symfony\Component\Console\Output\OutputInterface;
18+
19+
#[AsCommand(
20+
name: 'display',
21+
description: 'Display the context configuration in a human-readable format',
22+
)]
23+
final class DisplayCommand extends Command
24+
{
25+
public function __construct(
26+
private readonly FilesInterface $files,
27+
private readonly string $defaultConfigPath = 'context.json',
28+
private readonly string $rootPath = '.',
29+
) {
30+
parent::__construct();
31+
}
32+
33+
protected function configure(): void
34+
{
35+
$this
36+
->setHelp('This command displays the context configuration in a human-readable format')
37+
->addArgument(
38+
'config',
39+
InputArgument::OPTIONAL,
40+
'Path to the configuration file',
41+
$this->defaultConfigPath,
42+
);
43+
}
44+
45+
protected function execute(InputInterface $input, OutputInterface $output): int
46+
{
47+
$configPath = $input->getArgument('config');
48+
49+
if (!$this->files->exists($configPath)) {
50+
$output->writeln("<error>Configuration file not found: $configPath</error>");
51+
return Command::FAILURE;
52+
}
53+
54+
try {
55+
// Load the configuration using JsonConfigDocumentsLoader
56+
// todo use factory
57+
$loader = new JsonConfigDocumentsLoader(
58+
files: $this->files,
59+
parser: new ConfigParser(
60+
rootPath: $this->rootPath,
61+
documentsParser: new DocumentsParserPlugin(),
62+
),
63+
configPath: $configPath,
64+
rootPath: $this->rootPath,
65+
);
66+
67+
if (!$loader->isSupported()) {
68+
$output->writeln("<error>Configuration file format not supported: $configPath</error>");
69+
return Command::FAILURE;
70+
}
71+
72+
// Load the document registry
73+
$registry = $loader->load();
74+
75+
// Create renderer and render each document
76+
$renderer = new DocumentRenderer();
77+
78+
$title = "Context: {$configPath}";
79+
80+
$output->writeln("\n" . Style::header($title));
81+
$output->writeln(Style::separator('=', \strlen($title)) . "\n");
82+
83+
$documents = $registry->getDocuments();
84+
$output->writeln(Style::property("Total documents") . ": " . Style::count(\count($documents)) . "\n\n");
85+
86+
foreach ($documents as $index => $document) {
87+
$output->writeln(
88+
Style::header("Document") . " " . Style::itemNumber($index + 1, \count($documents)) . ":",
89+
);
90+
$output->writeln(Style::separator('=', \strlen($title)) . "\n");
91+
$output->writeln(Style::indent($renderer->renderDocument($document)));
92+
$output->writeln("");
93+
}
94+
95+
return Command::SUCCESS;
96+
} catch (\Exception $e) {
97+
$output->writeln("<error>Error displaying configuration: {$e->getMessage()}</error>");
98+
99+
if ($output->isVerbose()) {
100+
$output->writeln("<error>{$e->getTraceAsString()}</error>");
101+
}
102+
103+
return Command::FAILURE;
104+
}
105+
}
106+
}

src/Console/GenerateCommand.php

+10-16
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44

55
namespace Butschster\ContextGenerator\Console;
66

7-
use Butschster\ContextGenerator\Document\DocumentCompiler;
8-
use Butschster\ContextGenerator\Error\ErrorCollection;
7+
use Butschster\ContextGenerator\Document\Compiler\DocumentCompiler;
98
use Butschster\ContextGenerator\Fetcher\SourceFetcherRegistry;
109
use Butschster\ContextGenerator\FilesInterface;
1110
use Butschster\ContextGenerator\Lib\Content\ContentBuilderFactory;
@@ -14,13 +13,14 @@
1413
use Butschster\ContextGenerator\Lib\HttpClient\HttpClientInterface;
1514
use Butschster\ContextGenerator\Loader\CompositeDocumentsLoader;
1615
use Butschster\ContextGenerator\Loader\ConfigDocumentsLoader;
16+
use Butschster\ContextGenerator\Loader\ConfigRegistry\ConfigParser;
17+
use Butschster\ContextGenerator\Loader\ConfigRegistry\DocumentsParserPlugin;
1718
use Butschster\ContextGenerator\Loader\JsonConfigDocumentsLoader;
1819
use Butschster\ContextGenerator\Modifier\AstDocTransformer;
1920
use Butschster\ContextGenerator\Modifier\ContextSanitizerModifier;
2021
use Butschster\ContextGenerator\Modifier\PhpContentFilter;
2122
use Butschster\ContextGenerator\Modifier\PhpSignature;
2223
use Butschster\ContextGenerator\Modifier\SourceModifierRegistry;
23-
use Butschster\ContextGenerator\Parser\DefaultSourceParser;
2424
use Butschster\ContextGenerator\Source\File\FileSourceFetcher;
2525
use Butschster\ContextGenerator\Source\GitDiff\CommitDiffSourceFetcher;
2626
use Butschster\ContextGenerator\Source\Github\GithubFinder;
@@ -130,13 +130,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
130130
],
131131
);
132132

133-
$sourceParser = new DefaultSourceParser(
134-
fetcherRegistry: $sourceFetcherRegistry,
135-
);
136-
137133
$compiler = new DocumentCompiler(
138134
files: $files,
139-
parser: $sourceParser,
135+
parser: $sourceFetcherRegistry,
140136
basePath: $this->outputPath,
141137
builderFactory: $contentBuilderFactory,
142138
);
@@ -146,14 +142,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int
146142
new ConfigDocumentsLoader(
147143
configPath: $this->rootPath . '/' . $this->phpConfigName,
148144
),
145+
// todo use factory
149146
new JsonConfigDocumentsLoader(
150147
files: $files,
148+
parser: new ConfigParser(
149+
rootPath: $this->rootPath,
150+
documentsParser: new DocumentsParserPlugin(),
151+
),
151152
configPath: $this->rootPath . '/' . $configPath,
152153
rootPath: $this->rootPath,
153154
),
154155
);
155156

156-
foreach ($loader->load()->getDocuments() as $document) {
157+
foreach ($loader->load()->getItems() as $document) {
157158
$outputStyle->info(\sprintf('Compiling %s...', $document->description));
158159

159160
$compiledDocument = $compiler->compile($document);
@@ -168,11 +169,4 @@ protected function execute(InputInterface $input, OutputInterface $output): int
168169

169170
return Command::SUCCESS;
170171
}
171-
172-
private function renderErrors(SymfonyStyle $output, ErrorCollection $errors): void
173-
{
174-
foreach ($errors as $error) {
175-
$output->error($error);
176-
}
177-
}
178172
}

src/Console/InitCommand.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace Butschster\ContextGenerator\Console;
66

7-
use Butschster\ContextGenerator\Document;
8-
use Butschster\ContextGenerator\Document\DocumentRegistry;
7+
use Butschster\ContextGenerator\Document\Document;
8+
use Butschster\ContextGenerator\Loader\ConfigRegistry\DocumentRegistry;
99
use Butschster\ContextGenerator\Source\Text\TextSource;
1010
use Symfony\Component\Console\Attribute\AsCommand;
1111
use Symfony\Component\Console\Command\Command;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\Console\Renderer;
6+
7+
/**
8+
* @deprecated Should be completely redesigned
9+
*/
10+
interface ConfigRendererInterface
11+
{
12+
/**
13+
* Check if this renderer supports the given configuration
14+
*/
15+
public function supports(array $config): bool;
16+
17+
/**
18+
* Render the configuration to a string representation
19+
*/
20+
public function render(array $config): string;
21+
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\Console\Renderer;
6+
7+
use Butschster\ContextGenerator\Document\Document;
8+
9+
/**
10+
* @deprecated Should be completely redesigned
11+
*/
12+
final class DocumentRenderer
13+
{
14+
public function renderDocument(Document $document): string
15+
{
16+
$output = Style::keyValue("Description", $document->description) . "\n";
17+
$output .= Style::keyValue("Output Path", $document->outputPath) . "\n";
18+
$output .= Style::keyValue("Overwrite", $document->overwrite) . "\n\n";
19+
20+
$sources = $document->getSources();
21+
22+
$sourceRenderer = new SourceRenderer();
23+
24+
foreach ($sources as $index => $source) {
25+
$sourceOutput = $sourceRenderer->renderSource($source);
26+
$output .= Style::indent($sourceOutput) . "\n";
27+
}
28+
29+
return $output;
30+
}
31+
}
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\Console\Renderer;
6+
7+
use Butschster\ContextGenerator\Modifier\Modifier;
8+
9+
/**
10+
* @deprecated Should be completely redesigned
11+
*/
12+
final class ModifierRenderer
13+
{
14+
private const MODIFIER_TYPES = [
15+
'php-signature' => 'PHP Signature Modifier',
16+
'php-content-filter' => 'PHP Content Filter Modifier',
17+
'sanitizer' => 'Content Sanitizer Modifier',
18+
'php-docs' => 'PHP Docs Transformer Modifier',
19+
];
20+
21+
public function renderModifier(Modifier $modifier): string
22+
{
23+
$name = $modifier->name;
24+
$displayName = self::MODIFIER_TYPES[$name] ?? 'Modifier: ' . $name;
25+
26+
$output = Style::subtitle($displayName) . "\n";
27+
$output .= Style::separator('-', \strlen($displayName)) . "\n\n";
28+
29+
if (!empty($modifier->context)) {
30+
$output .= Style::property("Options") . ":\n";
31+
foreach ($modifier->context as $key => $value) {
32+
$output .= Style::indent(Style::keyValue($this->formatKey($key), $value)) . "\n";
33+
}
34+
}
35+
36+
return $output;
37+
}
38+
39+
private function formatKey(string $key): string
40+
{
41+
return \ucfirst(\str_replace('_', ' ', $key));
42+
}
43+
}

0 commit comments

Comments
 (0)