txt: ## dist_zef-lizmat-Ecosystem.md
  [![Actions Status](https://github.com/lizmat/Ecosystem/actions/workflows/linux.yml/badge.svg)](https://github.com/lizmat/Ecosystem/actions) [![Actions Status](https://github.com/lizmat/Ecosystem/actions/workflows/macos.yml/badge.svg)](https://github.com/lizmat/Ecosystem/actions) [![Actions Status](https://github.com/lizmat/Ecosystem/actions/workflows/windows.yml/badge.svg)](https://github.com/lizmat/Ecosystem/actions)
  
  # NAME
  
  Ecosystem - Accessing a Raku Ecosystem Storage
  
  # SYNOPSIS
  
  ```
  use Ecosystem;
  
  my $eco = Ecosystem.new;  # access the REA ecosystem
  
  say "Ecosystem has $eco.identities.elems() identities:";
  .say for $eco.identities.keys.sort;
  
  ```
  
  # DESCRIPTION
  
  Ecosystem provides the basic logic to accessing a Raku Ecosystem, defaulting to the Raku Ecosystem Archive, a place where (almost) every distribution ever available in the Raku Ecosystem, can be obtained even after it has been removed (specifically in the case of the old ecosystem master list and the distributions kept on CPAN).
  
  # COMMAND LINE INTERFACE
  
  An `ecosystems` interactive interface is provided by the [App::Ecosystems](https://raku.land/zef:lizmat/App::Ecosystems) distribution.
  
  # CONSTRUCTOR ARGUMENTS
  
  ## ecosystem
  
  ```
  my $eco = Ecosystem.new(:ecosystem<fez>);
  
  ```
  
  The `ecosystem` named argument is string that indicates which ecosystem (content-storage) should be used: it basically is a preset for the `meta-url` and `IO` arguments. The following names are recognized:
  
  * p6c the original content storage / ecosystem
  * cpan the content storage that uses CPAN
  * fez the zef (fez) ecosystem
  * rea the Raku Ecosystem Archive (default)
  
  If this argument is not specified, then at least the `IO` named argument must be specified.
  
  ## IO
  
  ```
  my $eco = Ecosystem.new(IO => "path".IO);
  
  ```
  
  The `IO` named argument specifies the path of the file that contains / will contain the META information. If not specified, will default to whatever can be determined from the other arguments.
  
  ## meta-url
  
  ```
  my $eco = Ecosystem.new(meta-url => "https://foo.bar/META.json");
  
  ```
  
  The `meta-url` named argument specifies the URL that should be used to obtain the META information if it is not available locally yet, or if it has been determined to be stale. Will default to whatever can be determined from the other arguments. If specified, then the `IO` arguments **must** also be specified to store the meta information in.
  
  ## stale-period
  
  ```
  my $eco = Ecosystem.new(stale-period => 3600);
  
  ```
  
  The `stale-period` named argument specifies the number of seconds after which the meta information is considered to be stale and needs updating using the `meta-url`. Defaults to `86400`, aka 1 day.
  
  ## longname
  
  ```
  my $eco = Ecosystem.new(longname => 'My very own ecosystem storage';
  
  ```
  
  The long name with which the ecosystem is to be known. Defaults to sensible name for the 4 original ecosystems: p6c cpan fez rea.
  
  # CLASS METHODS
  
  ## dependencies-from-meta
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.dependencies-from-meta(from-json $io.slurp);
  
  ```
  
  The `dependencies-from-meta` class method returns the list of `use-targets` as specified in the `depends` field of the given hash with meta information.
  
  ## sort-identities
  
  ```
  .say for Ecosystem.sort-identities(@identities);
  
  ```
  
  The `sort-identities` class method sorts the given identities with the highest version first, and then by the `short-name` of the identity.
  
  # INSTANCE METHODS
  
  ## authors
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.authors{ / eigenstates / }
  
  ```
  
  The `authors` instance method returns a [Map::Match](https://raku.land/zef:lizmat/Map::Match) with the authors found in each distribution as the keys, and all of the identities each author was found in as the value.
  
  ## dependencies
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.dependencies("Ecosystem");
  
  ```
  
  The `dependencies` instance method returns a sorted list of all `use-target`s (either directly or recursively) for an `identity`, `use-target` or `distro-name`.
  
  ## distro-names
  
  ```
  my $eco = Ecosystem.new;
  say "Found $eco.distro-names.elems() differently named distributions";
  
  ```
  
  The `distro-names` instance method returns a `Map` keyed on distribution name, with a sorted list of the identities that have that distribution name (sorted by short-name, latest version first).
  
  ## distros-of-use-target
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.distros-of-use-target($target);
  
  ```
  
  The `distro-of-use-target` instance method the names of the distributions that provide the given use target.
  
  ## ecosystem
  
  ```
  my $eco = Ecosystem.new;
  say "The ecosystem is $_" with $eco.ecosystem;
  
  ```
  
  The `ecosystem` instance method returns the value (implicitely) specified with the `:ecosystem` named argument.
  
  ## find-distro-names
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.find-distro-names: / JSON /;
  
  .say for $eco.find-distro-names: :auth<zef:lizmat>;
  
  ```
  
  The `find-distro-names` instance method returns the distribution names that match the optional given string or regular expression, potentially filtered by a `:ver`, `:auth`, `:api` and/or `:from` value.
  
  ## find-identities
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.find-identities: / Utils /, :ver<0.0.3+>, :auth<zef:lizmat>;
  
  .say for $eco.find-identities: :auth<zef:lizmat>, :all;
  
  .say for $eco.find-identities: :latest;
  
  ```
  
  The `find-identities` method returns identities (sorted by short-name, latest version first) that match the optional given string or regular expression, potentially filtered by `:ver`, `:auth`, `:api` and/or `:from` value.
  
  The specified string is looked up / regular expression is matched in the distribution names, the use-targets and the descriptions of the distributions.
  
  By default, only the identity with the highest `:ver` value will be returned: a `:all` flag can be specified to return **all** possible identities.
  
  The `:latest` flag can be specified to apply heuristics on the identities so that only the most recent version of a distribution across ecosystems and authorities will be returned. This will e.g. return only `AccountableBagHash:ver<0.0.6>:auth<zef:lizmat>` from a list with:
  
  ```
  AccountableBagHash:ver<0.0.3>:auth<cpan:ELIZABETH>
  AccountableBagHash:ver<0.0.6>:auth<zef:lizmat>
  
  ```
  
  ## find-no-tags
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.find-no-tags;
  
  .say for $eco.find-no-tags: / zef /;
  
  .say for $eco.find-no-tags: / zef / :all;
  
  ```
  
  The `find-no-tags` method returns identities (sorted by short-name, latest version first) that match the optional given string or regular expression (potentially filtered by `:ver`, `:auth`, `:api` and/or `:from` value) that do **not** have any tags specified.
  
  The specified string is looked up / regular expression is matched in the distribution names, the use-targets and the descriptions of the distributions.
  
  By default, only the identity with the highest `:ver` value will be returned: a `:all` flag can be specified to return **all** possible identities that do **not** have tags.
  
  ## find-use-targets
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.find-use-targets: / JSON /;
  
  .say for $eco.find-use-targets: :auth<zef:lizmat>;
  
  ```
  
  The `find-use-targets` instance method returns the strings that can be used in a `use` command that match the optional given string or regular expression, potentially filtered by a `:ver`, `:auth`, `:api` and/or `:from` value.
  
  ## identities
  
  ```
  my $eco = Ecosystem.new;
  my %identities := $eco.identities;
  say "Found %identities.elems() identities";
  
  ```
  
  The `identities` instance method returns a `Map` keyed on identity string, with a `Map` of the META information of that identity as the value.
  
  ## identity-dependencies
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.identity-dependencies($identity);
  
  .say for $eco.identity-dependencies($identity, :all);
  
  ```
  
  The `identity-dependencies` instance method returns a sorted list of the dependencies of the given **identity** string, if any. Takes an optional `:all` named to also return any dependencies of the initial dependencies, recursively.
  
  ## identity-release-Date
  
  ```
  my $eco = Ecosystem.new;
  say $eco.identity-release-Date($identity);
  
  ```
  
  The `identity-release-Date` instance method returns the `Date` when the the distribution of the given identity string was released, or `Nil` if either the identity could not be found, or if there is no release date information available.
  
  ## identity-release-yyyy-mm-dd
  
  ```
  my $eco = Ecosystem.new;
  say $eco.identity-release-yyyy-mm-dd($identity);
  
  ```
  
  The `identity-release-yyyy-mm-dd` instance method returns a `Str` in YYYY-MM-DD format of when the the distribution of the given identity string was released, or `Nil` if either the identity could not be found, or if there is no release date information available.
  
  ## identity-url
  
  ```
  my $eco = Ecosystem.new;
  say $eco.identity-url($identity);
  
  ```
  
  The `identity-url` instance method returns the `URL` of the distribution file associated with the given identity string, or `Nil`.
  
  ## IO
  
  ```
  my $eco = Ecosystem.new(:IO("foobar.json").IO);
  say $eco.IO;  # "foobar.json".IO
  
  ```
  
  The `IO` instance method returns the `IO::Path` object of the file where the local copy of the META data lives.
  
  ## least-recent-release
  
  ```
  my $eco = Ecosystem.new;
  say $eco.least-recent-release;
  
  ```
  
  The `least-recent-release` instancemethod returns the `Date` of the least recent release in the ecosystem, if any.
  
  ## longname
  
  ```
  my $eco = Ecosystem.new;
  say $eco.longname;  # Raku Ecosystem Archive
  
  ```
  
  Return the long name of the ecosystem.
  
  ## matches
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.matches{ / Utils / }
  
  ```
  
  The `matches` instance method returns a [Map::Match](https://raku.land/zef:lizmat/Map::Match) with the string that caused addition of an identity as the key, and a sorted list of the identities that either matched the distribution name or the description (sorted by short-name, latest version first). It is basically the workhorse of the [find-identities](#find-identities) method.
  
  ## meta
  
  ```
  my $eco = Ecosystem.new;
  say $eco.meta;  # ...
  
  ```
  
  The `meta` instance method returns the JSON representation of the META data.
  
  ## meta-url
  
  ```
  my $eco = Ecosystem.new(:ecosystem<fez>);
  say $eco.meta-url;  # https://360.zef.pm/
  
  ```
  
  The `meta-url` instance method returns the URL that is used to fetch the META data, if any.
  
  ## most-recent-release
  
  ```
  my $eco = Ecosystem.new;
  say $eco.most-recent-release;
  
  ```
  
  The `most-recent-release` instance method returns the `Date` of the most recent release in the ecosystem, if any.
  
  ## resolve
  
  ```
  my $eco = Ecosystem.new;
  say $eco.resolve("eigenstates");  # eigenstates:ver<0.0.9>:auth<zef:lizmat>
  
  ```
  
  The `resolve` instance method attempts to resolve the given string and the given `:ver`, `:auth`, `:api` and `:from` named arguments to the identity that would be assumed when specified with e.g. `dependencies`.
  
  ## reverse-dependencies
  
  ```
  my $eco = Ecosystem.new;
  my %reverse-dependencies := $eco.reverse-dependencies;
  say "Found %reverse-dependencies.elems() reverse dependencies";
  
  ```
  
  The `reverse-dependencies` instance method returns a `Map` keyed on resolved dependencies, with a list of identities that depend on it.
  
  ## reverse-dependencies-for-short-name
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.reverse-dependencies-for-short-name("File::Temp");
  
  ```
  
  The `reverse-dependencies-for-short-name` instance method returns a unique list of short-names of identities that depend on any version of the given short-name.
  
  ## river
  
  ```
  my $eco = Ecosystem.new;
  say "Top five modules on the Raku Ecosystem River:";
  .say for $eco.river.sort(-*.value.elems).map(*.key).head(5);
  
  ```
  
  The `river` instance method returns a `Map` keyed on short-name of an identity, with as value a list of short-names of identities that depend on it **without** having pinned `:ver` and `:auth` in their dependency specification.
  
  ## stale-period
  
  ```
  my $eco = Ecosystem.new;
  say $eco.stale-period;  # 86400
  
  ```
  
  The `stale-period` instance method returns the number of seconds after which any locally stored META information is considered to be stale.
  
  ## release-dates
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.release-dates{ / ^2024 / }
  
  ```
  
  The `release-dates` instance method returns a [Map::Match](https://raku.land/zef:lizmat/Map::Match) with the release-dates (YYYY-MM-DD) found in each distribution as the keys, and all of the identities that were released on that date as the value.
  
  ## tags
  
  ```
  my $eco = Ecosystem.new;
  .say for $eco.tags{ / eigenstates / }
  
  ```
  
  The `tags` instance method returns a [Map::Match](https://raku.land/zef:lizmat/Map::Match) with the tags found in each distribution as the keys, and all of the identities each tag was found in as the value.
  
  ## update
  
  ```
  my $eco = Ecosystem.new;
  $eco.update;
  
  ```
  
  The `update` instance method re-fetches the META information from the `meta-url` and updates it internal state in a thread-safe manner.
  
  ## unresolvable-dependencies
  
  ```
  my $eco = Ecosystem.new;
  say "Found $eco.unresolvable-dependencies.elems() unresolvable dependencies";
  
  ```
  
  The `unresolvable-dependencies` instance method returns a `Map` keyed on an unresolved dependency, and a `List` of identities that have this unresolvable dependency as the value. By default, only current (as in the most recent version) identities will be in the list. You can specify the named `:all` argument to have also have the non-current identities listed.
  
  ## unversioned-distros
  
  ```
  my $eco = Ecosystem.new;
  say "Found $eco.unversioned-distro-names.elems() unversioned distributions";
  
  ```
  
  The `unversioned-distro-names` instance method returns a sorted list of distribution names (identity without `:ver`) that do not have any release with a valid `:ver` value (typically **:ver<\*>**).
  
  ## use-targets
  
  ```
  my $eco = Ecosystem.new;
  say "Found $eco.use-targets.elems() different 'use' targets";
  
  ```
  
  The `use-targets` instance method returns a `Map` keyed on 'use' target, with a sorted list of the identities that provide that 'use' target (sorted by short-name, latest version first).
  
  # AUTHOR
  
  Elizabeth Mattijsen [liz@raku.rocks](mailto:liz@raku.rocks)
  
  Source can be located at: <https://github.com/lizmat/Ecosystem> . Comments and Pull Requests are welcome.
  
  If you like this module, or what I’m doing more generally, committing to a [small sponsorship](https://github.com/sponsors/lizmat/) would mean a great deal to me!
  
  # COPYRIGHT AND LICENSE
  
  Copyright 2022, 2024, 2025 Elizabeth Mattijsen
  
  This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.
  