zenith_cli/cli/library.rs
1//! Argument types for `zenith library` and its subcommands.
2
3use clap::{Args, Subcommand};
4use std::path::PathBuf;
5
6/// Arguments for `zenith library`.
7///
8/// The library subsystem is a set of reusable **packs** — collections of design
9/// assets that you materialize into a `.zen` document. A pack is identified by
10/// a package id such as `@zenith/filters`, and each pack exports one or more
11/// named **items** addressed as `<package>#<item>` (e.g.
12/// `@zenith/flowchart#decision`).
13///
14/// Three item kinds exist:
15///
16/// * **token** — a filter or mask token (e.g. `@zenith/filters#sepia`). Added
17/// to the document's `tokens` block; apply with `filter=(token)"sepia"` or
18/// `mask=(token)"vignette"` on any node.
19/// * **component** — a reusable node group (e.g. a flowchart shape) that is
20/// materialized as an `instance` on a named page. Requires `--page <id>`.
21/// * **action** — a canned transaction op sequence (e.g.
22/// `@zenith/brand-kit#apply-2026`) that mutates the target document's tokens
23/// or layout. No page required.
24///
25/// Embedded `@zenith/*` packs are bundled in the binary; project-local packs
26/// live in `<project-dir>/libraries/*.zen` and shadow the embedded ones.
27///
28/// WORKFLOW:
29/// zenith library list # discover packs + items
30/// zenith library show @zenith/filters#sepia # inspect one item
31/// zenith library add @zenith/filters#sepia --into poster.zen
32#[derive(Debug, Args)]
33#[command(
34 long_about = "Manage reusable library packs (embedded @zenith/* presets + project-local packs).\n\n\
35A pack exports items addressed as <package>#<item>, e.g. `@zenith/flowchart#decision`.\n\
36Item kinds:\n \
37token — filter or mask token; copy into tokens block, apply with filter=(token)\"id\"\n \
38component — reusable node group; materialized as an instance on a page (requires --page)\n \
39action — canned tx op sequence; runs a transaction against the target document\n\n\
40Embedded @zenith/* packs are built in; project packs live in libraries/*.zen and shadow them.\n\n\
41WORKFLOW:\n \
42zenith library list # discover packs and items\n \
43zenith library show @zenith/filters#sepia # inspect item content before adding\n \
44zenith library add @zenith/filters#sepia --into poster.zen"
45)]
46pub struct LibraryArgs {
47 #[command(subcommand)]
48 pub command: LibrarySub,
49}
50
51/// Subcommands of `zenith library`.
52#[derive(Debug, Subcommand)]
53pub enum LibrarySub {
54 /// List all resolved library packs (project + embedded presets) and items.
55 ///
56 /// Lists every available pack and its exported items. Run `zenith library
57 /// show <package>#<item>` to inspect any item in detail before adding it.
58 List(LibraryListArgs),
59
60 /// Inspect a library item in detail before adding it.
61 ///
62 /// Shows the package, item id, and kind-specific content: filter/mask token
63 /// types and ops, component node structure, or action op sequence. Prints
64 /// the exact `zenith library add` invocation to materialize the item.
65 Show(LibraryShowArgs),
66
67 /// Materialize a library item into a target `.zen` document.
68 Add(LibraryAddArgs),
69}
70
71/// Arguments for `zenith library add`.
72#[derive(Debug, Args)]
73pub struct LibraryAddArgs {
74 /// The item to add, as `<package>#<item>`, e.g. `@zenith/flowchart#decision`.
75 pub spec: String,
76
77 /// Target `.zen` document to materialize the item into (written in-place,
78 /// unless `--dry-run`). Its parent directory is the project dir whose
79 /// `libraries/*.zen` packs are resolved alongside the embedded presets.
80 #[arg(long, value_name = "FILE")]
81 pub into: PathBuf,
82
83 /// Id of the page in the target document to place the instance on.
84 ///
85 /// Required only for COMPONENT items; TOKEN items (filter tokens) ignore it.
86 #[arg(long, value_name = "ID")]
87 pub page: Option<String>,
88
89 /// Instance origin as `X,Y` in pixels (default `0,0`).
90 #[arg(long, value_name = "X,Y")]
91 pub at: Option<String>,
92
93 /// Override the generated instance id base (default: the item name).
94 #[arg(long, value_name = "ID")]
95 pub id: Option<String>,
96
97 /// Print the resulting source to stdout WITHOUT writing the file.
98 #[arg(long)]
99 pub dry_run: bool,
100}
101
102/// Arguments for `zenith library list`.
103#[derive(Debug, Args)]
104pub struct LibraryListArgs {
105 /// Project directory, or a `.zen` file whose parent is the project directory.
106 /// Project `libraries/*.zen` packs are scanned alongside embedded presets.
107 /// Defaults to the current working directory.
108 pub path: Option<PathBuf>,
109
110 /// Emit machine-readable JSON instead of a human-readable listing.
111 #[arg(long)]
112 pub json: bool,
113}
114
115/// Arguments for `zenith library show`.
116#[derive(Debug, Args)]
117#[command(after_help = "EXAMPLES:\n \
118zenith library show @zenith/filters#sepia # inspect a filter token\n \
119zenith library show @zenith/flowchart#decision # inspect a component\n \
120zenith library show @zenith/brand-kit#apply-2026 --json")]
121pub struct LibraryShowArgs {
122 /// The item to inspect, as `<package>#<item>`, e.g. `@zenith/filters#sepia`.
123 pub spec: String,
124
125 /// Project directory, or a `.zen` file whose parent is the project directory.
126 /// Project `libraries/*.zen` packs are resolved alongside embedded presets.
127 /// Defaults to the current working directory.
128 pub path: Option<PathBuf>,
129
130 /// Emit machine-readable JSON instead of a human-readable summary.
131 #[arg(long)]
132 pub json: bool,
133}