API Reference
Module
The PackageURLs module provides the PURL type and related functions for working with Package URLs.
using PackageURLsTypes
PackageURLs.PURL — Type
PURLRepresents a Package URL (PURL) as specified in ECMA-427.
A PURL is a URL string used to identify and locate a software package in a mostly universal and uniform way across programming languages, package managers, and packaging conventions.
Fields
type::String: The package type or protocol (e.g., "julia", "npm", "pypi")namespace::Union{String, Nothing}: Optional namespace or organizationname::String: The package nameversion::Union{String, Nothing}: Optional package versionqualifiers::Union{Dict{String,String}, Nothing}: Optional key-value metadatasubpath::Union{String, Nothing}: Optional path within the package
Examples
# Parse from string
purl = parse(PURL, "pkg:julia/Example@1.0.0")
# Construct programmatically
purl = PURL("julia", nothing, "Example", "1.0.0", nothing, nothing)
# Use string macro
purl = purl"pkg:julia/Example@1.0.0"
# Convert to string
string(purl) # => "pkg:julia/Example@1.0.0"PackageURLs.PURLError — Type
PURLError <: ExceptionException thrown when PURL parsing or validation fails.
Fields
message::String: Human-readable error descriptionposition::Union{Int, Nothing}: Character position where error occurred (1-based)
Examples
try
parse(PURL, "invalid")
catch e::PURLError
println("Error at position $(e.position): $(e.message)")
endString Macro
PackageURLs.@purl_str — Macro
@purl_str(s)Create a PURL from a string literal with compile-time validation.
Examples
purl"pkg:julia/Example@1.0.0"
purl"pkg:npm/%40angular/core@15.0.0"Invalid PURLs will cause a compile-time error.
Bundled Artifact Paths
Functions to access the bundled purl-spec v1.0.0 artifact containing official type definitions and test fixtures.
PackageURLs.purl_spec_path — Function
purl_spec_path() -> StringReturn the path to the bundled purl-spec v1.0.0 artifact root.
This directory contains the full purl-spec repository including type definitions, test fixtures, JSON schemas, and documentation.
Example
root = purl_spec_path()
# ~/.julia/artifacts/<hash>/purl-spec-1.0.0/PackageURLs.type_definitions_path — Function
type_definitions_path() -> StringReturn the path to the bundled PURL type definitions directory.
Contains 37 official type definition JSON files (e.g., pypi-definition.json).
Example
types_dir = type_definitions_path()
# ~/.julia/artifacts/<hash>/purl-spec-1.0.0/types/PackageURLs.test_fixtures_path — Function
test_fixtures_path() -> StringReturn the path to the bundled PURL test fixtures directory.
Contains official test cases for each type (e.g., types/pypi-test.json).
Example
tests_dir = test_fixtures_path()
# ~/.julia/artifacts/<hash>/purl-spec-1.0.0/tests/Type Definitions
Types and functions for loading and registering custom type definitions from JSON.
PackageURLs.TypeDefinition — Type
TypeDefinitionRepresents a PURL type's rules loaded from JSON per ECMA-427 Section 6.
Fields
type::String: Package ecosystem identifier (e.g., "cargo", "swift")description::Union{String, Nothing}: Human-readable descriptionname_normalize::Vector{String}: Normalization operations to apply to namesrequired_qualifiers::Vector{String}: Qualifiers that must be presentknown_qualifiers::Vector{String}: Recognized qualifier keys
Supported Normalization Operations
"lowercase": Convert name to lowercase"replace_underscore": Replace_with-"replace_dot": Replace.with-"collapse_hyphens": Collapse multiple-to single-
Example
def = TypeDefinition(
"cargo",
"Rust crates from crates.io",
["lowercase"],
String[],
["arch", "os"]
)PackageURLs.JsonTypeRules — Type
JsonTypeRules <: TypeRulesType rules loaded from a JSON definition. Used by the typerules() dispatcher when a type is found in TYPEREGISTRY.
PackageURLs.load_type_definition — Function
load_type_definition(path::AbstractString) -> TypeDefinitionLoad a type definition from a JSON file per ECMA-427 Section 6 schema.
ECMA-427 Format
{
"type": "pypi",
"description": "PyPI packages",
"name_definition": {
"case_sensitive": false,
"normalization_rules": ["Replace underscore _ with dash -"]
},
"qualifiers_definition": [
{"key": "file_name", "requirement": "optional"}
]
}Normalization Derivation
name_definition.case_sensitive: false→ "lowercase" normalizationnormalization_ruleswith "underscore" AND "dash" → "replace_underscore"normalization_ruleswith "dot" AND "dash"/"hyphen" → "replace_dot"
Arguments
path: Path to the JSON file
Returns
TypeDefinition: The loaded type definition
Throws
ArgumentError: If the file does not existPURLError: If the JSON is missing required fields or has invalid values
Example
def = load_type_definition("data/type_definitions/pypi.json")
register_type_definition!(def)PackageURLs.register_type_definition! — Function
register_type_definition!(def::TypeDefinition)Register a type definition in the global registry. The type name is stored in lowercase for consistent lookup.
Registered types take priority over hardcoded type rules.
Example
def = TypeDefinition("mytype", "My custom type", ["lowercase"], String[], String[])
register_type_definition!(def)PackageURLs.list_type_definitions — Function
list_type_definitions() -> Dict{String, TypeDefinition}Return a copy of the type registry containing all registered type definitions.
Example
defs = list_type_definitions()
for (name, def) in defs
println("$name: $(def.description)")
endPackageURLs.clear_type_registry! — Function
clear_type_registry!()Remove all registered type definitions from the registry. This restores the system to use only hardcoded type rules.
Example
register_type_definition!(my_def)
# ... use custom type ...
clear_type_registry!() # Back to default rulesParsing and Serialization
The following standard Julia functions work with PURL:
parse
parse(PURL, s::AbstractString) -> PURLParse a PURL string into a PURL object. Throws PURLError if the string is not a valid PURL.
purl = parse(PURL, "pkg:npm/lodash@4.17.21")tryparse
tryparse(PURL, s::AbstractString) -> Union{PURL, Nothing}Try to parse a PURL string, returning nothing on failure instead of throwing an exception.
result = tryparse(PURL, "invalid") # nothing
result = tryparse(PURL, "pkg:npm/lodash@4.17.21") # PURLstring
string(purl::PURL) -> StringConvert a PURL back to its canonical string form.
purl = purl"pkg:npm/lodash@4.17.21"
string(purl) # "pkg:npm/lodash@4.17.21"print(io::IO, purl::PURL)Print the PURL string to an IO stream.
show
show(io::IO, purl::PURL)Display a PURL in the REPL with type information.
PURL Fields
The PURL struct has the following fields:
| Field | Type | Description |
|---|---|---|
type | String | Package ecosystem (e.g., "julia", "npm") |
namespace | Union{String, Nothing} | Organizational grouping |
name | String | Package name |
version | Union{String, Nothing} | Package version |
qualifiers | Union{Dict{String,String}, Nothing} | Key-value metadata |
subpath | Union{String, Nothing} | Path within package |
Access fields directly:
purl = parse(PURL, "pkg:maven/org.apache.commons/commons-lang3@3.12.0")
purl.type # "maven"
purl.namespace # "org.apache.commons"
purl.name # "commons-lang3"
purl.version # "3.12.0"
purl.qualifiers # nothing
purl.subpath # nothing