NAME
Perl::CodeMap - Analyze Perl packages and generate interactive dependency and source maps
VERSION
Version 0.3.2.
SYNOPSIS
The command-line interface is the recommended starting point:
cpanm Perl::CodeMap
cpanm PPI
perl-codemap --root ./lib --parser ppi --output map.html
perl-codemap --help
perl-codemap --man
The module also exposes the analyzer and report generator programmatically:
use strict;
use warnings;
use Perl::CodeMap;
my $codemap = Perl::CodeMap->new(
root => './lib',
parser => 'auto',
embed_source => 1,
include_tests => 0,
);
my $analysis = $codemap->analyze;
my $html_path = $codemap->write_report(
$analysis,
output => 'map.html',
json => 'map.json',
);
printf "Mapped %d packages to %s\n", scalar @{$analysis->{pkgs}}, $html_path;
DESCRIPTION
Perl::CodeMap provides a static analyzer for Perl codebases. It discovers package declarations, subroutines, file locations, and statically identifiable local package dependencies without loading or executing the input source. Its primary output is a self-contained HTML report featuring an interactive package dependency graph, searchable symbols, and a syntax-highlighted source viewer. It can also export the analysis as JSON for later use.
This module is the library underpinning the perl-codemap command installed by the same distribution. For most users, run perl-codemap --help or perl-codemap --man; no Perl API programming is required.
The preferred analysis engine is PPI. A limited heuristic fallback parser is available when PPI is not installed. This tool does not implement Perl's runtime semantics or a complete function-level call graph.
INSTALLATION
Install the application and recommended parser from CPAN:
cpanm Perl::CodeMap
cpanm PPI
Perl 5.20 or newer is required. PPI is recommended but is not required by the distribution; parser auto falls back to lite if PPI is unavailable.
For a standalone usage example, visit the public sample.
CONSTRUCTOR
new
my $codemap = Perl::CodeMap->new(%options);
Constructs an analyzer object. The source root must exist and must be a directory. Invalid parser modes, invalid per-file size limits, or an explicit request for an unavailable PPI parser raise an exception with die.
Accepted options are:
root-
Filesystem directory to scan. Defaults to the current working directory (
.). The path is resolved to an absolute path during construction. parser-
One of
auto(default),ppi, orlite.autoselects PPI when installed, otherwiselite.ppifails if PPI cannot be loaded.liteis a heuristic parser and may miss complex Perl syntax. include_tests-
Boolean; default false. When enabled, include .t test files and common t/, xt/, test/, and tests/ directories.
embed_source-
Boolean; default true. When enabled, place decoded source-file text in the
sourcesfield of the analysis, making the offline report's source browser available. Reports may contain private information when this is enabled. max_source_bytes-
Positive integer limiting the number of bytes embedded from any one source file. Default
2_000_000. Oversized files are analyzed for symbols but not embedded insources; a warning is recorded. source_base-
Optional URL prefix used for links to hosted source files. If omitted, a GitHub source URL may be inferred from the local Git checkout's
originremote and current revision. Set it explicitly for GitLab or other hosts. name-
Optional display name for the generated report. Defaults to the basename of the resolved source root.
The constructor returns a Perl::CodeMap object. It does not scan files; call "analyze" to perform the scan.
PUBLIC METHODS
analyze
my $analysis = $codemap->analyze;
Statically reads candidate Perl files beneath the constructor's root and returns a hash reference describing packages, files, functions, dependencies, source text (when enabled), and warnings.
The analyzer recognizes .pm, .pl, .psgi, optionally .t, and extensionless files with a Perl shebang. It skips hidden directories, symlinks, and common version-control, vendor, and build directories. It creates edges only for local packages that are discoverable in the same scan.
The analysis does not modify the source tree and does not execute source files. Individual unreadable files are noted in the warnings array. Unexpected I/O or parser failures may raise an exception.
See "ANALYSIS DATA FORMAT" for the returned structure.
hydrate_sources
my $loaded = $codemap->hydrate_sources($analysis, './original-source');
Adds decoded source contents to an existing analysis hash reference, including a previously imported JSON export. The source root is the second positional argument; if omitted, the analyzer's own root is used. Paths are taken from the analysis's package/file list and interpreted relative to that directory.
The method skips missing, oversized, symlinked, or unsafe paths; it prevents source reads outside the resolved root. It modifies $analysis->{sources} in place and returns the number of files loaded. The root must exist or an exception is raised. It does not remove previously embedded source entries that are unrelated to successfully loaded files.
Be careful when using data imported from untrusted JSON: the report will also retain text already present in that JSON, including any embedded source.
write_report
my $output_path = $codemap->write_report(
$analysis,
output => 'architecture.html',
json => 'architecture.json',
);
Serializes the analysis data into a single, self-contained HTML file with embedded CSS, JavaScript, syntax highlighting, and data. The HTML report requires only a modern browser with JavaScript enabled; it does not require a web server or CDN. Optionally writes a machine-readable JSON file.
Arguments:
$analysis-
A hash reference containing at least a
pkgsarray, normally returned by "analyze" or decoded from an earlier CodeMap JSON export. output-
Optional HTML destination path. Defaults to
perl-code-map.html. json-
Optional JSON export destination path. If omitted, no separate JSON file is written.
Returns the HTML output path. Invalid data or I/O failures raise an exception. Existing output files at these paths are overwritten.
ANALYSIS DATA FORMAT
The analysis is a hash reference with the following top-level members:
format-
Numeric CodeMap data format version (currently
1). name-
Report display name.
module-
Absolute path of the scanned root. Treat this as potentially sensitive metadata if exporting analysis outside your organization.
parser-
Parser selected for the analysis:
ppiorlite. scanned_files-
Number of recognized Perl source files read for the analysis.
rev,source-
Detected Git revision and remote source prefix, or empty strings when unknown.
pkgs-
Array reference of package objects. Each package contains
path(fully qualified package name),dir,doc,imports(array of local package names), andfiles(array of file objects). Each file containspath,name,lines, andfuncs. Each function object contains the keysn(name),l(starting line),s(approximate body length),k(kind),e(public-name flag), andd(preceding documentation comment). sources-
Hash reference mapping relative file paths to source text. Populated only when source embedding is enabled and the source file does not exceed the configured limit.
warnings-
Array reference of nonfatal scan and source-embedding warnings.
This is an analysis/export structure, not a complete Perl abstract syntax tree. The current format number is intended to support versioned consumers; minor internal fields may evolve across versions. When processing imports, validate format and the expected types rather than assuming all fields are always present.
ERROR HANDLING
These public methods use die for invalid configuration, invalid report data, and unrecoverable read/write errors. Callers may wrap them in eval:
my $data = eval { $codemap->analyze };
if ($@) {
warn "Unable to analyze source: $@";
}
Per-file read failures may be returned as warnings instead of being fatal. The CLI maps failures to documented exit statuses; run perl-codemap --man for its exit-status reference.
LIMITATIONS
Dependency edges represent statically detectable local package references, not runtime method calls. Dynamic require, AUTOLOAD, monkey-patching, Moose/Moo method modifiers, Catalyst dispatch, and DBIx::Class runtime relationships are not fully modeled. Multiple package declarations per file are supported; temporary block-scoped declarations are best effort. For complicated syntax, use PPI and verify the result against the source.
SECURITY AND PRIVACY
Source embedding is enabled by default. HTML/JSON results can contain entire proprietary source files, secrets, internal names, and filesystem paths. Keep reports from private repositories private. The option embed_source => 0 excludes source text but does not remove potentially sensitive package metadata. Use a dedicated secrets scanner if you need one.
The source analyzer does not execute scanned files. It is not a security sandbox or a secrets detector.
SEE ALSO
The executable's complete manual: perldoc perl-codemap or perl-codemap --man after installation. The online Perl CodeMap user guide and source repository provide additional examples.
PPI, Pod::Usage, Perl CodeMap on MetaCPAN, Live demo.
AUTHOR
Scott Muller <scott@21h.io>
COPYRIGHT AND LICENSE
Copyright (c) 2026 Scott Muller. This program is distributed under the MIT License. See LICENSE and NOTICE.md for attribution and third-party notices.