=begin pod

=head1 NAME

SBOM::Raku - Raku specific SBOM functionality 

=head1 SYNOPSIS

=begin code :lang<raku>
use SBOM::Raku;

say source-sbom("META6.json").JSON;
# {
#   "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
#   "bomFormat": "CycloneDX",
#   "specVersion": "1.6",
#   "version": 1,
#   "metadata": {
#     "timestamp": "2025-07-22T18:39:29.458604+02:00",
# ...
=end code

=head1 DESCRIPTION

The C<SBOM::Raku> distribution provides logic for the creation and
maintenance of SBOM (Software Bill Of Materials) files in the Raku
Programming Language context.

=head1 SCRIPTS

=head2 source-sbom

=begin output
$ source-sbom META6.json
Created 1 source SBOM
=end output

The C<source-sbom> script expects at least one "META6.json" file to
be specified.  It will try to create source SBOM files for each of
the "META6.json" files specified in tyeir sibling directory C<.META>.
If this is a newly created file, an attempt will be made to add it
to the repository in which it is residing.

=head2 modernize-meta

=begin output
$ modernize-meta META6.json
Updated 1 META6.json file
=end output

The C<modernize-meta> script expects at least one "META6.json" file
to be specified.  It will try to update the specified file(s) to
match modern META specifications:

=item replace "depends" field with an array specification by a hash
with extended specifications.
=item remove "build-dependencies" and "test-dependencies" and put any
information in there into the "depends" hash
=item add "raku" field, take (and remove) "perl" field if there is any
=item remove "author" field: put any contents in the "authors" field
array
=item remove empty array fields
=item add "support" field hash with at least a "bugtracker" field
=item move the "source-url" field to the "support" fueld hash

=head1 SELECTIVE IMPORTING

=begin code :lang<raku>
use SBOM::Raku <component>;  # only import "component"
=end code

By default all utility functions are exported.  But you can limit this to
the functions you actually need by specifying the names in the C<use>
statement.

To prevent name collisions and/or import any subroutine with a more
memorable name, one can use the "original-name:known-as" syntax.  A
semi-colon in a specified string indicates the name by which the subroutine
is known in this distribution, followed by the name with which it will be
known in the lexical context in which the C<use> command is executed.

=begin code :lang<raku>
use SBOM::Raku <component:comp>;  # import "component" as "comp"
say comp |%args;
=end code

Apart from the subroutines provided by the C<SBOM::Raku> distribution,
it also possible to import the following subroutines from other packages,
but which are used internally by C<SBOM::Raku>:

=table
Package         | importable subroutines
----------------+-----------------------
JSON::Fast      | from-json, to-json
Identity::Utils | auth, build, meta, dependencies-from-meta, distribution-name, ecosystem, is-pinned, issue-tracker-url, raku-land-url, short-name, source-distribution-url, ver
String::Utils   | after, before, describe-Version

=head1 SUBROUTINES

=head2 authors

=begin code :lang<raku>
dd authors(from-json "META6.json".IO.slurp);
# (SBOM::Contact.new(|Map.new((:name("Jane Doe")))),)
=end code

The C<authors> subroutine returns a C<List> with C<SBOM::Contact>
objects for the authors of the JSON hash from a META6.json file.

=head2 component

=begin code :lang<raku>
say component("META6.json").JSON;
# {
#   "type": "library",
#   "mime-type": "text/plain",
# ...

my %meta-json = ...;
my $component = component(%meta-json);
=end code

The C<component> subroutine returns a
L<SBOM::Component|https://raku.land/zef:lizmat/SBOM::CycloneDX#sbomcomponent>
for the given arguments.

The arguments can be either an C<IO::Path> object (or a string that can
be coerced to an C<IO::Path>) to a file that contains Raku module meta
information (usually called C<META6.json>).  Or a hash with arguments
(in the C<META6.json> format) to build an C<SBOM::Component> object with.

=head2 component-hash

=begin code :lang<raku>
my %args := component-hash("META6.json");
# ... perform tweaks
my $component = SBOM::Component.new(|%args);
=end code

The C<component-hash> subroutine returns a hash in the format needed to
create an C<SBOM::Component> object with, from a C<META6.json> file (or
a hash of that representation).

It's main intended use is to be able to tweak the arguments prior to
making an C<SBOM::Component> object.

=head2 contact

=begin code :lang<raku>
my $contact = contact("Jane Doe");
=end code

The C<contact> subroutine creates a unique C<SBOM::Contact> object
for the given string, providing from a cache if necessary.

=head2 licenses

=begin code :lang<raku>
dd licenses(from-json "META6.json".IO.slurp);
# (SBOM::License.new(|Map.new((:license(Map.new((:id("Artistic-2.0"))))))),)
=end code

The C<licenses> subroutine returns a C<List> with C<SBOM::License>
objects for the license(s) of the JSON hash from a META6.json file.

=head2 metadata

=begin code :lang<raku>
say metadata("META6.json").JSON;
# {
#   "timestamp": "2025-07-22T18:52:04.686316+02:00",
#   "lifecycles": [
#     {
#       "phase": "build"
# ...

my %meta-json = ...;
my $metadata = metadata(%meta-json);
=end code

The C<metadata> subroutine returns a
L<SBOM::Metadata|https://raku.land/zef:lizmat/SBOM::CycloneDX#sbommetadata>
for the given arguments.

