Compare commits

...
Author SHA1 Message Date
cliphouse 2bb405d741 Add tests for new array functions, other minro fixes for phan && phpstan checks 2026-09-18 17:33:44 +09:00
cliphouse c38ff8b405 Merge branch 'development' into feature/TTD-2662/function-add-to-ArrayCombined 2026-09-18 15:44:01 +09:00
cliphouse 66d5f6247b Add eslint packages 2026-09-18 15:43:01 +09:00
Clemens Schwaighofer e2362418aa phive updates 2026-04-20 10:36:26 +09:00
Clemens Schwaighofer 71e34848d9 Merge branch 'development' into feature/TTD-2662/function-add-to-ArrayCombined 2026-04-17 18:57:59 +09:00
Clemens Schwaighofer f275180571 Add bew array handler functions for various array interfaces
get random entry, remove array entry by value, add string to each entry in array, create sort by array key
2026-03-25 18:51:28 +09:00
9 changed files with 486 additions and 28 deletions
@@ -16,7 +16,7 @@ use PHPUnit\Framework\TestCase;
*/
final class CoreLibsCombinedArrayHandlerTest extends TestCase
{
// we use that for all
/** @var array<mixed> we use that for all */
public static $array = [
'a' => [
'b' => 'bar',
@@ -51,7 +51,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* Undocumented function
*
* @return array
* @return array<mixed>
*/
public function arraySearchRecursiveProvider(): array
{
@@ -110,7 +110,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* Undocumented function
*
* @return array
* @return array<mixed>
*/
public function arraySearchRecursiveAllProvider(): array
{
@@ -182,7 +182,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* Undocumented function
*
* @return array
* @return array<mixed>
*/
public function arraySearchSimpleProvider(): array
{
@@ -383,7 +383,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* Undocumented function
*
* @return array
* @return array<mixed>
*/
public function arraySearchKeyProvider(): array
{
@@ -565,7 +565,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* provides array listing for the merge test
*
* @return array
* @return array<mixed>
*/
public function arrayMergeRecursiveProvider(): array
{
@@ -602,7 +602,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* for warning checks
*
* @return array
* @return array<mixed>
*/
public function arrayMergeRecursiveProviderWarning(): array
{
@@ -634,7 +634,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* Undocumented function
*
* @return array
* @return array<mixed>
*/
public function arrayCompareProvider(): array
{
@@ -665,7 +665,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* Undocumented function
*
* @return array
* @return array<mixed>
*/
public function inArrayAnyProvider(): array
{
@@ -688,6 +688,11 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
];
}
/**
* Undocumented function
*
* @return array<mixed>
*/
public function genAssocArrayProvider(): array
{
return [
@@ -764,7 +769,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* Undocumented function
*
* @return array
* @return array<mixed>
*/
public function flattenArrayProvider(): array
{
@@ -808,7 +813,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* use the flattenArrayProvider and replace 1 with 2 array pos
*
* @return array
* @return array<mixed>
*/
public function flattenArrayKeyProvider(): array
{
@@ -825,7 +830,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* use the flattenArrayProvider and replace 1 with array pos
*
* @return array
* @return array<mixed>
*/
public function flattenArrayKeyLeavesOnlyProvider(): array
{
@@ -842,7 +847,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
/**
* Undocumented function
*
* @return array
* @return array<mixed>
*/
public function arrayFlatForKeyProvider(): array
{
@@ -906,6 +911,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
];
}
// MARK: arraySearchRecursive
/**
* Undocumented function
*
@@ -926,6 +933,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arraySearchRecursiveAll
/**
* Undocumented function
*
@@ -947,6 +956,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arraySearchSimple
/**
* Undocumented function
*
@@ -969,6 +980,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arraySearchKey
/**
* Undocumented function
*
@@ -1007,6 +1020,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arrayMergeRecursive
/**
* Undocumented function
*
@@ -1031,6 +1046,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arrayMergeRecursive
/**
* Undocumented function
*
@@ -1063,6 +1080,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
restore_error_handler();
}
// MARK: arrayDiff
/**
* Undocumented function
*
@@ -1083,6 +1102,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: inArrayAny
/**
* Undocumented function
*
@@ -1103,6 +1124,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: genAssocArray
/**
* Undocumented function
*
@@ -1125,6 +1148,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: flattenArray
/**
* Undocumented function
*
@@ -1144,6 +1169,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: flattenArrayKey
/**
* Undocumented function
*
@@ -1163,6 +1190,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: flattenArrayKeyLeavesOnly
/**
* Undocumented function
*
@@ -1182,6 +1211,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arrayFlatForKey
/**
* Undocumented function
*
@@ -1202,6 +1233,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arrayGetPrevKey, arrayGetNextKey
/**
* Undocumented function
*
@@ -1295,6 +1328,13 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arrayReturnMatchingKeyOnly
/**
* Undocumented function
*
* @return array
*/
public function providerReturnMatchingKeyOnley(): array
{
return [
@@ -1380,6 +1420,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: arrayModifyKey
/**
* provider for arrayModifyKey
*
@@ -1492,6 +1534,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: sortArray
/**
* sort
*
@@ -1711,7 +1755,9 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
}
}
/**
// MARK: ksortArray
/**
* sort
*
* @return array
@@ -1867,6 +1913,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
}
}
// MARK: findArraysMissingKey
/**
* Undocumented function
*
@@ -2034,6 +2082,8 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
);
}
// MARK: selectArrayFromOption
/**
* Undocumented function
*
@@ -2379,6 +2429,316 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
$result
);
}
// MARK: getRandomEntryFromArrayProvider
/**
* Get random entry from array provider
*
* @return array<mixed>
*/
public function getRandomEntryFromArrayProvider(): array
{
return [
'empty array' => [
[],
],
'single element array' => [
['only'],
],
'multiple elements array' => [
['first', 'second', 'third'],
],
];
}
/**
* Undocumented function
*
* @covers ::getRandomEntryFromArray
* @dataProvider getRandomEntryFromArrayProvider
* @testdox getRandomEntryFromArray get random value from array [$_dataName]
*
* @param array $input
* @return void
*/
public function testGetRandomEntryFromArray(array $input): void
{
$result = \CoreLibs\Combined\ArrayHandler::getRandomEntryFromArray($input);
if (empty($input)) {
$this->assertNull($result);
} else {
$this->assertContains($result, $input);
}
}
// MARK: removeArrayEntryByValue
/**
* Remove array entry by value provider
*
* @return array<mixed>
*/
public function removeArrayEntryByValueProvider(): array
{
return [
'empty array' => [
[],
'',
null,
[],
],
'single element array' => [
['only'],
'only',
null,
[]
],
'single element array, not found' => [
['only'],
'foo',
null,
['only']
],
'multiple elements array' => [
['first', 'second', 'third'],
'second',
null,
['first', 'third'],
],
'array with multiple identical elements' => [
['first', 'second', 'first', 'third'],
'first',
null,
['second', 'third'],
],
'array with multiple identical elements, other remove' => [
['first', 'second', 'first', 'third'],
'second',
null,
['first', 'first', 'third'],
],
'array with key value entries' => [
[
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3',
],
'value2',
null,
[
'key1' => 'value1',
'key3' => 'value3',
]
],
'nested array, array match' => [
[
['first', 'second'],
['third', 'fourth'],
],
['third', 'fourth'],
null,
[
['first', 'second'],
],
],
'strict test, off' => [
['3', 3,],
'3',
null,
[],
],
'strict test, on' => [
['3', 3,],
'3',
true,
[3,],
],
'strict test bool, off' => [
['false', false, 0],
false,
null,
['false'],
],
'strict test bool, on' => [
['false', false, 0],
false,
true,
['false', 0],
],
'strict test float, off' => [
['3.14', 3.14],
3.14,
null,
[],
],
'strict test float, on' => [
['3.14', 3.14],
3.14,
true,
['3.14'],
],
'stric test float and int, off' => [
['1.0', '1', 1.0, 1],
1,
null,
[],
],
'stric test float and int, on' => [
['1.0', '1', 1.0, 1],
1,
true,
['1.0', '1', 1.0],
],
];
}
/**
* Test for removeArrayEntryByValue function
*
* @covers ::removeArrayEntryByValue
* @dataProvider removeArrayEntryByValueProvider
* @testdox removeArrayEntryByValue Remove $value from array $input, with $strict [$_dataName]
*
* @param array $input
* @param string|int|float|bool|array $value
* @param bool|null $strict
* @param array $expected
* @return void
*/
public function testRemoveArrayEntryByValue(
array $input,
string|int|float|bool|array $value,
?bool $strict,
array $expected
): void {
if ($strict !== null) {
$result = \CoreLibs\Combined\ArrayHandler::removeArrayEntryByValue($input, $value, $strict);
} else {
$result = \CoreLibs\Combined\ArrayHandler::removeArrayEntryByValue($input, $value);
}
$this->assertEquals(array_values($expected), array_values($result));
}
// MARK: addStringToEachValueInArray
/**
* Data provider for addStringToEachValueInArray tests.
*
* @return array
*/
public function addStringToEachValueInArrayProvider(): array
{
return [
'empty array' => [
[],
'string',
null,
[],
],
'empty string to add' => [
['a', 'b'],
'',
null,
['a', 'b'],
],
'prefix true' => [
['a', 'b'],
'pre_',
true,
['pre_a', 'pre_b'],
],
'prefix false' => [
['a', 'b'],
'_suf',
false,
['a_suf', 'b_suf'],
],
'mixed values' => [
['a', 'b', 'c', 5, 6],
'X',
true,
['Xa', 'Xb', 'Xc', 'X5', 'X6'],
]
];
}
/**
* Test for addStringToEachValueInArray function
*
* @covers ::addStringToEachValueInArray
* @dataProvider addStringToEachValueInArrayProvider
* @testdox addStringToEachValueInArray Add $string_to_add to each value in $array, with $prefix [$_dataName]
*
* @param array $array
* @param string $string_to_add
* @param bool|null $prefix
* @param array|null $expected
* @return void
*/
public function testAddStringToEachValueInArray(
array $array,
string $string_to_add,
?bool $prefix,
?array $expected
) {
if ($prefix == null) {
$result = \CoreLibs\Combined\ArrayHandler::addStringToEachValueInArray($array, $string_to_add);
} else {
$result = \CoreLibs\Combined\ArrayHandler::addStringToEachValueInArray($array, $string_to_add, $prefix);
}
$this->assertEquals($expected, $result);
}
// MARK: createSortedArrayByKey
/**
* Data provider for createSortedArrayByKey tests.
*
* @return array
*/
public function createSortedArrayByKeyProvider(): array
{
return [
'empty' => [
[],
[],
],
'flat array' => [
['b' => 2, 'a' => 1, 'c' => 3],
['a' => 1, 'b' => 2, 'c' => 3],
],
'nested array' => [
['b' => 2, 'a' => 1, 'c' => ['d' => 4, 'b' => 2]],
['a' => 1, 'b' => 2, 'c' => ['b' => 2, 'd' => 4]],
],
'deeply nested array' => [
['b' => 2, 'a' => 1, 'c' => ['d' => 4, 'b' => 2, 'e' => ['g' => 7, 'f' => 6]]],
['a' => 1, 'b' => 2, 'c' => ['b' => 2, 'd' => 4, 'e' => ['f' => 6, 'g' => 7]]],
],
'mixed key type' => [
['b' => 2, 1 => 'one', 'a' => 1],
[1 => 'one', 'a' => 1, 'b' => 2],
],
];
}
/**
* Test for createSortedArrayByKey function
*
* @covers ::createSortedArrayByKey
* @dataProvider createSortedArrayByKeyProvider
* @testdox createSortedArrayByKey Sort the array by keys recursively [$_dataName]
*
* @param array $input
* @param array $expected
* @return void
*/
public function testCreateSortedArrayByKey(array $input, array $expected): void
{
$result = \CoreLibs\Combined\ArrayHandler::createSortedArrayByKey($input);
$this->assertEquals($expected, $result);
}
}
// __END__
+8
View File
@@ -124,3 +124,11 @@ The development for those files is located in a different repository
General: <https://[service]/CodeBlocks/JavaScript.utils>
Org: <https://[serverice]/[org]/Code-Blocks.JavaScript.utils>
### Update NPM packages
```sh
npm-check-updates
ncu -u
npm install
```
+4
View File
@@ -18,6 +18,10 @@ export default [
globals: {
...globals.browser,
...globals.jquery
},
parserOptions: {
ecmaVersion: 2022,
sourceType: "script",
}
}},
pluginJs.configs.recommended,
+4 -4
View File
@@ -9,9 +9,9 @@
"license": "",
"description": "Core Libraries",
"devDependencies": {
"@eslint/js": "^9.20.0",
"esbuild": "^0.25.0",
"eslint": "^9.20.1",
"globals": "^15.15.0"
"@eslint/js": "^10.0.1",
"esbuild": "^0.28.1",
"eslint": "^10.5.0",
"globals": "^17.7.0"
}
}
+1 -1
View File
@@ -15,7 +15,7 @@
]
},
"repositories": {
"git.egplusww.jp.Composer": {
"packages.omnicomproduction.jp.Composer": {
"type": "composer",
"url": "https://packages.omnicomproduction.jp/api/packages/Composer/composer"
}
+1 -1
View File
@@ -60,7 +60,7 @@ class File
* @param string $read_file File to read, relative or absolute path
* @return string mime type
* @throws \UnexpectedValueException if file cannot be read or is not a file
* @throws \RangeException if we cannot get a mime type and throw exception is on
* @throws \RangeException if we cannot get a mime type
*/
public static function getMimeType(string $read_file): string
{
+88 -2
View File
@@ -475,8 +475,7 @@ class ArrayHandler
throw new \ArgumentCountError(__FUNCTION__ . ' needs two or more array arguments');
}
$merged = [];
while ($in_arrays) {
$in_array = array_shift($in_arrays);
foreach ($in_arrays as $in_array) {
if (!is_array($in_array)) {
throw new \TypeError(__FUNCTION__ . ' encountered a non array argument');
}
@@ -811,6 +810,93 @@ class ArrayHandler
);
return $in_array;
}
/**
* return one random entry from an array (value)
* the return entry is null if the incoming array is empty
* the array can also be an array of arrays
*
* @param array<mixed> $array
* @return string|int|float|bool|array<mixed>|null
*/
public static function getRandomEntryFromArray(array $array): string|int|float|bool|array|null
{
if (empty($array)) {
return null;
}
$random_index = array_rand($array);
return $array[$random_index];
}
/**
* find and remove one value
* on default does not strict compare
*
* @param array<mixed> $array
* @param string|int|float|bool|array<mixed> $value
* @param bool $strict [false]
* @return array<mixed>
*/
public static function removeArrayEntryByValue(
array $array,
string|int|float|bool|array $value,
bool $strict = false,
): array {
if (empty($array)) {
return $array;
}
return array_filter($array, function ($element) use ($value, $strict) {
return $strict ?
$element !== $value :
$element != $value;
});
}
/**
* add a string to each element in an array, default is at the end of the value,
* can be switched with the prefix flag
*
* @param array<string> $array
* @param string $string_to_add
* @param bool $prefix [false]
* @return array<string>
*/
public static function addStringToEachValueInArray(array $array, string $string_to_add, bool $prefix = false): array
{
// nothing set, skip
if (empty($string_to_add) || empty($array)) {
return $array;
}
return array_map(function ($value) use ($string_to_add, $prefix) {
return $prefix ?
$string_to_add . $value :
$value . $string_to_add;
}, $array);
}
/**
* sort by key any array, even if it is nested
*
* @param array<mixed> $data
* @return array<mixed>
*/
public static function createSortedArrayByKey(array $data): array
{
if (empty($data)) {
return $data;
}
// Sort by keys
ksort($data);
// Recursively sort nested arrays
foreach ($data as $key => $value) {
if (is_array($value)) {
$data[$key] = self::createSortedArrayByKey($value);
}
}
return $data;
}
}
// __END__
+5 -5
View File
@@ -154,11 +154,11 @@ class RandomKey
* if override key length is set, it will check on valid key and use this
* this will not set the class key length variable
*
* @param int $key_length [default=-1] key length override,
* if not set use default [LEGACY]
* @param array<string> $key_range a list of key ranges as array,
* if not set use previous set data
* @return string random key
* @param int $key_length [default=-1] key length override,
* if not set use default [LEGACY]
* @param array<string> ...$key_range a list of key ranges as array,
* if not set use previous set data
* @return string random key
*/
public static function randomKeyGen(
int $key_length = self::KEY_LENGTH_DEFAULT,
@@ -290,7 +290,7 @@ class ConvertPlaceholder
}
$match = $matches[self::MATCHING_POS];
// only count pos up for actual replacements we will do
if (!empty($match)) {
if (strlen((string)$match) > 0) {
$pos++;
$params_lookup[] = '$' . $pos;
}