Zig 0.16 · v0.0.2 preview

Zig-native architecture metrics

Metrics analyze Zig declarations, source structure, and dependency coupling. They intentionally omit object-oriented measures that would turn absent Zig concepts into misleading zeros.

A compiled example

const std = @import("std");
const archunit = @import("archunit");

test "source files stay small" {
    var project = try archunit.metrics(std.testing.allocator, .{});
    defer project.deinit();
    var source = try project.inPath(&.{.{ .glob = "src/**/*.zig" }});
    defer source.deinit();
    var counts = try source.count();
    defer counts.deinit();
    var functions = try counts.functions();
    defer functions.deinit();
    var rule = try functions.shouldBeBelowOrEqual(2);
    defer rule.deinit(std.testing.allocator);
    try archunit.expectPasses(&rule, .init(.init(std.testing.allocator, std.testing.io)));
}

Compiled source: test/readme/metrics.zig

Choose files, declarations, or containers

Begin with a file scope and its normal path selectors. Project that scope to named declarations or containers when the metric should operate at Zig declaration identity. Name filters compare both simple and qualified names consistently.

Structural counts

Count declarations, functions, tests, constants, variables, fields, structs, unions, enums, opaque types, error sets, anonymous containers, imports, statements, tokens, source lines, and non-blank lines. A measurement returns owned subject/value pairs; a threshold rule returns structured metric violations.

Dependency coupling

MetricMeaning
Afferent couplingSelected incoming dependency count.
Efferent couplingSelected outgoing dependency count.
InstabilityCe / (Ca + Ce) over the selected projection.
Coupling factorObserved internal relationships relative to possible relationships.

Thresholds and predicates

Integral counts stay integers through comparison. Ratios stay finite floating-point values. The API does not implicitly mix them because conversion can change an equality boundary. Built-in threshold rules support below, above, equal, and inclusive variants; shouldSatisfy accepts a borrowed callback and returns a distinct predicate violation when it rejects a subject.

Custom metrics

A custom metric receives borrowed structural facts, or full dependency facts for a dependency projection, plus an optional caller context. It returns one tagged scalar per selected subject. Custom definitions own their name and description so diagnostic and report lifetimes do not depend on callback storage.

Owned data and offline HTML

Count, dependency, and custom builders gather MetricsReportData before rendering. Sections and entries are sorted without mutating the caller's data. The HTML renderer escapes titles and labels, neutralizes embedded-style terminators in custom CSS, uses no scripts or remote assets, and supports deterministic output without a timestamp.

Not class metrics with new names LCOM, abstractness, distance from the main sequence, zone labels, and class/interface totals are not shipped. Add a custom metric only when your repository has a precise Zig-level definition.
Next: Testing & diagnostics