oaspec/config
Types
Configuration for oaspec code generation.
Opaque: external callers construct via new/6 and read fields via
the accessors below. Mutators (with_mode, with_validate,
with_output, with_include) live in this module too, so every
change to a Config value goes through an explicit function.
pub opaque type Config
Errors that can occur when loading config.
pub type ConfigError {
FileNotFound(path: String)
FileReadError(path: String, detail: String)
ParseError(detail: String)
MissingField(field: String)
InvalidValue(field: String, detail: String)
}
Constructors
-
FileNotFound(path: String) -
FileReadError(path: String, detail: String) -
ParseError(detail: String) -
MissingField(field: String) -
InvalidValue(field: String, detail: String)
Generation mode.
pub type GenerateMode {
Server
Client
Both
}
Constructors
-
Server -
Client -
Both
Issue #387: subset filter for codegen. When non-empty, only
operations matching at least one of the listed tags or paths
are kept; the others are dropped before capability check, hoist,
and validate.
Path patterns may end in /** to match any path under a prefix
("/repos/**" matches /repos/foo, /repos/foo/bar, …);
otherwise the pattern is compared by exact string equality.
tags and paths combine with OR semantics — an operation is
kept if EITHER its tag list intersects Include.tags OR its path
matches one of Include.paths. With both lists empty (the
default), no filtering is applied.
pub type Include {
Include(tags: List(String), paths: List(String))
}
Constructors
-
Include(tags: List(String), paths: List(String))
Values
pub fn empty_include() -> Include
The default include filter — matches everything. Equivalent to
oaspec.yaml omitting the include: key entirely.
pub fn error_to_string(error: ConfigError) -> String
Convert config error to a human-readable string.
pub fn include_is_empty(include: Include) -> Bool
True when no filter is active (both tag and path lists empty).
pub fn load(path: String) -> Result(Config, ConfigError)
Load config from a YAML file.
Returns the single target the YAML declares. When the YAML has a
targets: array with more than one entry, this errors out with
a multi-target hint — callers that need to handle the multi-
target case must use load_all/1 instead. For ordinary
single-target configs (no targets: key, or a targets: array
with exactly one entry) the result is the same as before.
pub fn load_all(
path: String,
) -> Result(List(Config), ConfigError)
Load every target declared by an oaspec.yaml. A config without a
targets: key is treated as a single implicit target whose
fields come from the top-level package:, output:, and
include: keys (the legacy single-target shape). A config with
a targets: sequence yields one Config per element, each
carrying its own package / output_* / include while
sharing the top-level input:, mode:, and validate: values.
pub fn new(
input input: String,
output_server output_server: String,
output_client output_client: String,
package package: String,
mode mode: GenerateMode,
validate validate: Bool,
) -> Config
Construct a new Config from its six required fields. Prefer
load/1 in production code; new/6 is primarily for tests and
ad-hoc tooling that assembles a config in memory. The include
filter defaults to empty_include() (match everything); use
with_include/2 to override.
pub fn output_client(cfg: Config) -> String
Output directory for client-side generated files.
pub fn output_server(cfg: Config) -> String
Output directory for server-side generated files.
pub fn package(cfg: Config) -> String
Gleam package name (module prefix) for generated files.
pub fn parse_mode(
mode: String,
) -> Result(GenerateMode, ConfigError)
Parse a mode string into GenerateMode.
pub fn validate(cfg: Config) -> Bool
Whether guard-based runtime validation is enabled.
pub fn validate_output_dir_layout(
config: Config,
) -> Result(Nil, ConfigError)
Validate the on-disk layout implied by output.dir.
Issue #319: when output.dir is something like ./src/gen, generated
code lands at src/gen/<pkg>/types.gleam whose Gleam module path is
gen/<pkg>/types — but oaspec emits import <pkg>/types, which the
compiler can’t resolve. Catch this at config time so the user sees a
clear error instead of a wall of Unknown module ... from
gleam build.
Heuristic: in the path leading up to the package’s top-level
directory, src must either be the immediate parent (the “
src in any other position is the
foot-gun.
Nested packages (Issue #387): for a package like dco_check/github
the “package directory” is the last 2 path segments, and the rule
applies to whatever sits BEFORE that pair. So ./src/dco_check/github
has parent chain [src] (immediate parent src → ok), and
./pkg/src/foo/dco_check/github has parent chain
[pkg, src, foo] (last is foo and src appears earlier → bad).
pub fn validate_output_package_match(
config: Config,
) -> Result(Nil, ConfigError)
Validate that output directory basenames are valid Gleam module names usable as import roots.
Server output must end in <package> so generated imports such as
import <package>/types resolve. Client output may end in either
<package> (when client lives in its own project) or <package>_client
(the new default since Issue #248 — both server and client share the same
<dir> and need distinct basenames). Anything else is a misconfigured
package/output mismatch the user should be told about.
Nested packages (Issue #387): a package containing / such as
dco_check/github declares an N-segment Gleam module path. The path
tail compared against the package is N segments deep — the LAST N
segments of the output path must equal the package’s segments. The
_client suffix attaches to the LAST package segment only, matching
the single-segment behaviour (dco_check/github →
dco_check/github_client, never dco_check_client/github).
pub fn with_include(config: Config, include: Include) -> Config
Apply include-filter override (Issue #387). Useful for tests
that build a Config in memory.
pub fn with_mode(config: Config, mode: GenerateMode) -> Config
Apply CLI overrides to a config.
pub fn with_output(
config: Config,
output: option.Option(String),
) -> Config
Apply output base directory override. Derives server/client paths as
Both mode. In client-only mode the client path drops the suffix
(Issue #262) so generated import <package>/... lines resolve.
The suffix decision reads config.mode at call time, so apply
with_mode/2 before with_output/2 if both overrides are needed —
otherwise the client path will reflect the previous mode’s default.