remove redundant validations

This commit is contained in:
Emil Lerch 2026-05-19 10:02:47 -07:00
parent 7769155e76
commit 1e1e62846b
22 changed files with 30 additions and 96 deletions

View file

@ -27,10 +27,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len > 0) { if (cmd_args.len > 0) {
try cli.stderrPrint(ctx.io, "Error: 'analysis' takes no arguments\n"); try cli.stderrPrint(ctx.io, "Error: 'analysis' takes no arguments\n");

View file

@ -2280,10 +2280,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(_: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(_: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
var parsed: ParsedArgs = .{}; var parsed: ParsedArgs = .{};
var i: usize = 0; var i: usize = 0;

View file

@ -35,10 +35,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
/// Data types to show in the stats table (skip candles_meta and meta internal bookkeeping). /// Data types to show in the stats table (skip candles_meta and meta internal bookkeeping).
const display_types = [_]DataType{ const display_types = [_]DataType{
.candles_daily, .candles_daily,

View file

@ -128,10 +128,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
const io = ctx.io; const io = ctx.io;
const today = ctx.today; const today = ctx.today;

View file

@ -228,10 +228,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
const io = ctx.io; const io = ctx.io;
const today = ctx.today; const today = ctx.today;

View file

@ -27,10 +27,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len < 1) { if (cmd_args.len < 1) {
try cli.stderrPrint(ctx.io, "Error: 'divs' requires a symbol argument\n"); try cli.stderrPrint(ctx.io, "Error: 'divs' requires a symbol argument\n");

View file

@ -33,10 +33,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len < 1) { if (cmd_args.len < 1) {
try cli.stderrPrint(ctx.io, "Error: 'earnings' requires a symbol argument\n"); try cli.stderrPrint(ctx.io, "Error: 'earnings' requires a symbol argument\n");

View file

@ -43,10 +43,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len < 1) { if (cmd_args.len < 1) {
try cli.stderrPrint(ctx.io, "Error: 'enrich' requires a portfolio file path or symbol\n"); try cli.stderrPrint(ctx.io, "Error: 'enrich' requires a portfolio file path or symbol\n");

View file

@ -28,10 +28,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len < 1) { if (cmd_args.len < 1) {
try cli.stderrPrint(ctx.io, "Error: 'etf' requires a symbol argument\n"); try cli.stderrPrint(ctx.io, "Error: 'etf' requires a symbol argument\n");

View file

@ -24,18 +24,20 @@
//! ``` //! ```
//! //!
//! The `validateCommandModule(Module)` walker enforces the contract at //! The `validateCommandModule(Module)` walker enforces the contract at
//! comptime with copy-paste-ready error messages. //! comptime with copy-paste-ready error messages. It's invoked from a
//! single registry walk in `src/main.zig`; individual command files
//! do NOT carry their own validation block. See the doc-comment on
//! `validateCommandModule` for the rationale.
//! //!
//! ## Global-option promotion criterion //! ## Global-option promotion criterion
//! //!
//! A flag belongs as a global iff it is *orthogonal* to every command's //! A flag belongs as a global iff it is *orthogonal* to every command's
//! semantics (purely an I/O / output / cache-policy concern) AND every //! semantics (purely an I/O / output / cache-policy concern) AND every
//! command would honor it identically. Today's globals are //! command would honor it identically. Today's globals are `--no-color`,
//! `--no-color`, `-p`, `-w` (and `--refresh` / `--no-refresh` once //! `-p`, `-w`, and `--refresh-data=<auto|never|force>`. `--as-of` does
//! commit 18c lands). `--as-of` does NOT pass this test because its //! NOT pass this test because its meaning varies between view-as-of
//! meaning varies between view-as-of (`projections`) and write-as-of //! (`projections`) and write-as-of (`snapshot`), and the two-sided
//! (`snapshot`), and the two-sided commands need two endpoints, not //! commands need two endpoints, not one so it stays per-command.
//! one so it stays per-command.
const std = @import("std"); const std = @import("std");
const zfin = @import("../root.zig"); const zfin = @import("../root.zig");
@ -264,8 +266,20 @@ fn resolveUserPath(
/// Validate a command module against the framework contract. Emits /// Validate a command module against the framework contract. Emits
/// a `@compileError` with the full expected signature for any /// a `@compileError` with the full expected signature for any
/// missing or wrong-shape decl. Call from the `command_modules` /// missing or wrong-shape decl.
/// registry walker in `src/main.zig`. ///
/// **Call site policy: registry-walk only.** This function should
/// be invoked exactly once per command, from the `command_modules`
/// registry walker in `src/main.zig`. Do NOT add in-file
/// `comptime { framework.validateCommandModule(@This()); }` blocks
/// to individual command files they're redundant with the
/// registry walk under both `zig build` and ZLS build-on-save (the
/// only ZLS mode that evaluates comptime; ZLS's own semantic
/// analyzer doesn't run comptime reliably). The registry walk also
/// produces a better diagnostic, identifying the offending command
/// by its registry name (`commands.cache`) rather than just its
/// module identity. The TUI tab framework follows the same policy
/// in `src/tui.zig`.
pub fn validateCommandModule(comptime Module: type) void { pub fn validateCommandModule(comptime Module: type) void {
comptime { comptime {
const mod_name = @typeName(Module); const mod_name = @typeName(Module);

View file

@ -85,10 +85,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub const Error = error{ pub const Error = error{
UnexpectedArg, UnexpectedArg,
InvalidFlagValue, InvalidFlagValue,

View file

@ -31,10 +31,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len < 1) { if (cmd_args.len < 1) {
try cli.stderrPrint(ctx.io, "Error: 'lookup' requires a CUSIP argument\n"); try cli.stderrPrint(ctx.io, "Error: 'lookup' requires a CUSIP argument\n");

View file

@ -64,10 +64,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub const RunError = error{ pub const RunError = error{
UnexpectedArg, UnexpectedArg,
MissingStep, MissingStep,

View file

@ -35,10 +35,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len < 1) { if (cmd_args.len < 1) {
try cli.stderrPrint(ctx.io, "Error: 'options' requires a symbol argument\n"); try cli.stderrPrint(ctx.io, "Error: 'options' requires a symbol argument\n");

View file

@ -35,10 +35,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len < 1) { if (cmd_args.len < 1) {
try cli.stderrPrint(ctx.io, "Error: 'perf' requires a symbol argument\n"); try cli.stderrPrint(ctx.io, "Error: 'perf' requires a symbol argument\n");

View file

@ -32,10 +32,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len > 0) { if (cmd_args.len > 0) {
const a = cmd_args[0]; const a = cmd_args[0];

View file

@ -110,10 +110,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
const io = ctx.io; const io = ctx.io;
const today = ctx.today; const today = ctx.today;

View file

@ -32,10 +32,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
/// Quote data extracted from the real-time API (or synthesized from candles). /// Quote data extracted from the real-time API (or synthesized from candles).
pub const QuoteData = struct { pub const QuoteData = struct {
price: f64, price: f64,

View file

@ -98,10 +98,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
var parsed: ParsedArgs = .{}; var parsed: ParsedArgs = .{};
var i: usize = 0; var i: usize = 0;

View file

@ -27,10 +27,6 @@ pub const meta: framework.Meta = .{
, ,
}; };
comptime {
framework.validateCommandModule(@This());
}
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
if (cmd_args.len < 1) { if (cmd_args.len < 1) {
try cli.stderrPrint(ctx.io, "Error: 'splits' requires a symbol argument\n"); try cli.stderrPrint(ctx.io, "Error: 'splits' requires a symbol argument\n");

View file

@ -35,10 +35,6 @@ pub const meta: framework.Meta = .{
.uppercase_first_arg = false, .uppercase_first_arg = false,
}; };
comptime {
framework.validateCommandModule(@This());
}
/// Parse `--verbose`/`-v`. Unknown args produce an error on stderr. /// Parse `--verbose`/`-v`. Unknown args produce an error on stderr.
pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs { pub fn parseArgs(ctx: *framework.RunCtx, cmd_args: []const []const u8) !ParsedArgs {
var parsed: ParsedArgs = .{}; var parsed: ParsedArgs = .{};

View file

@ -216,13 +216,13 @@ pub fn alwaysEnabled() fn (*App) bool {
// Every error message includes the full expected signature so the // Every error message includes the full expected signature so the
// developer knows exactly what to add, copy-paste ready. // developer knows exactly what to add, copy-paste ready.
// //
// Call sites: the registry in `src/tui.zig` calls this once per // Call site policy: registry-walk only. The registry in
// entry. Each `<name>_tab.zig` can also opt in via a comptime // `src/tui.zig` calls this once per entry. Do NOT add in-file
// block in the file itself for faster local feedback: // `comptime { framework.validateTabModule(@This()); }` blocks to
// // individual tab files they're redundant with the registry walk
// ```zig // under both `zig build` and ZLS build-on-save (the only ZLS mode
// comptime { framework.validateTabModule(@This()); } // that runs comptime), and the registry walk produces a better
// ``` // diagnostic. Mirrors the policy in `src/commands/framework.zig`.
/// Validate a tab module against the framework contract. Emits a /// Validate a tab module against the framework contract. Emits a
/// `@compileError` with the full expected signature for any /// `@compileError` with the full expected signature for any