Repository: CuyZ/Valinor (php)

Issue:
Serialization to json - Namespaces are not escaped
Hello ;)

I have a problem with serializing object namespaces (FQCN). Code below shows this situation:

Serilized objects:
```php
final class CheckProduct
{
    public function __construct(
        public string $name,
        public string $class,
    ) {
    }
}

final class Strawberry
{
}
```

Test:
```php
    #[Test]
    public function can_serialize_object_with_class_namespace(): void
    {
        // given
        $normalizer = (new \CuyZ\Valinor\MapperBuilder())
            ->normalizer(\CuyZ\Valinor\Normalizer\Format::json());
        // and
        $object = new CheckProduct('strawberry', Strawberry::class);

        // when
        $json = $normalizer->normalize($object);

        // then
        self::assertEquals(json_encode($object), $json);
    }
```

// output of $json variable
```
{"name":"strawberry","class":"Test\Unit\Strawberry"}
```
It's not a valid json, because backslashes are not escaped. It should be like this:
```
{"name":"strawberry","class":"Test\\Unit\\Strawberry"}
```

Is it a bug or did I forgot something?

Pull request:
fix: properly encode scalar value in JSON normalization
fixes #489 

Patch:
diff --git a/src/Normalizer/Formatter/JsonFormatter.php b/src/Normalizer/Formatter/JsonFormatter.php
index a3369f5..930daf9 100644
--- a/src/Normalizer/Formatter/JsonFormatter.php
+++ b/src/Normalizer/Formatter/JsonFormatter.php
@@ -7,16 +7,14 @@ namespace CuyZ\Valinor\Normalizer\Formatter;
 use CuyZ\Valinor\Normalizer\Formatter\Exception\CannotFormatInvalidTypeToJson;
 use Generator;
 
-use function addcslashes;
 use function array_is_list;
 use function fwrite;
 use function is_array;
 use function is_bool;
-use function is_float;
-use function is_int;
 use function is_iterable;
 use function is_null;
-use function is_string;
+use function is_scalar;
+use function json_encode;
 
 /** @internal */
 final class JsonFormatter implements StreamFormatter
@@ -34,10 +32,8 @@ final class JsonFormatter implements StreamFormatter
             $this->write('null');
         } elseif (is_bool($value)) {
             $this->write($value ? 'true' : 'false');
-        } elseif (is_int($value) || is_float($value)) {
-            $this->write((string)$value);
-        } elseif (is_string($value)) {
-            $this->write('"' . addcslashes($value, '"') . '"');
+        } elseif (is_scalar($value)) {
+            $this->write(json_encode($value, JSON_THROW_ON_ERROR));
         } elseif (is_iterable($value)) {
             // Note: when a generator is formatted, it is considered as a list
             // if its first key is 0. This is done early because the first JSON


Test patch:
diff --git a/tests/Integration/Normalizer/NormalizerTest.php b/tests/Integration/Normalizer/NormalizerTest.php
index 2a1359d..22f0a2e 100644
--- a/tests/Integration/Normalizer/NormalizerTest.php
+++ b/tests/Integration/Normalizer/NormalizerTest.php
@@ -132,6 +132,12 @@ final class NormalizerTest extends IntegrationTestCase
             'expected json' => 'true',
         ];
 
+        yield 'class string' => [
+            'input' => 'Some\Namespace\To\Class',
+            'expected array' => 'Some\Namespace\To\Class',
+            'expected json' => '"Some\\\\Namespace\\\\To\\\\Class"',
+        ];
+
         yield 'array of scalar' => [
             'input' => [
                 'string' => 'foo',
@@ -295,7 +301,7 @@ final class NormalizerTest extends IntegrationTestCase
         yield 'time zone with default transformer' => [
             'input' => new DateTimeZone('Europe/Paris'),
             'expected array' => 'Europe/Paris',
-            'expected json' => '"Europe/Paris"',
+            'expected json' => '"Europe\/Paris"',
         ];
 
         yield 'time zone with transformer' => [
@@ -304,7 +310,7 @@ final class NormalizerTest extends IntegrationTestCase
                 'name' => 'Europe/Paris',
                 'country_code' => 'FR',
             ],
-            'expected json' => '{"name":"Europe/Paris","country_code":"FR"}',
+            'expected json' => '{"name":"Europe\/Paris","country_code":"FR"}',
             'transformers' => [
                 [fn (DateTimeZone $object) => [
                     'name' => $object->getName(),