Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 30 Oct 2026. What's built · Install 0.1.0
jadpo
Reference: Standard library

Standard library

Software types

On this page

The software types are the values tools and build systems pass around: version numbers and ranges, git refs, package and container names, licences, trace ids, file names and paths. Each follows its standard, as the web types do.

Here a shop's plugin registry reads the version a release form names, offers a release only to the shops whose range it fits, and tells a newer release from an older one by SemVer's rules, not by its text:

example
type FormText = Text {}type YesNo = Bool {}type NotAVersion = Failure {    kind: FailureKind.invalid_value}/// The version a plugin's release form names.function plugin_version(raw: FormText) fails NotAVersion -> SemanticVersion {    var typed_version: SemanticVersion = attempt text.parse(raw, as: SemanticVersion) {        malformed: NotAVersion    }    return typed_version}/// Whether a plugin's release fits the range a shop asks for.function fits_shop(plugin_release: SemanticVersion, shop_wants: VersionRange) -> YesNo {    return YesNo(semver.satisfies(plugin_release, shop_wants))}/// Whether an offered release is newer than the one installed.function newer_than(installed_release: SemanticVersion, offered_release: SemanticVersion) -> YesNo {    return YesNo(offered_release > installed_release)}/// Whether a release is offered to every shop: it has no pre-release.function generally_available(plugin_release: SemanticVersion) -> YesNo {    return YesNo(plugin_release.pre_release == none)}/// A release's version as its tag writes it.function release_tag(plugin_release: SemanticVersion) -> FormText {    return FormText(text.from(plugin_release))}
example
test "versions follow SemVer's precedence, not their text" {    var nine: SemanticVersion = attempt plugin_version("1.9.0")    var ten: SemanticVersion = attempt plugin_version("1.10.0")    var release_candidate: SemanticVersion = attempt plugin_version("1.10.0-rc.1")    assert newer_than(nine, ten)    assert newer_than(release_candidate, ten)    assert not generally_available(release_candidate)    assert release_tag(release_candidate) == "1.10.0-rc.1"    assert plugin_version("v1.10.0") fails NotAVersion}test "a range takes a pre-release only where it names one" {    var patch_release: SemanticVersion = attempt plugin_version("1.4.2")    var beta_release: SemanticVersion = attempt plugin_version("2.0.0-beta.1")    assert fits_shop(patch_release, "^1.2.3")    assert not fits_shop(patch_release, "~1.2.3")    assert not fits_shop(beta_release, "^1.2.3")    assert not fits_shop(beta_release, ">=1.0.0")    assert fits_shop(beta_release, ">=2.0.0-beta.0 <3.0.0")}

Which standard each type follows

Type Standard
SemanticVersion SemVer 2.0.0, 1.2.3-alpha.1+build.5
VersionRange npm's range grammar, written one way: ^1.2.3, >=1.0.0 <2.0.0, 1.2.x || >=2.5.0-beta.1
GitRef what git check-ref-format accepts
PackageUrl ECMA-427's canonical pkg: URL
Cve the CVE programme's id
SpdxLicence an SPDX expression over the SPDX licence list
TraceId, SpanId, TraceParent W3C Trace Context
LogLevel OpenTelemetry's six severities
FileName, FilePath names and paths every common file system takes, written with /
RegularExpression a pattern that pattern:'s linear-time engine takes
ContainerImage the OCI distribution reference, with its registry and a tag or a digest
Digest the OCI image specification
Ulid the ULID specification's 26 characters
IdempotencyKey what the Idempotency-Key header carries
Doi the DOI Handbook's name

None of them is personal data. type.standard_exists matches none of them, so your own { major, minor, patch } type stays your own for now: adding a shape later would report every such type at once.

Versions

A SemanticVersion is an object of major, minor and patch, each a whole number from 0 up, and pre_release and build, each text or none. So code reads its parts: release.pre_release == none.

Its canonical text has no v before it, and a number too large for an Int is malformed. It is sent as that text and shown as its text. It is stored as a column per part: bigint for the numbers, and text or NULL for the rest.

< is SemVer 2.0.0's precedence (§11), so 1.10.0 comes after 1.9.0 and every pre-release comes before its release:

  • the numbers compare numerically;
  • a pre-release is below its release;
  • pre-release identifiers compare numerically when they are numbers and in ASCII order when they aren't, numbers first.

Build metadata is ignored, as §10 says, so neither of 1.0.0+a and 1.0.0+b is below the other. They still aren't equal, because == compares every part. Sorting and a set's order go by precedence, then by build metadata as text, so they stay total and agree with ==.

A query can't order by a version, because its columns don't sort by precedence.

Version ranges

A VersionRange is the range a package asks for, in npm's range grammar (node-semver's), because SemVer defines none. It is one or more sets joined by ||. Each set is made of comparisons (<, <=, >, >=), ~, ^, partial versions (1.2, 1.2.x) and hyphen ranges (1.0.0 - 1.4.2), with * for any version.

A range is read in one spelling only:

  • no v or = before a version;
  • no space after an operator, and one space between comparisons;
  • the wildcard x inside a version, and * only on its own;
  • no build metadata, which a range can't use.

