From c535f21069f1e27a0b71fdab3d18518b5ffa5a72 Mon Sep 17 00:00:00 2001 From: Romain Canon Date: Tue, 12 Mar 2024 07:21:48 +0100 Subject: [PATCH] fix: properly encode scalar value in JSON normalization --- src/Normalizer/Formatter/JsonFormatter.php | 12 ++++-------- tests/Integration/Normalizer/NormalizerTest.php | 10 ++++++++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Normalizer/Formatter/JsonFormatter.php b/src/Normalizer/Formatter/JsonFormatter.php index a3369f5b..930daf9f 100644 --- a/src/Normalizer/Formatter/JsonFormatter.php +++ b/src/Normalizer/Formatter/JsonFormatter.php @@ -7,16 +7,14 @@ 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 @@ public function format(mixed $value): void $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 diff --git a/tests/Integration/Normalizer/NormalizerTest.php b/tests/Integration/Normalizer/NormalizerTest.php index 2a1359d5..22f0a2eb 100644 --- a/tests/Integration/Normalizer/NormalizerTest.php +++ b/tests/Integration/Normalizer/NormalizerTest.php @@ -132,6 +132,12 @@ public static function normalize_basic_values_yields_expected_output_data_provid '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 @@ public function getIterator(): Traversable 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 @@ public function getIterator(): Traversable '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(),