diff --git a/CHANGELOG.md b/CHANGELOG.md index b79c60c1..881460f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed - Rename master to main ([#848](https://github.com/jsonrainbow/json-schema/pull/848)) +### Fixed +- Don't skip ref expanding for property called enum when child of property called properties ([#851](https://github.com/jsonrainbow/json-schema/pull/851)) ## [6.6.0] - 2025-10-10 ### Added diff --git a/src/JsonSchema/SchemaStorage.php b/src/JsonSchema/SchemaStorage.php index f818aecd..05397e7e 100644 --- a/src/JsonSchema/SchemaStorage.php +++ b/src/JsonSchema/SchemaStorage.php @@ -81,9 +81,10 @@ public function addSchema(string $id, $schema = null): void /** * Recursively resolve all references against the provided base * - * @param mixed $schema + * @param mixed $schema + * @param list $propertyStack */ - private function expandRefs(&$schema, ?string $parentId = null): void + private function expandRefs(&$schema, ?string $parentId = null, array $propertyStack = []): void { if (!is_object($schema)) { if (is_array($schema)) { @@ -100,8 +101,9 @@ private function expandRefs(&$schema, ?string $parentId = null): void $schema->{'$ref'} = (string) $refPointer; } + $parentProperty = array_slice($propertyStack, -1)[0] ?? ''; foreach ($schema as $propertyName => &$member) { - if (in_array($propertyName, ['enum', 'const'])) { + if ($parentProperty !== 'properties' && in_array($propertyName, ['enum', 'const'])) { // Enum and const don't allow $ref as a keyword, see https://github.com/json-schema-org/JSON-Schema-Test-Suite/pull/445 continue; } @@ -112,7 +114,9 @@ private function expandRefs(&$schema, ?string $parentId = null): void $childId = $this->uriResolver->resolve($schemaId, $childId); } - $this->expandRefs($member, $childId); + $clonedPropertyStack = $propertyStack; + $clonedPropertyStack[] = $propertyName; + $this->expandRefs($member, $childId, $clonedPropertyStack); } } diff --git a/tests/Drafts/Draft3Test.php b/tests/Drafts/Draft3Test.php index 1edee6b0..d0fb90f4 100644 --- a/tests/Drafts/Draft3Test.php +++ b/tests/Drafts/Draft3Test.php @@ -78,14 +78,7 @@ protected function getFilePaths(): array public function getInvalidTests(): \Generator { - $skip = [ - 'ref.json / $ref prevents a sibling id from changing the base uri / $ref resolves to /definitions/base_foo, data does not validate' - ]; - foreach (parent::getInvalidTests() as $name => $testcase) { - if (in_array($name, $skip, true)) { - continue; - } yield $name => $testcase; } } @@ -107,15 +100,7 @@ public function getInvalidForAssocTests(): \Generator public function getValidForAssocTests(): \Generator { - $skip = [ - 'type.json / object type matches objects / an array is not an object', - 'type.json / array type matches arrays / an object is not an array', - ]; - foreach (parent::getValidForAssocTests() as $name => $testcase) { - if (in_array($name, $skip, true)) { - continue; - } yield $name => $testcase; } } @@ -129,8 +114,6 @@ protected function getSkippedTests(): array // Optional 'bignum.json', 'ecmascript-regex.json', - 'format.json', - 'jsregex.json', 'zeroTerminatedFloats.json' ]; } diff --git a/tests/Drafts/Draft4Test.php b/tests/Drafts/Draft4Test.php index 4cd0c865..e6bbd0f8 100644 --- a/tests/Drafts/Draft4Test.php +++ b/tests/Drafts/Draft4Test.php @@ -23,13 +23,8 @@ protected function getFilePaths(): array public function getInvalidTests(): \Generator { $skip = [ - 'id.json / id inside an enum is not a real identifier / no match on enum or $ref to id', - 'ref.json / $ref prevents a sibling id from changing the base uri / $ref resolves to /definitions/base_foo, data does not validate', - 'ref.json / Recursive references between schemas / invalid tree', - 'ref.json / refs with quote / object with strings is invalid', 'ref.json / Location-independent identifier / mismatch', 'ref.json / Location-independent identifier with base URI change in subschema / mismatch', - 'ref.json / empty tokens in $ref json-pointer / non-number is invalid', 'ref.json / id must be resolved against nearest parent, not just immediate parent / non-number is invalid', 'refRemote.json / Location-independent identifier in remote ref / string is invalid', 'refRemote.json / base URI change - change folder / string is invalid' @@ -46,7 +41,6 @@ public function getInvalidTests(): \Generator public function getInvalidForAssocTests(): \Generator { $skip = [ - 'ref.json / Recursive references between schemas / valid tree', 'type.json / object type matches objects / an array is not an object', 'type.json / array type matches arrays / an object is not an array', ]; @@ -62,13 +56,8 @@ public function getInvalidForAssocTests(): \Generator public function getValidTests(): \Generator { $skip = [ - 'ref.json / $ref prevents a sibling id from changing the base uri / $ref resolves to /definitions/base_foo, data validates', - 'ref.json / Recursive references between schemas / valid tree', - 'ref.json / refs with quote / object with numbers is valid', 'ref.json / Location-independent identifier / match', 'ref.json / Location-independent identifier with base URI change in subschema / match', - 'ref.json / empty tokens in $ref json-pointer / number is valid', - 'ref.json / naive replacement of $ref with its destination is not correct / match the enum exactly', 'ref.json / id must be resolved against nearest parent, not just immediate parent / number is valid', 'refRemote.json / Location-independent identifier in remote ref / integer is valid', 'refRemote.json / base URI change - change folder / number is valid',