Skip to content

Commit

Permalink
Enhancement: Implement JsonPointer
Browse files Browse the repository at this point in the history
  • Loading branch information
localheinz committed Jan 28, 2022
1 parent 46547c2 commit c607de8
Show file tree
Hide file tree
Showing 6 changed files with 393 additions and 2 deletions.
11 changes: 9 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## Unreleased

For a full diff see [`a5ba52c...main`][a5ba52c...main].
For a full diff see [`1.0.0...main`][1.0.0...main].

## [`1.0.0`][1.0.0]

For a full diff see [`a5ba52c...1.0.0`][a5ba52c...1.0.0].

### Added

- Added `ReferenceToken` as a value object ([#1]), by [@localheinz]
- Added `JsonPointer` as a value object ([#2]), by [@localheinz]

[a5ba52c...main]: https://github.com/ergebnis/json-pointer/compare/a5ba52c...main
[a5ba52c...1.0.0]: https://github.com/ergebnis/json-pointer/compare/a5ba52c...1.0.0
[1.0.0...main]: https://github.com/ergebnis/json-pointer/compare/1.0.0...main

[#1]: https://github.com/ergebnis/json-pointer/pull/1
[#2]: https://github.com/ergebnis/json-pointer/pull/2

[@localheinz]: https://github.com/localheinz
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,69 @@ $two = Pointer\ReferenceToken::fromEscapedString('foo~1bar');
$one->equals($two); // true
```

### `JsonPointer`

You can create a `JsonPointer` referencing a document:

```php
<?php

declare(strict_types=1);

use Ergebnis\Json\Pointer;

$jsonPointer = Pointer\JsonPointer::document();

$jsonPointer->toString(); // ''
```

You can create a `JsonPointer` from a `string` value:

```php
<?php

declare(strict_types=1);

use Ergebnis\Json\Pointer;

$jsonPointer = Pointer\JsonPointer::fromString('/foo/bar');

$jsonPointer->toString(); // '/foo/bar'
```

You can compare `JsonPointer`s:

```php
<?php

declare(strict_types=1);

use Ergebnis\Json\Pointer;

$one = Pointer\JsonPointer::fromString('/foo/bar');
$two = Pointer\JsonPointer::fromString('/foo~1bar');

$one->equals($two); // false
```

You can append a `ReferenceToken` to a `JsonPointer`:

```php
<?php

declare(strict_types=1);

use Ergebnis\Json\Pointer;

$jsonPointer = Pointer\JsonPointer::fromString('/foo/bar');

$referenceToken = Pointer\ReferenceToken::fromUnescapedString('baz');

$newJsonPointer = $jsonPointer->append($referenceToken);

$newJsonPointer->toString(); // '/foo/bar/baz'
```

## Changelog

Please have a look at [`CHANGELOG.md`](CHANGELOG.md).
Expand Down
25 changes: 25 additions & 0 deletions src/Exception/InvalidJsonPointer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2020-2022 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/json-pointer
*/

namespace Ergebnis\Json\Pointer\Exception;

final class InvalidJsonPointer extends \InvalidArgumentException implements Exception
{
public static function fromString(string $value): self
{
return new self(\sprintf(
'Value "%s" does not appear to be a valid JSON Pointer.',
$value,
));
}
}
67 changes: 67 additions & 0 deletions src/JsonPointer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2020-2022 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/json-pointer
*/

namespace Ergebnis\Json\Pointer;

/**
* @psalm-immutable
*
* @see https://datatracker.ietf.org/doc/html/rfc6901
*/
final class JsonPointer
{
private string $value;

private function __construct(string $value)
{
$this->value = $value;
}

/**
* @see https://datatracker.ietf.org/doc/html/rfc6901#section-3
*
* @throws Exception\InvalidJsonPointer
*/
public static function fromString(string $value): self
{
if (1 !== \preg_match('/^(\/(?P<referenceToken>((?P<unescaped>[\x00-\x2E]|[\x30-\x7D]|[\x7F-\x{10FFFF}])|(?P<escaped>~[01]))*))*$/u', $value, $matches)) {
throw Exception\InvalidJsonPointer::fromString($value);
}

return new self($value);
}

public static function document(): self
{
return new self('');
}

public function append(ReferenceToken $referenceToken): self
{
return new self(\sprintf(
'%s/%s',
$this->value,
$referenceToken->toEscapedString(),
));
}

public function toString(): string
{
return $this->value;
}

public function equals(self $other): bool
{
return $this->value === $other->value;
}
}
42 changes: 42 additions & 0 deletions test/Unit/Exception/InvalidJsonPointerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2020-2022 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/json-pointer
*/

namespace Ergebnis\Json\Pointer\Test\Unit\Exception;

use Ergebnis\Json\Pointer\Exception;
use Ergebnis\Json\Pointer\Test;
use PHPUnit\Framework;

/**
* @internal
*
* @covers \Ergebnis\Json\Pointer\Exception\InvalidJsonPointer
*/
final class InvalidJsonPointerTest extends Framework\TestCase
{
use Test\Util\Helper;

public function testFromValueReturnsInvalidJsonPointerException(): void
{
$value = self::faker()->sentence();

$exception = Exception\InvalidJsonPointer::fromString($value);

$message = \sprintf(
'Value "%s" does not appear to be a valid JSON Pointer.',
$value,
);

self::assertSame($message, $exception->getMessage());
}
}
Loading

0 comments on commit c607de8

Please sign in to comment.