Skip to content

Commit

Permalink
Add type hint and refacto json classes, remove deprecated methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
terabytesoftw committed Jan 19, 2024
1 parent 8982a26 commit 3fcd2b1
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 79 deletions.
55 changes: 19 additions & 36 deletions src/Json/JsonFile.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Foxy package.
*
Expand All @@ -11,43 +13,32 @@

namespace Foxy\Json;

use Composer\Json\JsonFile as BaseJsonFile;

/**
* The JSON file.
*
* @author François Pluchino <[email protected]>
*/
class JsonFile extends BaseJsonFile
final class JsonFile extends \Composer\Json\JsonFile
{
/**
* @var string[]
*/
private $arrayKeys;

/**
* @var int
*/
private $indent;

/**
* @var string[]
* @psalm-var string[]|null
*/
private static $encodeArrayKeys = array();

private array $arrayKeys = [];
private int|null $indent = null;
/**
* @var int
* @psalm-var string[]
*/
private static $encodeIndent = JsonFormatter::DEFAULT_INDENT;
private static array $encodeArrayKeys = [];
private static int $encodeIndent = JsonFormatter::DEFAULT_INDENT;

/**
* Get the list of keys to be retained with an array representation if they are empty.
*
* @return string[]
* @psalm-return string[]
*/
public function getArrayKeys()
public function getArrayKeys(): array
{
if (null === $this->arrayKeys) {
if ([] === $this->arrayKeys) {
$this->parseOriginalContent();
}

Expand All @@ -56,10 +47,8 @@ public function getArrayKeys()

/**
* Get the indent for this json file.
*
* @return int
*/
public function getIndent()
public function getIndent(): int
{
if (null === $this->indent) {
$this->parseOriginalContent();
Expand All @@ -68,10 +57,7 @@ public function getIndent()
return $this->indent;
}

/**
* {@inheritdoc}
*/
public function read()
public function read(): array
{
$data = parent::read();
$this->getArrayKeys();
Expand All @@ -80,22 +66,19 @@ public function read()
return $data;
}

/**
* {@inheritdoc}
*/
public function write(array $hash, int $options = 448)
public function write(array $hash, int $options = 448): void
{
self::$encodeArrayKeys = $this->getArrayKeys();
self::$encodeIndent = $this->getIndent();
parent::write($hash, $options);
self::$encodeArrayKeys = array();
self::$encodeIndent = JsonFormatter::DEFAULT_INDENT;
self::$encodeArrayKeys = [];
self::$encodeIndent = 4;
}

/**
* {@inheritdoc}
*/
public static function encode($data, int $options = 448, string $indent = self::INDENT_DEFAULT): string
public static function encode(mixed $data, int $options = 448, string $indent = self::INDENT_DEFAULT): string
{
$result = parent::encode($data, $options, $indent);

Expand All @@ -105,7 +88,7 @@ public static function encode($data, int $options = 448, string $indent = self::
/**
* Parse the original content.
*/
private function parseOriginalContent()
private function parseOriginalContent(): void
{
$content = $this->exists() ? file_get_contents($this->getPath()) : '';
$this->arrayKeys = JsonFormatter::getArrayKeys($content);
Expand Down
95 changes: 65 additions & 30 deletions src/Json/JsonFormatter.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Foxy package.
*
Expand All @@ -11,44 +13,40 @@

namespace Foxy\Json;

use Composer\Json\JsonFormatter as ComposerJsonFormatter;

/**
* Formats JSON strings with a custom indent.
*
* @author François Pluchino <[email protected]>
*/
class JsonFormatter
final class JsonFormatter
{
const DEFAULT_INDENT = 4;
const ARRAY_KEYS_REGEX = '/["\']([\w\d_\-.]+)["\']:\s\[]/';
const INDENT_REGEX = '/^[{\[][\r\n]([ ]+)["\']/';
public const DEFAULT_INDENT = 4;
public const ARRAY_KEYS_REGEX = '/["\']([\w\d_\-.]+)["\']:\s\[]/';
public const INDENT_REGEX = '/^[{\[][\r\n]([ ]+)["\']/';

/**
* Get the list of keys to be retained with an array representation if they are empty.
*
* @param string $content The content
* @param string $content The content.
*
* @return string[]
* @psalm-return string[] The list of keys to be retained with an array representation if they are empty.
*/
public static function getArrayKeys($content)
public static function getArrayKeys(string $content): array
{
preg_match_all(self::ARRAY_KEYS_REGEX, trim($content), $matches);

return !empty($matches) ? $matches[1] : array();
return !empty($matches) ? $matches[1] : [];
}

/**
* Get the indent of file.
*
* @param string $content The content
*
* @return int
*/
public static function getIndent($content)
public static function getIndent(string $content): int
{
$indent = self::DEFAULT_INDENT;
preg_match(self::INDENT_REGEX, trim($content), $matches);
\preg_match(self::INDENT_REGEX, \trim($content), $matches);

if (!empty($matches)) {
$indent = \strlen($matches[1]);
Expand All @@ -60,42 +58,79 @@ public static function getIndent($content)
/**
* Format the data in JSON.
*
* @param string $json The original JSON
* @param string[] $arrayKeys The list of keys to be retained with an array representation if they are empty
* @param int $indent The space count for indent
* @param bool $formatJson Check if the json must be formatted
* @param string $json The original JSON.
* @param array $arrayKeys The list of keys to be retained with an array representation if they are empty.
* @param int $indent The space count for indent.
* @param bool $formatJson Check if the json must be formatted.
*
* @return string
*/
public static function format($json, array $arrayKeys = array(), $indent = self::DEFAULT_INDENT, $formatJson = true)
{
public static function format(
string $json,
array $arrayKeys = [],
$indent = self::DEFAULT_INDENT,
$formatJson = true
): string {
if ($formatJson) {
$json = ComposerJsonFormatter::format($json, true, true);
$json = self::formatInternal($json, true, true);
}

if (4 !== $indent) {
$json = str_replace(' ', sprintf('%'.$indent.'s', ''), $json);
$json = \str_replace(' ', \str_repeat(' ', $indent), $json);
}

return self::replaceArrayByMap($json, $arrayKeys);
}

/**
* Format the data in JSON.
*
* @param bool $unescapeUnicode Un escape unicode.
* @param bool $unescapeSlashes Un escape slashes.
*/
private static function formatInternal(string $json, bool $unescapeUnicode, bool $unescapeSlashes): string
{
$array = \json_decode($json, true);

if ($unescapeUnicode) {
\array_walk_recursive($array, function (&$item) {
if (\is_string($item)) {
$item = \preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function ($match) {
return \mb_convert_encoding(\pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
}, $item);
}
});
}

if ($unescapeSlashes) {
\array_walk_recursive($array, function (&$item) {
if (\is_string($item)) {
$item = \str_replace('\\/', '/', $item);
}
});
}

return \json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}

/**
* Replace the empty array by empty map.
*
* @param string $json The original JSON
* @param string[] $arrayKeys The list of keys to be retained with an array representation if they are empty
* @param string $json The original JSON.
* @param array $arrayKeys The list of keys to be retained with an array representation if they are empty.
*
* @psalm-param string[] $arrayKeys The list of keys to be retained with an array representation if they are empty.
*
* @return string
*/
private static function replaceArrayByMap($json, array $arrayKeys)
private static function replaceArrayByMap(string $json, array $arrayKeys): string
{
preg_match_all(self::ARRAY_KEYS_REGEX, $json, $matches, PREG_SET_ORDER);
\preg_match_all(self::ARRAY_KEYS_REGEX, $json, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
if (!\in_array($match[1], $arrayKeys, true)) {
$replace = str_replace('[]', '{}', $match[0]);
$json = str_replace($match[0], $replace, $json);
$replace = \str_replace('[]', '{}', $match[0]);
$json = \str_replace($match[0], $replace, $json);
}
}

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
26 changes: 13 additions & 13 deletions tests/Json/JsonFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ public function testGetIndent()
}

public function testFormat()
{
$expected = <<<'JSON'
{
$expected = <<<'JSON'
{
"name": "test",
"contributors": [],
Expand All @@ -62,16 +62,16 @@ public function testFormat()
"devDependencies": {}
}
JSON;
$data = array(
'name' => 'test',
'contributors' => array(),
'dependencies' => array(
'@foo/bar' => '^1.0.0',
),
'devDependencies' => array(),
);
$content = json_encode($data);
$data = array(
'name' => 'test',
'contributors' => array(),
'dependencies' => array(
'@foo/bar' => '^1.0.0',
),
'devDependencies' => array(),
);
$content = json_encode($data);

static::assertSame($expected, JsonFormatter::format($content, array('contributors'), 2));
}
static::assertSame($expected, JsonFormatter::format($content, array('contributors'), 2));
}
}

0 comments on commit 3fcd2b1

Please sign in to comment.