parent
16d1b11c26
commit
1c9fbeb978
|
@ -42,12 +42,16 @@ class JsonFile
|
||||||
|
|
||||||
public const COMPOSER_SCHEMA_PATH = __DIR__ . '/../../../res/composer-schema.json';
|
public const COMPOSER_SCHEMA_PATH = __DIR__ . '/../../../res/composer-schema.json';
|
||||||
|
|
||||||
|
public const INDENT_DEFAULT = ' ';
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $path;
|
private $path;
|
||||||
/** @var ?HttpDownloader */
|
/** @var ?HttpDownloader */
|
||||||
private $httpDownloader;
|
private $httpDownloader;
|
||||||
/** @var ?IOInterface */
|
/** @var ?IOInterface */
|
||||||
private $io;
|
private $io;
|
||||||
|
/** @var string */
|
||||||
|
private $indent = self::INDENT_DEFAULT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes json file reader/parser.
|
* Initializes json file reader/parser.
|
||||||
|
@ -117,6 +121,8 @@ class JsonFile
|
||||||
throw new \RuntimeException('Could not read '.$this->path);
|
throw new \RuntimeException('Could not read '.$this->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->indent = self::detectIndenting($json);
|
||||||
|
|
||||||
return static::parseJson($json, $this->path);
|
return static::parseJson($json, $this->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +137,7 @@ class JsonFile
|
||||||
public function write(array $hash, int $options = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
public function write(array $hash, int $options = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||||
{
|
{
|
||||||
if ($this->path === 'php://memory') {
|
if ($this->path === 'php://memory') {
|
||||||
file_put_contents($this->path, static::encode($hash, $options));
|
file_put_contents($this->path, static::encode($hash, $options, $this->indent));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -153,7 +159,7 @@ class JsonFile
|
||||||
$retries = 3;
|
$retries = 3;
|
||||||
while ($retries--) {
|
while ($retries--) {
|
||||||
try {
|
try {
|
||||||
$this->filePutContentsIfModified($this->path, static::encode($hash, $options). ($options & JSON_PRETTY_PRINT ? "\n" : ''));
|
$this->filePutContentsIfModified($this->path, static::encode($hash, $options, $this->indent). ($options & JSON_PRETTY_PRINT ? "\n" : ''));
|
||||||
break;
|
break;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
if ($retries > 0) {
|
if ($retries > 0) {
|
||||||
|
@ -262,15 +268,28 @@ class JsonFile
|
||||||
*
|
*
|
||||||
* @param mixed $data Data to encode into a formatted JSON string
|
* @param mixed $data Data to encode into a formatted JSON string
|
||||||
* @param int $options json_encode options (defaults to JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
* @param int $options json_encode options (defaults to JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||||
|
* @param string $indent Indentation string
|
||||||
* @return string Encoded json
|
* @return string Encoded json
|
||||||
*/
|
*/
|
||||||
public static function encode($data, int $options = 448)
|
public static function encode($data, int $options = 448, string $indent = self::INDENT_DEFAULT): string
|
||||||
{
|
{
|
||||||
$json = json_encode($data, $options);
|
$json = json_encode($data, $options);
|
||||||
|
|
||||||
if (false === $json) {
|
if (false === $json) {
|
||||||
self::throwEncodeError(json_last_error());
|
self::throwEncodeError(json_last_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (($options & JSON_PRETTY_PRINT) > 0 && $indent !== self::INDENT_DEFAULT ) {
|
||||||
|
// Pretty printing and not using default indentation
|
||||||
|
return Preg::replaceCallback(
|
||||||
|
'#^ {4,}#m',
|
||||||
|
static function ($match) use ($indent): string {
|
||||||
|
return str_repeat($indent, (int)(strlen($match[0] ?? '') / 4));
|
||||||
|
},
|
||||||
|
$json
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return $json;
|
return $json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +298,7 @@ class JsonFile
|
||||||
*
|
*
|
||||||
* @param int $code return code of json_last_error function
|
* @param int $code return code of json_last_error function
|
||||||
* @throws \RuntimeException
|
* @throws \RuntimeException
|
||||||
|
* @return never
|
||||||
*/
|
*/
|
||||||
private static function throwEncodeError(int $code): void
|
private static function throwEncodeError(int $code): void
|
||||||
{
|
{
|
||||||
|
@ -356,4 +376,12 @@ class JsonFile
|
||||||
$result->getDetails());
|
$result->getDetails());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function detectIndenting(?string $json): string
|
||||||
|
{
|
||||||
|
if (Preg::isMatchStrictGroups('#^([ \t]+)"#m', $json ?? '', $match)) {
|
||||||
|
return $match[1];
|
||||||
|
}
|
||||||
|
return self::INDENT_DEFAULT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -561,10 +561,6 @@ class JsonManipulator
|
||||||
|
|
||||||
protected function detectIndenting(): void
|
protected function detectIndenting(): void
|
||||||
{
|
{
|
||||||
if (Preg::isMatchStrictGroups('{^([ \t]+)"}m', $this->contents, $match)) {
|
$this->indent = JsonFile::detectIndenting($this->contents);
|
||||||
$this->indent = $match[1];
|
|
||||||
} else {
|
|
||||||
$this->indent = ' ';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
|
@ -364,6 +364,29 @@ class JsonFileTest extends TestCase
|
||||||
$this->assertEquals($data, $doubleData);
|
$this->assertEquals($data, $doubleData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testPreserveIndentationAfterRead(): void
|
||||||
|
{
|
||||||
|
copy(__DIR__.'/Fixtures/tabs.json', __DIR__.'/Fixtures/tabs2.json');
|
||||||
|
$jsonFile = new JsonFile(__DIR__.'/Fixtures/tabs2.json');
|
||||||
|
$data = $jsonFile->read();
|
||||||
|
$jsonFile->write(['foo' => 'baz']);
|
||||||
|
|
||||||
|
self::assertSame("{\n\t\"foo\": \"baz\"\n}\n", file_get_contents(__DIR__.'/Fixtures/tabs2.json'));
|
||||||
|
|
||||||
|
unlink(__DIR__.'/Fixtures/tabs2.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOverwritesIndentationByDefault(): void
|
||||||
|
{
|
||||||
|
copy(__DIR__.'/Fixtures/tabs.json', __DIR__.'/Fixtures/tabs2.json');
|
||||||
|
$jsonFile = new JsonFile(__DIR__.'/Fixtures/tabs2.json');
|
||||||
|
$jsonFile->write(['foo' => 'baz']);
|
||||||
|
|
||||||
|
self::assertSame("{\n \"foo\": \"baz\"\n}\n", file_get_contents(__DIR__.'/Fixtures/tabs2.json'));
|
||||||
|
|
||||||
|
unlink(__DIR__.'/Fixtures/tabs2.json');
|
||||||
|
}
|
||||||
|
|
||||||
private function expectParseException(string $text, string $json): void
|
private function expectParseException(string $text, string $json): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue