Skip to content
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
25 changes: 25 additions & 0 deletions json-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,31 @@
"$ref": "#/definitions/prompt"
}
},
"variables": {
"type": "object",
"description": "Custom variables to use throughout the configuration",
"additionalProperties": {
"oneOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"examples": [
{
"version": "1.0.0",
"project_name": "My Project",
"environment": "development",
"api_token": "xyz-123-abc"
}
]
},
"import": {
"type": "array",
"description": "List of external configuration files to import",
Expand Down
3 changes: 3 additions & 0 deletions src/Application/Bootloader/ConfigLoaderBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Butschster\ContextGenerator\Document\Compiler\DocumentCompiler;
use Butschster\ContextGenerator\Document\DocumentsParserPlugin;
use Butschster\ContextGenerator\Lib\Content\ContentBuilderFactory;
use Butschster\ContextGenerator\Lib\Variable\VariableResolver;
use Butschster\ContextGenerator\Modifier\Alias\AliasesRegistry;
use Butschster\ContextGenerator\Modifier\Alias\ModifierAliasesParserPlugin;
use Butschster\ContextGenerator\Modifier\Alias\ModifierResolver;
Expand Down Expand Up @@ -100,11 +101,13 @@ public function defineSingletons(): array
SourceModifierRegistry $registry,
ContentBuilderFactory $builderFactory,
HasPrefixLoggerInterface $logger,
VariableResolver $variables,
) => new DocumentCompiler(
files: $files,
parser: $parser,
basePath: (string) $dirs->getOutputPath(),
modifierRegistry: $registry,
variables: $variables,
builderFactory: $builderFactory,
logger: $logger->withPrefix('document-compiler'),
),
Expand Down
32 changes: 30 additions & 2 deletions src/Application/Bootloader/VariableBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
namespace Butschster\ContextGenerator\Application\Bootloader;

use Butschster\ContextGenerator\Application\Logger\HasPrefixLoggerInterface;
use Butschster\ContextGenerator\Config\Parser\VariablesParserPlugin;
use Butschster\ContextGenerator\DirectoriesInterface;
use Butschster\ContextGenerator\Lib\Variable\Provider\CompositeVariableProvider;
use Butschster\ContextGenerator\Lib\Variable\Provider\ConfigVariableProvider;
use Butschster\ContextGenerator\Lib\Variable\Provider\DotEnvVariableProvider;
use Butschster\ContextGenerator\Lib\Variable\Provider\PredefinedVariableProvider;
use Butschster\ContextGenerator\Lib\Variable\VariableReplacementProcessor;
Expand All @@ -20,9 +22,22 @@ final class VariableBootloader extends Bootloader
public function defineSingletons(): array
{
return [
// Singleton provider for variables from config
ConfigVariableProvider::class => static fn() => new ConfigVariableProvider(),

// Parser plugin for extracting variables from config
VariablesParserPlugin::class => static fn(
ConfigVariableProvider $variableProvider,
HasPrefixLoggerInterface $logger,
) => new VariablesParserPlugin(
variableProvider: $variableProvider,
logger: $logger->withPrefix('variables-parser'),
),

VariableResolver::class => static function (
DirectoriesInterface $dirs,
HasPrefixLoggerInterface $logger,
ConfigVariableProvider $configVariableProvider,
) {
$envFilePath = null;
$envFileName = null;
Expand All @@ -35,17 +50,30 @@ public function defineSingletons(): array
return new VariableResolver(
processor: new VariableReplacementProcessor(
provider: new CompositeVariableProvider(
envProvider: new DotEnvVariableProvider(
$configVariableProvider,

// Environment variables have middle priority
new DotEnvVariableProvider(
repository: RepositoryBuilder::createWithDefaultAdapters()->make(),
rootPath: $envFilePath,
envFileName: $envFileName,
),
predefinedProvider: new PredefinedVariableProvider(),

// Predefined system variables have lowest priority
new PredefinedVariableProvider(),
),
logger: $logger->withPrefix('variable-resolver'),
),
);
},
];
}

public function boot(
ConfigLoaderBootloader $configLoaderBootloader,
VariablesParserPlugin $variablesParserPlugin,
): void {
// Register the variables parser plugin with the config loader
$configLoaderBootloader->registerParserPlugin($variablesParserPlugin);
}
}
2 changes: 2 additions & 0 deletions src/Config/Import/ImportResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ private function processSingleImport(

/**
* Merge multiple configurations
*
* todo: move to a parsers??
*/
private function mergeConfigurations(array $configs): array
{
Expand Down
55 changes: 55 additions & 0 deletions src/Config/Parser/VariablesParserPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\Config\Parser;

use Butschster\ContextGenerator\Config\Registry\RegistryInterface;
use Butschster\ContextGenerator\Lib\Variable\Provider\ConfigVariableProvider;
use Psr\Log\LoggerInterface;

/**
* Plugin for parsing the 'variables' section in configuration files
*/
final readonly class VariablesParserPlugin implements ConfigParserPluginInterface
{
public function __construct(
private ConfigVariableProvider $variableProvider,
private ?LoggerInterface $logger = null,
) {}

public function getConfigKey(): string
{
return 'variables';
}

public function supports(array $config): bool
{
return isset($config['variables']) && \is_array($config['variables']);
}

public function parse(array $config, string $rootPath): ?RegistryInterface
{
if (!$this->supports($config)) {
return null;
}

$variables = $config['variables'];

$this->logger?->debug('Parsing variables from config', [
'count' => \count($variables),
'keys' => \array_keys($variables),
]);

// Update the variables in the provider
$this->variableProvider->setVariables($variables);

return null;
}

public function updateConfig(array $config, string $rootPath): array
{
// We don't need to modify the config, just return it as is
return $config;
}
}
4 changes: 2 additions & 2 deletions src/Config/Registry/ConfigRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ public function has(string $type): bool
*
* @template T of RegistryInterface
* @param class-string<T> $className Optional class name to validate the registry type
* @return RegistryInterface The requested registry
* @return T
*
* @throws \InvalidArgumentException If the registry does not exist or is not of the expected type
*/
public function get(string $type, string $className = RegistryInterface::class): RegistryInterface
public function get(string $type, string $className): RegistryInterface
{
if (!$this->has($type)) {
throw new \InvalidArgumentException(\sprintf('Registry of type "%s" does not exist', $type));
Expand Down
15 changes: 10 additions & 5 deletions src/Document/Compiler/DocumentCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Butschster\ContextGenerator\Document\Document;
use Butschster\ContextGenerator\Lib\Content\Block\TextBlock;
use Butschster\ContextGenerator\Lib\Content\ContentBuilderFactory;
use Butschster\ContextGenerator\Lib\Variable\VariableResolver;
use Butschster\ContextGenerator\Modifier\ModifiersApplier;
use Butschster\ContextGenerator\Modifier\SourceModifierRegistry;
use Butschster\ContextGenerator\SourceParserInterface;
Expand All @@ -30,6 +31,7 @@ public function __construct(
private SourceParserInterface $parser,
private string $basePath,
private SourceModifierRegistry $modifierRegistry,
private VariableResolver $variables,
private ContentBuilderFactory $builderFactory = new ContentBuilderFactory(),
private ?LoggerInterface $logger = null,
) {}
Expand All @@ -39,13 +41,14 @@ public function __construct(
*/
public function compile(Document $document): CompiledDocument
{
$outputPath = $this->variables->resolve($document->outputPath);

$this->logger?->info('Starting document compilation', [
'document' => $document->description,
'outputPath' => $document->outputPath,
'outputPath' => $outputPath,
]);

$errors = new ErrorCollection();
$resultPath = \rtrim($this->basePath, '/') . '/' . \ltrim($document->outputPath, '/');
$resultPath = \rtrim($this->basePath, '/') . '/' . \ltrim($outputPath, '/');

if (!$document->overwrite && $this->files->exists($resultPath)) {
$this->logger?->notice('Document already exists and overwrite is disabled', [
Expand Down Expand Up @@ -86,11 +89,13 @@ public function compile(Document $document): CompiledDocument
*/
public function buildContent(ErrorCollection $errors, Document $document): CompiledDocument
{
$description = $this->variables->resolve($document->description);

$this->logger?->debug('Creating content builder');
$builder = $this->builderFactory->create();

$this->logger?->debug('Adding document title', ['title' => $document->description]);
$builder->addTitle($document->description);
$this->logger?->debug('Adding document title', ['title' => $description]);
$builder->addTitle($description);

// Add document tags if present
if ($document->hasTags()) {
Expand Down
66 changes: 66 additions & 0 deletions src/Lib/Variable/Provider/ConfigVariableProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\Lib\Variable\Provider;

use Spiral\Core\Attribute\Singleton;

/**
* Provider for custom variables defined in the configuration file
*/
#[Singleton]
final class ConfigVariableProvider implements VariableProviderInterface
{
/**
* @var array<string, string> Custom variables from config
*/
private array $variables = [];

public function __construct(array $variables = [])
{
$this->setVariables($variables);
}

/**
* Set variables from config
*
* @param array<string, mixed> $variables Variables from config
*/
public function setVariables(array $variables): self
{
$this->variables = [];

// Convert all values to strings
foreach ($variables as $key => $value) {
// Skip non-scalar values
if (!\is_scalar($value)) {
continue;
}

$this->variables[(string) $key] = (string) $value;
}

return $this;
}

public function has(string $name): bool
{
return \array_key_exists($name, $this->variables);
}

public function get(string $name): ?string
{
return $this->variables[$name] ?? null;
}

/**
* Get all variables
*
* @return array<string, string>
*/
public function getAll(): array
{
return $this->variables;
}
}
8 changes: 8 additions & 0 deletions src/Lib/context.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ documents:
filePattern: '*.php'
showTreeView: true

- description: Binary Updater
outputPath: utilities/binary-updater.md
sources:
- type: file
sourcePaths: ./BinaryUpdater
filePattern: '*.php'
showTreeView: true

- description: GitHub Client
outputPath: utilities/github-client.md
sources:
Expand Down
2 changes: 2 additions & 0 deletions tests/src/Document/Compiler/DocumentCompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Butschster\ContextGenerator\Document\Compiler\Error\SourceError;
use Butschster\ContextGenerator\Document\Document;
use Butschster\ContextGenerator\Lib\Content\ContentBuilderFactory;
use Butschster\ContextGenerator\Lib\Variable\VariableResolver;
use Butschster\ContextGenerator\Modifier\SourceModifierRegistry;
use Butschster\ContextGenerator\Source\SourceInterface;
use Butschster\ContextGenerator\SourceParserInterface;
Expand Down Expand Up @@ -300,6 +301,7 @@ protected function setUp(): void
parser: $this->parser,
basePath: '/base/path',
modifierRegistry: $this->modifierRegistry,
variables: new VariableResolver(),
builderFactory: $this->builderFactory,
logger: $this->logger,
);
Expand Down
Loading