Skip to content

Commit baf39a0

Browse files
wol-softclaude
andcommitted
Add $schema-URI Draft auto-detection for Draft 2019-09
AutoDetectionDraft previously always resolved to Draft_07 regardless of a schema's declared $schema keyword. Schemas declaring the 2019-09 meta-schema URI (http/https, with or without trailing #) now resolve to a cached Draft_2019_09 instance; every other case (absent, unrecognised, or the draft-07 URI) keeps the existing Draft_07 fallback unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 165da77 commit baf39a0

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

src/Draft/AutoDetectionDraft.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,30 @@
88

99
class AutoDetectionDraft implements DraftFactoryInterface
1010
{
11+
/** URI variants (with and without trailing '#', http and https) identifying a draft 2019-09 schema */
12+
private const array DRAFT_2019_09_SCHEMA_URIS = [
13+
'https://json-schema.org/draft/2019-09/schema',
14+
'https://json-schema.org/draft/2019-09/schema#',
15+
'http://json-schema.org/draft/2019-09/schema',
16+
'http://json-schema.org/draft/2019-09/schema#',
17+
];
18+
1119
/** @var DraftInterface[] Keyed by draft class name; reused across schemas */
1220
private array $draftInstances = [];
1321

1422
public function getDraftForSchema(JsonSchema $jsonSchema): DraftInterface
1523
{
16-
// Only Draft_07 is currently supported; all schemas (including unrecognised
17-
// or absent $schema keywords) fall back to it. Additional drafts will be
18-
// detected here when additional drafts are added (e.g. draft-04, draft 2020-12).
24+
$schemaUri = $jsonSchema->getJson()['$schema'] ?? null;
25+
26+
// Detect draft 2019-09 by its declared $schema URI. Every other case --
27+
// an absent $schema keyword, the draft-07 URI, or any unrecognised URI --
28+
// falls back to Draft_07, preserving the previous unconditional behaviour.
29+
// Additional drafts will be detected here when support for them is added
30+
// (e.g. draft-04, draft 2020-12).
31+
if (in_array($schemaUri, self::DRAFT_2019_09_SCHEMA_URIS, true)) {
32+
return $this->draftInstances[Draft_2019_09::class] ??= new Draft_2019_09();
33+
}
34+
1935
return $this->draftInstances[Draft_07::class] ??= new Draft_07();
2036
}
2137
}

tests/Draft/DraftTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use PHPModelGenerator\Draft\AutoDetectionDraft;
88
use PHPModelGenerator\Draft\Draft_07;
9+
use PHPModelGenerator\Draft\Draft_2019_09;
910
use PHPModelGenerator\Draft\Element\Type;
1011
use PHPModelGenerator\Exception\SchemaException;
1112
use PHPModelGenerator\Exception\String\MinLengthException;
@@ -170,6 +171,51 @@ public function testAutoDetectionFallsBackToDraft07ForUnrecognisedSchemaKeyword(
170171
$this->assertInstanceOf(Draft_07::class, (new AutoDetectionDraft())->getDraftForSchema($jsonSchema));
171172
}
172173

174+
/** @return array<string, array{string}> */
175+
public static function draft201909SchemaUriProvider(): array
176+
{
177+
return [
178+
'https without trailing hash' => ['https://json-schema.org/draft/2019-09/schema'],
179+
'https with trailing hash' => ['https://json-schema.org/draft/2019-09/schema#'],
180+
'http without trailing hash' => ['http://json-schema.org/draft/2019-09/schema'],
181+
'http with trailing hash' => ['http://json-schema.org/draft/2019-09/schema#'],
182+
];
183+
}
184+
185+
#[DataProvider('draft201909SchemaUriProvider')]
186+
public function testAutoDetectionReturnsDraft201909ForDraft201909SchemaKeyword(string $schemaUri): void
187+
{
188+
$jsonSchema = new JsonSchema('test.json', ['$schema' => $schemaUri]);
189+
190+
$this->assertInstanceOf(Draft_2019_09::class, (new AutoDetectionDraft())->getDraftForSchema($jsonSchema));
191+
}
192+
193+
public function testAutoDetectionReusesCachedDraft07Instance(): void
194+
{
195+
$autoDetectionDraft = new AutoDetectionDraft();
196+
197+
$firstSchema = new JsonSchema('first.json', ['$schema' => 'http://json-schema.org/draft-07/schema#']);
198+
$secondSchema = new JsonSchema('second.json', ['type' => 'object']);
199+
200+
$this->assertSame(
201+
$autoDetectionDraft->getDraftForSchema($firstSchema),
202+
$autoDetectionDraft->getDraftForSchema($secondSchema),
203+
);
204+
}
205+
206+
public function testAutoDetectionReusesCachedDraft201909Instance(): void
207+
{
208+
$autoDetectionDraft = new AutoDetectionDraft();
209+
210+
$firstSchema = new JsonSchema('first.json', ['$schema' => 'https://json-schema.org/draft/2019-09/schema']);
211+
$secondSchema = new JsonSchema('second.json', ['$schema' => 'https://json-schema.org/draft/2019-09/schema#']);
212+
213+
$this->assertSame(
214+
$autoDetectionDraft->getDraftForSchema($firstSchema),
215+
$autoDetectionDraft->getDraftForSchema($secondSchema),
216+
);
217+
}
218+
173219
// --- GeneratorConfiguration ---
174220

175221
public function testGeneratorConfigurationDefaultDraftIsAutoDetection(): void

0 commit comments

Comments
 (0)