The arguments can be either an C<IO::Path> object (or a string that can
be coerced to an C<IO::Path>) to a file that contains Raku module meta
information (usually called C<META6.json>).  Or a hash with arguments
(in the C<META6.json> format) to build an C<SBOM::Metadata> object with.

=head2 metadata-hash

=begin code :lang<raku>
my %args := metadata-hash("META6.json");
# ... perform tweaks
my $metadata = SBOM::Metadata.new(|%args);
=end code

The C<metadata-hash> subroutine returns a hash in the format needed to
create an C<SBOM::Metadata> object with, from a C<META6.json> file (or
a hash of that representation).

It's main intended use is to be able to tweak the arguments prior to
making an C<SBOM::Metadata> object.

=head2 modernize-META6

=begin code :lang<raku>
modernize-META6("META6.json");  # modernize in place

modernize-META6("META6.json", "modernized.json");
=end code

Read the META information at the path by the first positional argument
and produce a modernized version at the path specified by the optional
second argument (defaults to the first argument).

Optionally takes these named arguments, each taking a C<Callable> to
be executed when certain events take place:
=table
name     | arguments
---------+----------
:changed | IO::Path of changed file
:error   | IO::Path of file with error, error message

This subroutine may have limited production value, but it's the
workhorse of the C<modernize-meta> script, so it's included here for
convenience.  For more info on the changes, see the documentation
of the script.

=head2 produce-source-sbom

=begin code :lang<raku>
produce-source-sbom("META6.json");  # written to .META/SOURCE.cdx.json

produce-source-sbom("META6.json", ".META/SOURCE.cdx.json");

sub error($io, $error) { die "$io: $error }
produce-source-sbom("META6.json", :&error);
=end code

Read the META information at the path by the first positional argument
and produce a C<source-sbom> at the path specified by the optional
second argument (defaults to ".META/SOURCE.cdx.json" in the same
directory as the path of the first arguments).

If the file didn't exist before, it will be added to the repository
if possible.

Optionally takes these named arguments, each taking a C<Callable> to
be executed when certain events take place:
=table
name     | arguments
---------+----------
:created | IO::Path of created file
:updated | IO::Path of updated file
:error   | IO::Path of file with error, error message

This subroutine may have limited production value, but it's the
workhorse of the C<source-sbom> script, so it's included here for
convenience.

=head2 Rakudo-component

=begin code :lang<raku>
my $comp = Rakudo-component;
=end code

Returns a C<SBOM::Component> object representing the version of Rakudo
is running.

=head2 source-sbom

=begin code :lang<raku>
say source-sbom("META6.json").JSON;
# {
#   "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
#   "bomFormat": "CycloneDX",
#   "specVersion": "1.6",
#   "version": 1,
#   "metadata": {
#     "timestamp": "2025-07-22T18:53:59.841267+02:00",
# ...

my %meta-json = ...;
my $sbom = source-sbom(%meta-json);
=end code

The C<source-sbom> subroutine returns a
L<SBOM::CycloneDX|https://raku.land/zef:lizmat/SBOM::CycloneDX#sbomcyclonedx>
for the given arguments.

The arguments can be either an C<IO::Path> object (or a string that can
be coerced to an C<IO::Path>) to a file that contains Raku module meta
information (usually called C<META6.json>).  Or a hash with arguments
(in the C<META6.json> format) to build an C<SBOM::CycloneDX> object with.

=head2 source-sbom-hash

=begin code :lang<raku>
my %args := source-sbom-hash("META6.json");
# ... perform tweaks
my $sbom = SBOM::CycloneDX.new(|%args);
=end code

The C<source-sbom-hash> subroutine returns a hash in the format needed to
create an C<SBOM::CycloneDX> object with, from a C<META6.json> file (or
a hash of that representation).

It's main intended use is to be able to tweak the arguments prior to
making an C<SBOM::CycloneDX> object.

=head2 tar-sbom

=begin code :lang<raku>
my $sbom = tar-sbom("releases/SBOM-Raku-0.0.1.tar.gz");
=end code

The C<tar-sbom> subroutine returns a
L<SBOM::CycloneDX|https://raku.land/zef:lizmat/SBOM::CycloneDX#sbomcyclonedx>
for the given path, which is expected to indicate a tar-file.

=head2 tar-sbom-hash

=begin code :lang<raku>
my %args := tar-sbom-hash("releases/SBOM-Raku-0.0.1.tar.gz");
# ... perform tweaks
my $sbom = SBOM::CycloneDX.new(|%args);
=end code

The C<tar-sbom-hash> subroutine returns a hash in the format needed to
create an C<SBOM::CycloneDX> object with, from a tar-file that contains
a C<META6.json> file (or a hash of that representation).  Apart from
just creating the hash, it will also add crypto hashes for the tar-file
to the component in the metadata.

It's main intended use is to be able to tweak the arguments prior to
making an C<SBOM::CycloneDX> object.

=head2 VM-component

=begin code :lang<raku>
my $comp = VM-component;
=end code

Returns a C<SBOM::Component> object representing the value of C<$*VM>
that is currently set.

=head1 AUTHOR

Elizabeth Mattijsen <liz@raku.rocks>

Source can be located at: https://github.com/lizmat/SBOM-Raku . Comments
and Pull Requests are welcome.

If you like this module, or what I’m doing more generally, committing to a
L<small sponsorship|https://github.com/sponsors/lizmat/>  would mean a great
deal to me!

=head1 COPYRIGHT AND LICENSE

Copyright 2025, 2026 Elizabeth Mattijsen

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

=end pod

# vim: expandtab shiftwidth=4
