Skip to content

Commit

Permalink
Fixed merge script for specs with dots in paths
Browse files Browse the repository at this point in the history
  • Loading branch information
aprokopenko committed Jul 18, 2018
1 parent fc8b7cb commit f91ea16
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 18 deletions.
14 changes: 8 additions & 6 deletions src/Helpers/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ class Arr
* `function($array, $defaultValue)`.
* @param null|mixed $default the default value to be returned if the specified array key does not exist. Not used when
* getting value from an object.
* @param string $key_separator nested key parts separator
*
* @return mixed the value of the element if found, default value otherwise
*/
public static function get($array, $key, $default = null)
public static function get($array, $key, $default = null, $key_separator = '.')
{
if ($key instanceof \Closure) {
return $key($array, $default);
Expand All @@ -52,9 +53,9 @@ public static function get($array, $key, $default = null)
return $array[$key];
}

if (($pos = strrpos($key, '.')) !== false) {
$array = Arr::get($array, substr($key, 0, $pos), $default);
$key = substr($key, $pos + 1);
if (($pos = strrpos($key, $key_separator)) !== false) {
$array = Arr::get($array, substr($key, 0, $pos), $default, $key_separator);
$key = substr($key, $pos + strlen($key_separator));
}

if (is_object($array)) {
Expand Down Expand Up @@ -118,16 +119,17 @@ public static function get($array, $key, $default = null)
* you can also describe the path as an array of keys
* if the path is null then `$array` will be assigned the `$value`
* @param mixed $value the value to be written
* @param string $key_separator nested key parts separator
*/
public static function set(&$array, $path, $value)
public static function set(&$array, $path, $value, $key_separator = '.')
{
if ($path === null) {
$array = $value;

return;
}

$keys = is_array($path) ? $path : explode('.', $path);
$keys = is_array($path) ? $path : explode($key_separator, $path);

while (count($keys) > 1) {
$key = array_shift($keys);
Expand Down
10 changes: 6 additions & 4 deletions src/Helpers/Str.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ class Str
* user.profile.name > user/profile/name
*
* @param string $key
* @param string $separator array nested parts separator
*
* @return string
*/
public static function dotkey2path($key)
public static function arrkey2path($key, $separator = '.')
{
return strtr($key, [
'/' => '/',
'.' => '/',
$separator => '/',
]);
}

Expand All @@ -35,13 +36,14 @@ public static function dotkey2path($key)
* /user/profile/name/ > user.profile.name
*
* @param string $path
* @param string $separator array nested parts separator
*
* @return string
*/
public static function path2dotkey($path)
public static function path2arrkey($path, $separator = '.')
{
return strtr(trim($path, '/'), [
'/' => '.',
'/' => $separator,
]);
}
}
24 changes: 16 additions & 8 deletions src/YamlReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
*/
class YamlReader
{
/**
* Special symbol for building array nested keys
*
* URLs can contain usual cars like dots or lines, so to a safe key we will use rarely used ASCII symbol
*/
const ARR_KEY_SEP = '»';

/**
* Parse multi-document yaml file.
*
Expand Down Expand Up @@ -51,9 +58,10 @@ public function parseMultiFile($filename)
*/
public function mergeByReferences($yaml, $basedir, $index = '')
{
$branch = $index ? Arr::get($yaml, $index) : $yaml;
$ks = static::ARR_KEY_SEP; // Safe nested array key separator.
$branch = $index ? Arr::get($yaml, $index, null, $ks) : $yaml;
foreach ($branch as $key => $value) {
$branch_key = trim("$index.$key", '.');
$branch_key = trim("{$index}{$ks}{$key}", $ks);
if (is_array($value)) {
$yaml = $this->mergeByReferences($yaml, $basedir, $branch_key);
} elseif ('$ref' === $key && is_string($value) && 0 !== strpos($value, '#')) {
Expand Down Expand Up @@ -81,19 +89,19 @@ public function mergeByReferences($yaml, $basedir, $index = '')

$ref_yaml = $this->parse($ref_yaml_content);
// get referenced yaml part.
$ref_branch = Arr::get($ref_yaml, Str::path2dotkey($path));
$ref_branch = Arr::get($ref_yaml, Str::path2arrkey($path, $ks), null, $ks);

$branch_parent_path = dirname(Str::dotkey2path($index));
$ref_parent_path = dirname(Str::dotkey2path(Str::path2dotkey($path)));
$branch_parent_path = dirname(Str::arrkey2path($index, $ks));
$ref_parent_path = dirname(Str::arrkey2path(Str::path2arrkey($path, $ks), $ks));

if ($branch_parent_path !== $ref_parent_path) {
Arr::set($yaml, $branch_key, "#$path");
$branch_key = Str::path2dotkey($path);
Arr::set($yaml, $branch_key, "#$path", $ks);
$branch_key = Str::path2arrkey($path, $ks);
} else {
$branch_key = $index;
}

Arr::set($yaml, $branch_key, $ref_branch);
Arr::set($yaml, $branch_key, $ref_branch, $ks);

// check refs in replaced fragment.
$yaml = $this->mergeByReferences($yaml, $basedir, $branch_key);
Expand Down

0 comments on commit f91ea16

Please sign in to comment.