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
94 changes: 94 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

## [Unreleased]

### Breaking
- SchemaInterface now requires `toArray(): array`.
- Any custom implementations of `Blugen\\Service\\Lexicon\\SchemaInterface` must add `toArray()`.
- Namespace and layout refactor for type-specific schemas.
- Old: `Blugen\\Service\\Lexicon\\V1\\TypeSpecificSchema\\...`
- New roots under `Blugen\\Service\\Lexicon\\V1\\Schema\\...` with sub-namespaces:
- `Concrete\\*` (e.g., `StringSchema`, `IntegerSchema`, `BlobSchema`, ...)
- `Container\\*` (e.g., `ArraySchema`, `ObjectSchema`, `ParamsSchema`)
- `Meta\\*` (e.g., `RefSchema`, `UnionSchema`, `UnknownSchema`, `TokenSchema`)
- `Support\\*` (e.g., `InputSchema`, `OutputSchema`, `MessageSchema`, `ErrorsSchema`, `ErrorSchema`)
- `Primary\\*` (e.g., `QuerySchema`, `ProcedureSchema`, `RecordSchema`, `SubscriptionSchema`, `HTTPAbstract`)
- Code importing old `TypeSpecificSchema` classes will break and must be updated to the new `Schema` sub-namespaces.
- Support schema `type()`/`description()` behavior changed via `SupportSchemaTrait`.
- `type()` is no longer supported on support schemas and now throws `BadMethodCallException`.
- `description()` on some support schemas may also be unsupported (unless class overrides it).
- `InputSchema::schema()` / `OutputSchema::schema()` return raw arrays.
- In 1.x these methods returned wrapped schema objects (e.g., `ObjectSchema|UnionSchema|RefSchema|null`).
- Now they return `?array`/`array` of raw schema content. Callers must adapt accordingly.
- `InputSchema::schema()` may now be `null` when absent (previously defaulted to an empty object schema).
- `ErrorsSchema` element type and access semantics changed.
- Iteration now yields `ErrorSchema` objects (previously arrays).
- Implements read-only `ArrayAccess`; attempting to modify throws `BadMethodCallException`. Out-of-bounds reads throw `OutOfBoundsException`.
- `ObjectSchema::properties()` contract changed.
- Returns an array of schema instances built via `SchemaFactory` (previously returned `Property` objects with name/nullable/required metadata).
- Throws `V1\\Exceptions\\MissingRequiredFieldException` when `properties` is missing or not an array (was previously tolerant).
- Callers needing metadata must use `required()`/`nullable()` arrays alongside property keys.
- Legacy classes removed:
- `V1/TypeSpecificSchema/Support/{ErrorsSchema,InputSchema,MessageSchema,OutputSchema}`
- `V1/TypeSpecificSchema/Field/ObjectSchema`

### Added
- Primary schemas: `Schema\\Primary\\{QuerySchema, ProcedureSchema, RecordSchema, SubscriptionSchema}` and base `HTTPAbstract`.
- Traits to unify behavior and DRY:
- `V1\\Traits\\{ArrayableTrait, SchemaTrait, RawSchemaAccessorTrait, SupportSchemaTrait, DefinitionTrait}`
- `V1\\Schema\\Support\\ErrorSchema` and revamped `ErrorsSchema` (iterable, read-only `ArrayAccess`).
- `V1\\Exceptions\\MissingRequiredFieldException` for strict schema validation (e.g., object properties presence/type).

### Changed
- Moved all type-specific schemas to `V1\\Schema\\{Concrete, Container, Meta, Support, Primary}` per their roles.
- `SchemaFactory` now creates from new `V1\\Schema\\{Concrete,Container,Meta}` classes; dependent generators updated accordingly.
- IO support schemas share a common `IOAbstract` (unified `description()`, `encoding()`, `schema()`, `parameters()`, `toArray()`).
- `OutputSchema`: `schema` field is optional and may be `null` when not present.

