From 3c90eb9a0740ddfa4c9efad45d2f9769bd34ba37 Mon Sep 17 00:00:00 2001 From: Sasha Date: Fri, 17 Jul 2026 07:32:02 -0700 Subject: [PATCH] PathException with "The path does not apply to this data!" for objects like {"+1": ...} because filter_var('+1', FILTER_VALIDATE_INT) is 1. --- src/JsonPointer.php | 10 ++++++++++ tests/src/AssociativeTest.php | 32 +++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/JsonPointer.php b/src/JsonPointer.php index 1311ad3..6d080aa 100644 --- a/src/JsonPointer.php +++ b/src/JsonPointer.php @@ -120,6 +120,16 @@ public static function add(&$holder, $pathItems, $value, $flags = self::RECURSIV } } else { // null or array $intKey = filter_var($key, FILTER_VALIDATE_INT); + + // Avoid PathException with objects like {"+1": ...} + $hasPlus = $intKey !== false && + is_string($key) && + $key !== '' && + $key[0] === '+'; + if ($hasPlus) { + $intKey = false; + } + if ($ref === null && (false === $intKey || $intKey !== 0)) { $key = (string)$key; if ($flags & self::RECURSIVE_KEY_CREATION) { diff --git a/tests/src/AssociativeTest.php b/tests/src/AssociativeTest.php index d3a7cb6..0771676 100644 --- a/tests/src/AssociativeTest.php +++ b/tests/src/AssociativeTest.php @@ -59,4 +59,34 @@ public function testDiffAssociative() $patch->apply($original); $this->assertEquals($newJson, $original); } -} \ No newline at end of file + + /** + * Avoid PathException with objects like {"+1": ...} + * + * @throws \Swaggest\JsonDiff\Exception + */ + public function testSignedIntegerLikeKey() + { + $original = [ + '+1' => [ + ['name' => 'first', 'keep' => 1], + ['name' => 'second', 'keep' => 2], + ], + '-1' => [ + ['name' => 'other', 'keep' => 3], + ], + ]; + + $patch = JsonPatch::import([ + ['op' => 'replace', 'path' => '/+1/1/name', 'value' => 'patched'], + ['op' => 'replace', 'path' => '/-1/0/name', 'value' => 'negative'], + ]); + $patch->setFlags(JsonPatch::TOLERATE_ASSOCIATIVE_ARRAYS); + $patch->apply($original); + + $this->assertSame('patched', $original['+1'][1]['name']); + $this->assertSame('negative', $original['-1'][0]['name']); + $this->assertSame('first', $original['+1'][0]['name']); + $this->assertArrayNotHasKey(1, $original); + } +}