Refactor: Improve API ergonomics and simplify schema builder#1
Conversation
- Rename src/Schemas directory to src/Schema (singular) - Update all namespaces from Blaspsoft\Forerunner\Schemas to Blaspsoft\Forerunner\Schema - Remove config/forerunner.php (not needed at this time) - Remove config publishing from service provider - Update all use statements throughout codebase - Update stub template with new namespace - Update README examples with new namespace - Remove Configuration section from README - All 120 tests passing - PHPStan Level 9 clean
- Add OpenAI structured output format support when strict() is enabled
- Wraps schema with {name, strict: true, schema: {...}} structure
- Returns flat schema when strict mode is not used
- Remove redundant methods from Struct class
- Remove toJson() method (users can use json_encode() directly)
- Remove ArrayAccess implementation (58 lines reduced from 105)
- Keep JsonSerializable for native json_encode() support
- Simplify generated struct classes
- schema() method now returns array directly via ->toArray()
- Remove toArray() and toJson() helper methods from stub
- More explicit and cleaner API
- Add strict mode tracking to Builder
- New isStrict() method to check if strict mode is enabled
- Used by Struct to determine output format
- Update all tests to use ->toArray() explicitly
- 118 tests passing with 400 assertions
- PHPStan Level 9 clean
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add strict types declaration to all src files - src/Schema/Struct.php - src/Schema/Builder.php - src/Schema/PropertyBuilder.php - src/ForerunnerServiceProvider.php - src/Commands/MakeStructCommand.php - src/Facades/Schema.php - Add strict types declaration to all test files - tests/Unit/*.php - tests/Feature/*.php - tests/*.php - All 118 tests passing (400 assertions) - PHPStan Level 9 clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add optional third parameter to Struct::define($name, $callback, $description)
- Automatically sets schema description when provided
- Backward compatible - existing code without description continues to work
- All 118 tests passing (400 assertions)
- PHPStan Level 9 clean
Example usage:
```php
Struct::define(
'user_profile',
fn($b) => $b->string('name'),
'A user profile schema'
);
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Move description parameter to second position for more intuitive usage: - Before: Struct::define($name, $callback, $description) - After: Struct::define($name, $description, $callback) This ordering aligns with common API patterns where optional metadata comes before the main callback function. Tests pass null when description is not needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Changes description parameter from optional (?string) to required (string) for better LLM integration: - OpenAI Structured Outputs: Benefits from clear schema descriptions - Anthropic Claude Tool Use: Requires description as critical field - Forces developers to document schemas for better LLM understanding Updated signature: Struct::define(string $name, string $description, callable $callback) All tests updated with meaningful descriptions. The stub template now includes a placeholder description for generated structs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Major refactoring to improve code readability and match the fluent API pattern:
Changes:
- Renamed Builder.php → Property.php
- Updated class name from Builder to Property
- Changed all callback parameters from $builder to $property
- Updated all imports across codebase
- Updated README documentation with new syntax
New API pattern:
```php
Struct::define('User', 'User schema', function (Property $property) {
$property->string('name', 'Full name')->required();
$property->email('email', 'Email address')->required();
});
```
This better reflects that we're defining properties of a schema, not
building the entire structure. The Property class provides methods to
define individual schema properties with their constraints.
All tests passing (118/118), PHPStan Level 9 clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add required description parameter to all Struct::define() calls - Remove all references to toJson() method (was removed from Struct class) - Simplify "Working with Generated Schemas" section - Fix variable name from $table to $property in structure class example - Add ->toArray() calls where needed for consistency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
WalkthroughThis PR replaces the Builder-based schema API with a Property-based API, moves types from Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer/Test
participant Struct as Struct::define
participant Property as Property (builder)
participant Output as Schema Array/JSON
Dev->>Struct: call define(name, description, callback)
Struct->>Property: new Property(name) → passed to callback
Note right of Property #DFF7DF: Developer calls property->string()/int()/object()/enum() etc.
Property-->>Struct: configured Property instance
Dev->>Struct: call ->toArray() or json_encode(Struct)
Struct->>Property: Property->toArray()
alt Property->isStrict() == true
Property-->>Struct: schema array
Struct->>Output: return { name, strict: true, schema: schema }
else
Property-->>Struct: schema array
Struct->>Output: return schema
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used🧬 Code graph analysis (1)src/Schema/Property.php (2)
🔇 Additional comments (14)
Comment |
The config directory was removed in earlier refactoring, but PHPStan configuration still referenced it, causing CI failures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Added missing blank line between declare(strict_types=1) and namespace declaration to comply with blank_lines_before_namespace rule. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/Facades/Schema.php (1)
12-12: Update the docblock to reference the new namespace.The
@seetag still references the old namespace\Blaspsoft\Forerunner\Schemas\Structbut should point to\Blaspsoft\Forerunner\Schema\Struct.Apply this diff:
- * @see \Blaspsoft\Forerunner\Schemas\Struct + * @see \Blaspsoft\Forerunner\Schema\Structsrc/Schema/Property.php (1)
231-242: Strict mode correctness + required-state recomputation.
- Fields added after calling strict() are not auto-required.
- toArray() mutates/persists $this->required via markRequired(), causing stale required sets across calls and making optional() ineffective after a prior toArray().
Make strict truly “all fields required” and keep required derivation pure per-call.
@@ public function strict(): self { $this->isStrict = true; $this->additionalProperties = false; - // Mark all properties as required - foreach ($this->properties as $property) { - $property->required(); - } + // Mark existing properties as required now… + foreach ($this->properties as $property) { + $property->required(); + } return $this; } @@ protected function addProperty(string $name, string $type, ?string $description): PropertyBuilder { $builder = new PropertyBuilder($name, $type, $description); + // In strict mode, all fields must be required, including those added after strict(). + if ($this->isStrict) { + $builder->required(); + } $this->properties[$name] = $builder; return $builder; } @@ public function toArray(): array { $schema = [ 'type' => 'object', 'properties' => [], ]; + // Build required set fresh per call to avoid stale state. + $derivedRequired = []; @@ - foreach ($this->properties as $name => $builder) { + foreach ($this->properties as $name => $builder) { $schema['properties'][$name] = $builder->toArray(); - if ($builder->isRequired()) { - $this->markRequired($name); - } + if ($builder->isRequired()) { + $derivedRequired[] = $name; + } } - if (! empty($this->required)) { - $schema['required'] = $this->required; - } + // Merge manually-marked required with derived ones, then override in strict mode. + $finalRequired = array_values(array_unique(array_merge($this->required, $derivedRequired))); + if ($this->isStrict) { + $finalRequired = array_keys($this->properties); + } + if (! empty($finalRequired)) { + $schema['required'] = $finalRequired; + } $schema['additionalProperties'] = $this->additionalProperties; return $schema; }Also applies to: 265-271, 288-321
README.md (1)
310-332: Fix strict() output shape — Struct::toArray returns an OpenAI wrapperWith strict() enabled, Struct::toArray() returns a wrapper { name, strict: true, schema: {...} }, not a flat schema. The example currently shows a flat object and can mislead users.
Apply this correction:
-```php -// Perfect for OpenAI Structured Outputs -$schema = Struct::define('User', 'A user schema', function (Property $property) { - $property->string('fullname'); - $property->email('email'); - $property->int('age')->min(0)->max(120); - $property->string('location'); - - $property->strict(); // Makes all fields required + disallows extra properties -})->toArray(); -``` - -This generates: -```json -{ - "type": "object", - "properties": {...}, - "required": ["fullname", "email", "age", "location"], - "additionalProperties": false -} -``` +```php +// Perfect for OpenAI Structured Outputs +$struct = Struct::define('User', 'A user schema', function (Property $property) { + $property->string('fullname'); + $property->email('email'); + $property->int('age')->min(0)->max(120); + $property->string('location'); + + $property->strict(); // Disallows extras + (see note below on "required") +}); + +$wrapped = $struct->toArray(); // { name, strict: true, schema: {...} } +$schema = $wrapped['schema']; // Flat JSON Schema for OpenAI's `schema` field +``` + +This returns the wrapper: +```json +{ + "name": "User", + "strict": true, + "schema": { + "type": "object", + "properties": { "...": "..." }, + "required": ["fullname", "email", "age", "location"], + "additionalProperties": false + } +} +```
🧹 Nitpick comments (10)
stubs/struct.stub (1)
17-22: Showcase inline descriptions in the generated stub.The PR advertises inline field descriptions; the stub should demonstrate it.
- return Struct::define('{{ structName }}', 'Description of {{ structName }}', function (Property $property) { - $property->string('example_field'); + return Struct::define('{{ structName }}', 'Description of {{ structName }}', function (Property $property) { + $property->string('example_field', 'Describe example_field here'); // Add your fields here $property->strict(); // All fields required + no additional properties })->toArray();tests/Unit/BuilderTest.php (2)
7-12: Rename suite label for clarity.The suite still says "Builder" though the subject is Property. Rename to avoid confusion in reports.
-describe('Builder', function () { +describe('Property', function () {
168-177: Add a regression test: fields added after strict() are required.Covers the strict-mode contract and prevents future regressions.
it('can convert schema to JSON string', function () { @@ }); +it('marks fields required even if added after enabling strict', function () { + $property = new Property('TestSchema'); + $property->strict(); + $property->string('a'); + $property->int('b'); + $schema = $property->toArray(); + expect($schema['required'])->toContain('a') + ->and($schema['required'])->toContain('b'); +});src/Schema/Struct.php (1)
41-59: OpenAI wrapper + caching look correct. Minor nit: consider late-static return.Everything here matches the PR goals. Optionally, return static from define() for extensibility.
- public static function define(string $name, string $description, callable $callback): self + public static function define(string $name, string $description, callable $callback): statictests/Feature/SchemaFacadeTest.php (1)
9-12: Add a facade strict-mode test to lock wrapper semanticsGreat migration to Property API. To ensure Schema facade mirrors Struct behavior under strict mode (name/strict/schema wrapper), add a small test exercising Schema::define(...)->strict()->toArray(). This guards the container binding and facade accessor.
Apply this addition:
+ it('wraps in OpenAI format via the facade when strict', function () { + $schema = Schema::define('StrictUser', 'A strict user schema', function (Property $property) { + $property->string('name'); + $property->strict(); + })->toArray(); + + expect($schema)->toHaveKey('name', 'StrictUser') + ->and($schema)->toHaveKey('strict', true) + ->and($schema)->toHaveKey('schema') + ->and($schema['schema']['type'])->toBe('object'); + });Also applies to: 23-32
README.md (2)
80-90: Clarify strict() + Struct vs Property outputWhere examples use Struct::define(...)->toArray() with strict(), note the wrapper shape and show how to access the flat schema via $struct->toArray()['schema'] or by calling Property->toArray() directly.
Proposed note to append after these samples:
+> Tip: With strict() enabled, Struct::toArray() returns { name, strict, schema }. If you need the flat JSON Schema (e.g., to pass into an API field named "schema"), use `$struct->toArray()['schema']`. If you're building a schema without Struct, `$property->toArray()` returns the flat schema.Also applies to: 536-544, 549-557
256-263: Tighten format list wordingJSON Schema standard uses "uri" (not "url") as the format keyword. Since $property->url(...) maps to format "uri", clarify this to avoid confusion.
Apply this tweak:
-Supported formats: `email`, `uri`, `url`, `uuid`, `date`, `date-time`, `time`, `ipv4`, `ipv6`, `hostname`, and more. +Supported formats: `email`, `uri` (aliased via `$property->url()`), `uuid`, `date`, `date-time`, `time`, `ipv4`, `ipv6`, `hostname`, and more.tests/Unit/AdvancedFeaturesTest.php (2)
41-51: Document/guard strict() ordering semanticsNice coverage. Note that strict() marks fields required at call-time. You already call ->required() on fields in the strict test; consider either:
- Add a brief comment in the test explaining the ordering, or
- Change implementation to enforce “all properties required” at serialization time when isStrict() is true to remove ordering sensitivity.
If you prefer the latter, one minimal change in Property::toArray():
- foreach ($this->properties as $name => $builder) { - $properties[$name] = $builder->toArray(); - if ($builder->isRequired()) { - $this->markRequired($name); - } - } + foreach ($this->properties as $name => $builder) { + $properties[$name] = $builder->toArray(); + if ($this->isStrict || $builder->isRequired()) { + $this->markRequired($name); + } + }This preserves existing behavior and removes the ordering footgun. Based on relevant code snippets.
Also applies to: 343-388
371-388: Assertion style nit (Pest compatibility)toContain('id', 'email', 'created_at') may depend on Pest version. To avoid version sensitivity, prefer separate assertions or pass an array if supported.
Example:
- ->and($nestedSchema['required'])->toContain('id', 'email', 'created_at'); + ->and($nestedSchema['required'])->toContain('id') + ->and($nestedSchema['required'])->toContain('email') + ->and($nestedSchema['required'])->toContain('created_at');tests/Feature/IntendedUsageTest.php (1)
8-21: LGTM; consider asserting nested additionalProperties defaultGood end-to-end example. Since additionalProperties defaults to false (including nested objects), you could assert it on address to lock in the default.
Add:
->and($schema['properties']['address']['properties'])->toHaveKey('zip') + ->and($schema['properties']['address'])->toHaveKey('additionalProperties', false) ->and($schema['properties']['address']['properties']['street']['description'])->toBe('Street name')Also applies to: 23-54
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
README.md(16 hunks)config/forerunner.php(0 hunks)src/Commands/MakeStructCommand.php(1 hunks)src/Facades/Schema.php(1 hunks)src/ForerunnerServiceProvider.php(1 hunks)src/Schema/Property.php(5 hunks)src/Schema/PropertyBuilder.php(4 hunks)src/Schema/Struct.php(1 hunks)src/Schemas/Struct.php(0 hunks)stubs/struct.stub(1 hunks)tests/Feature/ExampleTest.php(1 hunks)tests/Feature/IntendedUsageTest.php(1 hunks)tests/Feature/MakeStructCommandTest.php(4 hunks)tests/Feature/SchemaFacadeTest.php(7 hunks)tests/Pest.php(1 hunks)tests/TestCase.php(1 hunks)tests/Unit/AdvancedFeaturesTest.php(3 hunks)tests/Unit/BuilderTest.php(6 hunks)tests/Unit/PropertyBuilderTest.php(4 hunks)tests/Unit/StructTest.php(8 hunks)
💤 Files with no reviewable changes (2)
- config/forerunner.php
- src/Schemas/Struct.php
🧰 Additional context used
🧬 Code graph analysis (9)
src/Schema/PropertyBuilder.php (1)
src/Schema/Property.php (1)
Property(7-333)
src/Schema/Struct.php (2)
src/Schema/Property.php (5)
Property(7-333)__construct(27-30)description(200-205)toArray(288-322)isStrict(247-250)src/Schema/PropertyBuilder.php (3)
__construct(49-54)description(79-84)toArray(263-341)
tests/Feature/SchemaFacadeTest.php (4)
src/Facades/Schema.php (1)
Schema(14-23)src/Schema/Property.php (10)
Property(7-333)string(35-38)toArray(288-322)object(99-110)array(91-94)enum(117-123)int(43-46)float(59-62)boolean(75-78)description(200-205)src/Schema/Struct.php (2)
define(25-33)toArray(41-59)src/Schema/PropertyBuilder.php (13)
required(59-64)toArray(263-341)items(101-112)enum(91-96)default(117-122)minLength(127-132)maxLength(137-142)pattern(187-192)min(167-172)max(177-182)minItems(147-152)maxItems(157-162)description(79-84)
tests/Unit/AdvancedFeaturesTest.php (3)
src/Schema/Property.php (21)
Property(7-333)string(35-38)additionalProperties(220-225)toArray(288-322)strict(231-242)int(43-46)array(91-94)schemaVersion(255-260)title(210-215)url(136-139)uuid(144-147)datetime(152-155)date(160-163)time(168-171)ipv4(176-179)ipv6(184-187)hostname(192-195)description(200-205)enum(117-123)object(99-110)src/Schema/PropertyBuilder.php (14)
PropertyBuilder(7-342)toArray(263-341)min(167-172)items(101-112)uniqueItems(207-212)format(217-222)title(197-202)required(59-64)description(79-84)nullable(227-232)enum(91-96)default(117-122)minItems(147-152)maxItems(157-162)src/Schema/Struct.php (3)
Struct(7-70)toArray(41-59)define(25-33)
src/ForerunnerServiceProvider.php (2)
src/Facades/Schema.php (1)
Schema(14-23)src/Schema/Struct.php (1)
Struct(7-70)
tests/Unit/BuilderTest.php (2)
src/Schema/Property.php (15)
Property(7-333)string(35-38)int(43-46)integer(51-54)float(59-62)number(67-70)boolean(75-78)bool(83-86)array(91-94)enum(117-123)object(99-110)description(200-205)toArray(288-322)toJson(329-332)markRequired(276-281)src/Schema/PropertyBuilder.php (10)
PropertyBuilder(7-342)enum(91-96)description(79-84)toArray(263-341)required(59-64)minLength(127-132)maxLength(137-142)min(167-172)max(177-182)default(117-122)
tests/Unit/PropertyBuilderTest.php (2)
src/Schema/Property.php (2)
Property(7-333)string(35-38)src/Schema/PropertyBuilder.php (2)
PropertyBuilder(7-342)items(101-112)
tests/Unit/StructTest.php (3)
src/Schema/Property.php (10)
Property(7-333)string(35-38)int(43-46)toArray(288-322)object(99-110)array(91-94)enum(117-123)float(59-62)boolean(75-78)description(200-205)src/Schema/Struct.php (3)
Struct(7-70)define(25-33)toArray(41-59)src/Schema/PropertyBuilder.php (13)
required(59-64)toArray(263-341)items(101-112)enum(91-96)minLength(127-132)maxLength(137-142)min(167-172)max(177-182)description(79-84)default(117-122)pattern(187-192)minItems(147-152)maxItems(157-162)
tests/Feature/IntendedUsageTest.php (3)
src/Schema/Property.php (7)
Property(7-333)string(35-38)int(43-46)boolean(75-78)array(91-94)object(99-110)toArray(288-322)src/Schema/Struct.php (3)
Struct(7-70)define(25-33)toArray(41-59)src/Schema/PropertyBuilder.php (10)
minLength(127-132)maxLength(137-142)required(59-64)min(167-172)max(177-182)default(117-122)items(101-112)minItems(147-152)maxItems(157-162)toArray(263-341)
🔇 Additional comments (19)
tests/Pest.php (1)
3-3: LGTM! Strict typing added.The addition of strict type declaration aligns with the PR's goal to improve type safety across the codebase.
tests/TestCase.php (1)
3-3: LGTM! Strict typing added.Consistent with the codebase-wide adoption of strict type declarations.
src/Schema/PropertyBuilder.php (4)
3-5: LGTM! Strict typing and namespace migration applied.The strict type declaration and namespace update from
SchemastoSchemaalign with the PR objectives.
20-20: LGTM! Type updated to Property.The nested builder type correctly changed from
BuildertoProperty, consistent with the API migration.
104-104: LGTM! Instantiation updated to Property.The nested builder instantiation correctly uses the new
Propertyclass.
237-237: LGTM! Method signature updated.The parameter type correctly changed from
BuildertoProperty, maintaining type consistency across the codebase.tests/Feature/ExampleTest.php (1)
3-3: LGTM! Strict typing added.Consistent with the strict type discipline adopted across the test suite.
src/Facades/Schema.php (1)
3-4: LGTM! Strict typing added.The strict type declaration is correctly placed.
src/Commands/MakeStructCommand.php (1)
3-4: LGTM! Strict typing added.The strict type declaration is properly placed.
src/ForerunnerServiceProvider.php (4)
3-4: LGTM! Strict typing added.The strict type declaration is correctly placed.
8-8: LGTM! Import path updated.The import correctly references the new
Schema\Structnamespace.
16-37: LGTM! Singleton binding preserved.The facade binding remains functional after the namespace migration. Config loading has been appropriately removed as per the PR objectives.
43-50: LGTM! Command registration intact.The
MakeStructCommandregistration is properly maintained.tests/Unit/PropertyBuilderTest.php (4)
3-5: LGTM! Strict typing and imports updated.The strict type declaration and imports correctly reference the new
Schema\PropertyandSchema\PropertyBuilderclasses.
158-161: LGTM! Callback type updated to Property.The callback parameter type correctly changed from
BuildertoProperty, aligning with the API migration.
173-174: LGTM! Instantiation updated to Property.The test correctly instantiates the new
Propertyclass instead ofBuilder.
254-256: LGTM! Instantiation updated to Property.The test correctly uses the new
Propertyclass, maintaining consistency with the migration.tests/Feature/MakeStructCommandTest.php (1)
52-54: Generator assertions align with new API. LGTM.Imports, return signature, and ->toArray() assertion match the refactor; strict by default is asserted. No changes needed.
Also applies to: 62-65, 73-74
tests/Unit/StructTest.php (1)
9-12: LGTM on API migration and coverageThe tests cleanly validate the new signatures, nested object/array handling, enum/defaults, and JsonSerializable. No issues found.
Also applies to: 32-36, 44-50, 61-64, 72-76, 83-90, 99-107, 115-121, 125-141, 156-164, 167-172, 179-183, 189-200, 209-219, 221-229
|
Note Docstrings generation - SUCCESS |
Docstrings generation was requested by @deemonic. * #1 (comment) The following files were modified: * `src/ForerunnerServiceProvider.php` * `src/Schema/Property.php` * `src/Schema/PropertyBuilder.php` * `src/Schema/Struct.php`
- Fix strict() mode to mark fields added after strict() as required - Make toArray() non-mutating by computing required array per-call - Update facade docblock to reference correct namespace These changes ensure strict mode works correctly even when fields are added after calling strict(), and prevent toArray() from causing side effects that could affect subsequent calls. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
✅ CodeRabbit Review Feedback AddressedI've fixed all the issues identified by CodeRabbit in commit 5a27b42: 1. Strict mode now handles fields added after
|
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/Facades/Schema.php(1 hunks)src/Schema/Property.php(7 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/Schema/Property.php (2)
src/Schema/PropertyBuilder.php (3)
required(59-64)toArray(263-341)isRequired(245-248)src/Schema/Struct.php (1)
toArray(41-59)
🔇 Additional comments (6)
src/Facades/Schema.php (1)
3-4: LGTM! Strict types enforced.The addition of
declare(strict_types=1)aligns with the PR's goal of adding strict type declarations across the codebase.src/Schema/Property.php (5)
3-5: LGTM! Strict types and namespace migration.The strict types declaration and namespace change from
SchemastoSchemaalign with the PR's refactoring objectives.
7-7: LGTM! Class renamed to Property.The class rename from
BuildertoPropertyimproves API ergonomics as intended by the PR.
25-26: LGTM! Strict mode tracking implemented.The
$isStrictproperty andisStrict()accessor cleanly track strict mode state, enabling OpenAI Structured Outputs format support in the Struct class.Also applies to: 244-250
101-101: LGTM! Nested builder uses Property.Correctly updated to instantiate
Propertyinstead ofBuilderfor nested objects.
268-272: LGTM! Auto-require in strict mode.Automatically marking new properties as required in strict mode ensures consistency, even for properties added after
strict()is called. This aligns with OpenAI Structured Outputs requirements.
| use Illuminate\Support\Facades\Facade; | ||
|
|
||
| /** | ||
| * @method static array<string, mixed> define(string $name, callable $callback) |
There was a problem hiding this comment.
Update method signature to include required description parameter.
According to the PR objectives, Struct::define now requires a description parameter: define(string $name, string $description, callable $callback). The current PHPDoc signature is missing this parameter.
Apply this diff to correct the signature:
- * @method static array<string, mixed> define(string $name, callable $callback)
+ * @method static array<string, mixed> define(string $name, string $description, callable $callback)🤖 Prompt for AI Agents
In src/Facades/Schema.php around line 10, the PHPDoc @method signature for
define is missing the required description parameter; update the docblock to
reflect Struct::define(string $name, string $description, callable $callback) so
the @method reads: @method static array<string, mixed> define(string $name,
string $description, callable $callback), ensuring the parameter order and types
match the implementation and regenerate any doc caches if needed.
- Remove dead code: $this->required property and markRequired() method - Update facade PHPDoc to include required description parameter - Fix README examples to call strict() after defining all fields - Update test to verify toArray() idempotency instead of markRequired() - Add documentation note about calling strict() at the end These changes ensure the API is cleaner, documentation is accurate, and strict() usage follows best practices by being called after all fields are defined. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
✅ Additional CodeRabbit Feedback AddressedFixed all new issues identified in commit 35ccefe: 1. 🔴 Removed dead code ✅Files: Removed the now-unused 2. 🟡 Updated facade PHPDoc signature ✅File: Fixed the - * @method static array<string, mixed> define(string $name, callable $callback)
+ * @method static \Blaspsoft\Forerunner\Schema\Struct define(string $name, string $description, callable $callback)3. 🟠 Fixed README strict() ordering ✅Files: Moved
Why this matters: Our implementation now auto-requires fields added after 4. Updated test expectations ✅File: Changed the "avoids duplicate required fields" test to verify Tests: All 118 tests passing with 402 assertions ✅ |
Summary
Major refactor to improve the package API ergonomics, simplify the schema builder interface, and add OpenAI Structured Outputs format support.
Key Changes
API Improvements
Builderclass toPropertyfor better semantic clarity - the class builds properties, not the entire structureStruct::define()to align with LLM provider requirements (Anthropic Claude requires description)Struct::define(name, description, callback)$builderto$propertythroughout codebase for consistency$property->string('name', 'Description')Simplifications
Schemasnamespace toSchemafor cleaner importstoJson()method - usejson_encode($struct)instead (implementsJsonSerializable)declare(strict_types=1)to all PHP files for better type safetyNew Features
->strict()mode wraps schema in{name, strict: true, schema: {...}}formattoArray()results are cached for performanceBreaking Changes
Blaspsoft\Forerunner\Schemas\Builder→Blaspsoft\Forerunner\Schema\PropertyBlaspsoft\Forerunner\Schemas\Struct→Blaspsoft\Forerunner\Schema\StructStruct::define($name, $callback)→Struct::define($name, $description, $callback)function (Builder $builder)→function (Property $property)$struct->toJson()→ Usejson_encode($struct)insteadMigration Example
Before:
After:
Testing
Documentation
toJson()references🤖 Generated with Claude Code
Summary by CodeRabbit
Breaking Changes
Documentation
Tests/Chores