Each form means what node-semver expands it to: ^0.2.3 is >=0.2.3 <0.3.0-0. A range is held as its text, so two spellings of one set, such as 1.2 and 1.2.x, are different values.

semver.satisfies(version, range) says whether a version is inside a range, and never fails. It keeps node-semver's rule for pre-releases, which Cargo shares: a version with a pre-release is inside a range only where a comparison in the same set names a pre-release of the same major, minor and patch. So ^1.2.3 never takes 2.0.0-beta.1, and * takes no pre-release.

Types held as text

The other software types are held as text:

  • A GitRef is any name git check-ref-format --allow-onelevel accepts: a branch (main), a tag, a full ref (refs/heads/main) or a commit's full hash. It isn't normalised with --normalize, so a leading / or a // is refused. Its length isn't limited, as git's isn't.
  • A PackageUrl is ECMA-427's canonical form: pkg: with no //, a lower-case type, and each component percent-encoded only where §5.4 says, in upper-case hex, with none of A-Z a-z 0-9 . - _ ~ : encoded. Qualifier keys are lower case, sorted, and each appears once with a value. A subpath has no ., .. or empty segment. A registered type's own rules, such as npm's lower-case names or PyPI's normalisation, aren't checked; checking them would refuse more, never accept more.
  • A Cve is CVE-, a year from 1999, a - and a sequence number of four digits, or of five to nineteen digits with no leading zero, in upper case. That is the CVE programme's 2014 syntax, with its JSON schema's limit of nineteen digits.
  • A SpdxLicence is an SPDX 2.3 expression (Annex D) over the SPDX License List 3.29.0, bundled by Embark's spdx crate 0.13.6 (CC0 data, Apache-2.0 code). It holds each identifier as the list spells it, deprecated ones included since they still name a licence; +; WITH an exception on the list; AND, OR and parentheses; and LicenseRef- and DocumentRef- references. Operators are upper case, words are one space apart, and parentheses have no space inside. NONE and NOASSERTION are values a document uses, not expressions, and are refused.
  • A TraceId and a SpanId are W3C Trace Context's ids, in lower-case hexadecimal, never all zeros.
  • A TraceParent, the header that carries a trace from one service to the next, is text, as Cidr is, because no operation reads its parts. Only version 00 is read: it is the one version defined, and its length is fixed. Its flags are any two hex digits.
  • A FileName is a name every common file system takes:
    • 1 to 255 bytes of UTF-8;
    • no /, \, NUL or other control character, and none of Windows' < > : " | ? *;
    • not . or .., and no space or dot at the end, which Windows drops;
    • not a Windows device name (CON, PRN, AUX, NUL, COM0 to COM9, LPT0 to LPT9, with ¹²³), in any case and with any extension, so nul.txt is refused.
  • A FilePath is written with /, as POSIX systems and URLs write one, so a Windows path such as C:\Users is refused. It is / alone, or names joined by /, absolute after a leading /, each a FileName. It is in its shortest form: no . segment, .. only at the start of a relative path, no empty segment, and no / at the end. It is at most 4096 bytes, Linux's PATH_MAX. It says nothing about where files are kept: the file stores never make a key from a name.
  • A RegularExpression is a pattern that a type's pattern: takes (Constraints), compiled by jadpo_std::compile_pattern with the regex crate. So backreferences and lookaround are refused, as they are there. It is matched against the whole text, and it isn't empty.
  • A ContainerImage is an OCI distribution reference, written in full: a registry first (a domain in lower case with a . or a port, an IP address, or localhost), then the repository's components in lower case, then a tag, a digest or both. So nginx:1.27, Docker Hub's short form of docker.io/library/nginx:1.27, is refused, and so is a reference with neither a tag nor a digest (an implied latest). Each image has one text.
  • A Digest follows the OCI image specification's grammar. Its registered algorithms are held to their own forms: sha256 and blake3 are 64 lower-case hex digits, sha512 128. An unregistered algorithm passes when it meets the grammar, as the specification asks.
  • A Ulid is in upper case only, its first character at most 7. It isn't ordered, as no type held as text is.
  • An IdempotencyKey, the key a client sends so that a repeated request isn't carried out twice, is 1 to 255 printable ASCII characters with no " or \ and no space at either end. That lets a structured header field carry it unescaped. The draft standard recommends a UUID but doesn't require one.
  • A Doi is 10., a registrant code of four to nine digits with any subdivisions, /, and a suffix of printable characters, its ASCII letters in lower case because the DOI Handbook compares them ignoring case. doi: and resolver URLs are refused.

Log levels

A LogLevel is an enum of OpenTelemetry's six severities: trace, debug, info, warn, error and fatal. All six are there, so a later addition doesn't break a match. Its codes are their short names, such as INFO, read ignoring case, and it is stored by its code, as HttpMethod is.

A LogLevel isn't ordered, because no enum is yet. So when Telemetry keeps "logs from LogLevel.warn", the runtime reads that order itself.

Markdown for agents: /docs/software-types.md.Built from Jadpo main at a707efb.