From my experiences with high-order functions in Rust, I'd like the following methods to generate composer.json blocks in T1680 from packages metadata.
We've some metadata we convert into PHP arrays (packages as a vector, packages_namespaces as a hashmap):
packages: - commands - database - omnitools - report packages_namespaces: commands: Keruald\Commands database: Keruald\Database omnitools: Keruald\OmniTools report: Keruald\Reporting
Map key and values
The map method doesn't allow to map values into keys. A mapValuesAndKeys method would allow to build arrays like:
{ "replace": { "keruald/commands": "self.version", "keruald/database": "self.version", "keruald/omnitools": "self.version", "keruald/report": "self.version" }, ... }
Note the values from packages become here keys.
We can accept two callbacks arguments formats, so we can use ($value) for vectors and ($key, $value) for hashmaps.
Both will return an array with two elements [key, value].
So we can do:
function getReplace(array $packages) : array { return HashMap::from($packages) ->mapValuesAndKeys(fn($v) => ["keruald/$v", "self.version"]) ->toArray(); }
Flatmap
Here, we need to add two elements for each value of package_namespaces, one for tests, one for src:
{ "autoload": { "psr-4": { "Keruald\\Commands\\": "commands/src/", "Keruald\\Commands\\Tests\\": "commands/tests/", "Keruald\\Database\\": "database/src/", "Keruald\\Database\\Tests\\": "database/tests/", "Keruald\\OmniTools\\": "omnitools/src/", "Keruald\\OmniTools\\Tests\\": "omnitools/tests/", "Keruald\\Reporting\\": "report/src/", "Keruald\\Reporting\\Tests\\": "report/tests/" } }, ... }
A regular map function will work, with a flat map variant.
The concept of the flat map is we return an iterable, and the key/values are added to the mapped hashmap:
function getAutoload(array $packages_namespaces) : array { return [ "psr-4" => HashMap::from($packages_namespaces) ->flatMap(fn($package, $ns) => [ $ns . '\\' => $package . "/src/", $ns . '\\Tests\\' => $package . "/tests/", ]) ->toArray() ]; }