### Fixed
- Treat `schema` as optional for Input/Output; tests and implementations updated accordingly.
- Resolved issues in `ObjectSchema` behavior and offset/exception handling in support schemas.

### Removed
- Old `TypeSpecificSchema` support classes and the field `ObjectSchema` (replaced by `Schema\\Container\\ObjectSchema`).

### Migration Guide
- Implementations of `SchemaInterface`: add `public function toArray(): array`.
- Update imports from `...\\V1\\TypeSpecificSchema\\Field\\*` to the new locations. Examples:
- `...\\TypeSpecificSchema\\Field\\StringSchema` → `...\\Schema\\Concrete\\StringSchema`
- `...\\TypeSpecificSchema\\Field\\ObjectSchema` → `...\\Schema\\Container\\ObjectSchema`
- `...\\TypeSpecificSchema\\Field\\RefSchema` → `...\\Schema\\Meta\\RefSchema`
- `...\\TypeSpecificSchema\\Support\\InputSchema` → `...\\Schema\\Support\\InputSchema`
- Support schema `type()` calls: remove/avoid calling `type()` on support schemas or guard with `method_exists`/try-catch.
- Input/Output/Message `schema()` usage:
- Previously: `$schemaObj = $output->schema(); $type = $schemaObj?->type();`
- Now: `$raw = $output->schema(); $type = $raw['type'] ?? null;` or wrap via `new V1\\Schema($raw)` and/or `SchemaFactory::create($raw['type'], $raw)`.
- `ErrorsSchema` iteration and access:
- Previously arrays: `$name = $errors[0]['name'];`
- Now objects: `$name = $errors[0]->name(); $desc = $errors[0]->description();`
- Collection is read-only; do not modify via array offsets.
- `ObjectSchema::properties()`:
- Previously returned `Property` objects with `name/nullable/required`.
- Now returns schema instances only. Use `required()`/`nullable()` and your properties keys to compute metadata.
- Handle `MissingRequiredFieldException` whenever reading properties of an object schema.

## [1.0.0-alpha.1] - 2025-07-26

### Added
- First 1.x pre-release tag for the library.
- CLI `blugen` with `generate` and `clear` commands.
- Lexicon V1 foundation: reader, generator, definition and schema interfaces.
- Type-specific schemas under `V1\TypeSpecificSchema\{Field,Support}` and supporting `SchemaFactory`.
- Basic syntax validators for string, integer, boolean, array, and null types.
- XRPC client pieces: `Client`, `SessionManager`, encoders and helpers.

### Changed
- Release automation and workflow adjustments for publishing the 1.x pre-release.

---
[Unreleased]: https://github.com/corebranch/blugen/compare/1.0.0-alpha.1...1.x
[1.0.0-alpha.1]: https://github.com/corebranch/blugen/releases/tag/1.0.0-alpha.1
1 change: 1 addition & 0 deletions src/Service/Lexicon/SchemaInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ interface SchemaInterface
public function type(): string;
public function description(): ?string;
public function __get(string $name): mixed;
public function toArray(): array;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\ArraySchema;
use Blugen\Service\Lexicon\V1\Schema\Container\ArraySchema;
use Nette\PhpGenerator\ClassType;

class ArrayComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\BlobSchema;
use Blugen\Service\Lexicon\V1\Schema\Concrete\BlobSchema;
use Nette\PhpGenerator\ClassType;

class BlobComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\BooleanSchema;
use Blugen\Service\Lexicon\V1\Schema\Concrete\BooleanSchema;
use Nette\PhpGenerator\ClassType;

class BooleanComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\BytesSchema;
use Blugen\Service\Lexicon\V1\Schema\Concrete\BytesSchema;
use Nette\PhpGenerator\ClassType;

class BytesComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\CidLinkSchema;
use Nette\PhpGenerator\ClassType;

class CidLinkComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\IntegerSchema;
use Blugen\Service\Lexicon\V1\Schema\Concrete\IntegerSchema;
use Nette\PhpGenerator\ClassType;

class IntegerComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\NullSchema;
use Nette\PhpGenerator\ClassType;

class NullComponentGenerator implements GeneratorInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
namespace Blugen\Service\Lexicon\V1\ComponentGenerator\Field;

use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Exceptions\MissingRequiredFieldException;
use Blugen\Service\Lexicon\V1\Factory\ComponentGeneratorFactory;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\ObjectSchema;
use Blugen\Service\Lexicon\V1\Schema;
use Blugen\Service\Lexicon\V1\Schema\Container\ObjectSchema;
use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\Literal;

Expand All @@ -22,7 +24,23 @@ public function generate(): void
$anonClass = new ClassType(null);
$objectSchema = new ObjectSchema($this->property->schema());

foreach ($objectSchema->properties() as $childProperty) {
try {
$properties = $objectSchema->properties();
} catch (MissingRequiredFieldException) {
$properties = [];
}

$nullable = $objectSchema->nullable() ?? [];
$required = $objectSchema->required() ?? [];

foreach ($properties as $childPropertyName => $childProperty) {
$childProperty = new Property(
$childPropertyName,
new Schema($childProperty),
in_array($childPropertyName, $nullable, true),
in_array($childPropertyName, $required, true),
);

ComponentGeneratorFactory::create($anonClass, $childProperty)->generate();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@

namespace Blugen\Service\Lexicon\V1\ComponentGenerator\Field;

use Blugen\Service\Lexicon\ArraySerialization\ArrayField;
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Factory\ComponentGeneratorFactory;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\ParamsSchema;
use Blugen\Service\Lexicon\V1\Schema\Container\ParamsSchema;
use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\Literal;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\Resolver\NamespaceResolver;
use Blugen\Service\Lexicon\V1\Resolver\NsidResolver;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\RefSchema;
use Blugen\Service\Lexicon\V1\Schema\Meta\RefSchema;
use Nette\PhpGenerator\ClassType;

class RefComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\StringSchema;
use Blugen\Service\Lexicon\V1\Schema\Concrete\StringSchema;
use Nette\PhpGenerator\ClassType;

class StringComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\TokenSchema;
use Nette\PhpGenerator\ClassType;

class TokenComponentGenerator implements GeneratorInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\Resolver\NamespaceResolver;
use Blugen\Service\Lexicon\V1\Resolver\NsidResolver;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\UnionSchema;
use Blugen\Service\Lexicon\V1\Schema\Meta\UnionSchema;
use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\Literal;

class UnionComponentGenerator implements GeneratorInterface, ArraySerializationContributor
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContributor;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\UnknownSchema;
use Nette\PhpGenerator\ClassType;

class UnknownComponentGenerator implements GeneratorInterface, ArraySerializationContributor
Expand Down
36 changes: 30 additions & 6 deletions src/Service/Lexicon/V1/DefGenerator/Primary/ProcedureGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\InputInterface;
use Blugen\Service\Lexicon\ProcedureInterface;
use Blugen\Service\Lexicon\V1\ComponentGenerator\Field\RefComponentGenerator;
use Blugen\Service\Lexicon\V1\Exceptions\MissingRequiredFieldException;
use Blugen\Service\Lexicon\V1\Factory\ComponentGeneratorFactory;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\Resolver\NamespaceResolver;
use Blugen\Service\Lexicon\V1\Resolver\NsidResolver;
use Blugen\Service\Lexicon\V1\Schema;
use Blugen\Service\Lexicon\V1\Schema\Container\ObjectSchema;
use Blugen\Service\Lexicon\V1\Schema\Meta\RefSchema;
use Blugen\Service\Lexicon\V1\Schema\Meta\UnionSchema;
use Blugen\Service\Lexicon\V1\TypeSpecificDefinition\Primary\ProcedureTypeDefinition;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\ObjectSchema;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\RefSchema;
use Blugen\Service\Lexicon\V1\TypeSpecificSchema\Field\UnionSchema;
use Blugen\Service\Syntax\Factory\SchemaFactory;
use Blugen\Service\Xrpc\CallableInterface;
use Blugen\Service\Xrpc\Encoder\Encoder;
use Nette\PhpGenerator\ClassType;
Expand Down Expand Up @@ -47,7 +50,12 @@ public function generate(): array

$this->class->addImplement(ProcedureInterface::class);

$schema = $this->definition->input()?->schema();
$schemaArr = $this->definition->input()?->schema();
$schema = null;

if (! empty($schemaArr)) {
$schema = container()->get(SchemaFactory::class)::create($schemaArr['type'], $schemaArr);
}

if ($schema instanceof UnionSchema) {
$refs = array_map(function (string $ref) {
Expand Down Expand Up @@ -75,7 +83,23 @@ public function generate(): array
$schemaClass = $schemaPhpNamespace->addClass($schemaClassName);
$schemaClass->addImplement(InputInterface::class);

foreach($schema->properties() as $property) {
try {
$properties = $schema->properties();
} catch (MissingRequiredFieldException) {
$properties = [];
}

$nullable = $schema->nullable() ?? [];
$required = $schema->required() ?? [];

foreach($properties as $propertyName => $property) {
$property = new Property(
$propertyName,
new Schema($property->toArray()),
in_array($property, $nullable, true),
in_array($property, $required, true)
);

ComponentGeneratorFactory::create($schemaClass, $property, $this->definition->lexicon())->generate();
}

Expand Down
20 changes: 19 additions & 1 deletion src/Service/Lexicon/V1/DefGenerator/Primary/RecordGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
use Blugen\Service\Lexicon\ArraySerialization\ArraySerializationContext;
use Blugen\Service\Lexicon\ArraySerialization\BuildsArraySerialization;
use Blugen\Service\Lexicon\GeneratorInterface;
use Blugen\Service\Lexicon\V1\Exceptions\MissingRequiredFieldException;
use Blugen\Service\Lexicon\V1\Factory\ComponentGeneratorFactory;
use Blugen\Service\Lexicon\V1\Property;
use Blugen\Service\Lexicon\V1\Resolver\NamespaceResolver;
use Blugen\Service\Lexicon\V1\Schema;
use Blugen\Service\Lexicon\V1\TypeSpecificDefinition\Primary\RecordTypeDefinition;
use JsonSerializable;
use Nette\InvalidArgumentException;
Expand Down Expand Up @@ -49,7 +52,22 @@ public function generate(): string
$this->class->addImplement(ArraySerializable::class)
->addImplement(JsonSerializable::class);

foreach ($this->definition->record()->properties() as $property) {
try {
$properties = $this->definition->record()->properties();
} catch (MissingRequiredFieldException) {
$properties = [];
}

$nullable = $this->definition->record()->nullable() ?? [];
$required = $this->definition->record()->required() ?? [];

foreach ($properties as $propertyName => $property) {
$property = new Property(
$propertyName,
new Schema($property->toArray()),
in_array($propertyName, $nullable, true),
in_array($propertyName, $required, true)
);
ComponentGeneratorFactory::create($this->class, $property, $this->definition->lexicon(), $this)->generate();
}

Expand Down
11 changes: 11 additions & 0 deletions src/Service/Lexicon/V1/Definition.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,15 @@ public function __get(string $name): mixed

return $def;
}

public function toArray(): array
{
return array_filter($this->schema(), static fn ($value) => $value !== null);
}

public function schema(): array
{
$defs = $this->lexicon->defs();
return $defs[$this->name] ?? [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Blugen\Service\Lexicon\V1\Exceptions;

use Blugen\Exceptions\Exception;

class MissingRequiredFieldException extends Exception
{
}
Loading