hedl_cli/cli/core.rs
1// Dweve HEDL - Hierarchical Entity Data Language
2//
3// Copyright (c) 2025 Dweve IP B.V. and individual contributors.
4//
5// SPDX-License-Identifier: Apache-2.0
6//
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License in the LICENSE file at the
10// root of this repository or at: http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Core HEDL commands for validation, formatting, linting, and inspection.
19//!
20//! This module contains the fundamental HEDL CLI commands that operate on
21//! individual HEDL files for validation, formatting, and analysis.
22
23use crate::commands;
24use clap::Subcommand;
25
26/// Core HEDL commands.
27///
28/// These commands provide the essential functionality for working with HEDL files:
29/// validation, formatting, linting, inspection, and statistics.
30///
31/// # Commands
32///
33/// - **Validate**: Check HEDL syntax and semantic correctness
34/// - **Format**: Convert to canonical form with optional optimizations
35/// - **Lint**: Check for best practices and style issues
36/// - **Inspect**: Visualize internal structure
37/// - **Stats**: Analyze size and token efficiency
38#[derive(Subcommand)]
39pub enum CoreCommands {
40 /// Validate a HEDL file
41 ///
42 /// Checks the syntax and semantic correctness of a HEDL file. In strict mode,
43 /// all references must resolve to existing entities.
44 Validate {
45 /// Input file path
46 #[arg(value_name = "FILE")]
47 file: String,
48
49 /// Strict reference validation (all references must resolve)
50 #[arg(short, long)]
51 strict: bool,
52
53 /// Use lenient parsing mode (constraint violations become null)
54 #[arg(short, long)]
55 lenient: bool,
56 },
57
58 /// Format a HEDL file to canonical form
59 ///
60 /// Reformats a HEDL file to its canonical representation. Supports various
61 /// formatting options including ditto optimization and automatic count hints.
62 Format {
63 /// Input file path
64 #[arg(value_name = "FILE")]
65 file: String,
66
67 /// Output file path (defaults to stdout)
68 #[arg(short, long)]
69 output: Option<String>,
70
71 /// Check only (exit 1 if not canonical)
72 #[arg(short, long)]
73 check: bool,
74
75 /// Use ditto optimization
76 #[arg(long, default_value = "true")]
77 ditto: bool,
78
79 /// Automatically add count hints to all matrix lists
80 #[arg(long)]
81 with_counts: bool,
82 },
83
84 /// Lint a HEDL file for best practices
85 ///
86 /// Analyzes a HEDL file for style issues, best practices violations, and
87 /// potential problems. Can output results in text or JSON format.
88 Lint {
89 /// Input file path
90 #[arg(value_name = "FILE")]
91 file: String,
92
93 /// Output format (text, json)
94 #[arg(short, long, default_value = "text")]
95 format: String,
96
97 /// Treat warnings as errors
98 #[arg(short = 'W', long)]
99 warn_error: bool,
100 },
101
102 /// Print parsed structure (debug)
103 ///
104 /// Displays the internal structure of a HEDL file as a tree, useful for
105 /// debugging and understanding how HEDL parses the file.
106 Inspect {
107 /// Input file path
108 #[arg(value_name = "FILE")]
109 file: String,
110
111 /// Show detailed internal structure
112 #[arg(short, long)]
113 verbose: bool,
114 },
115
116 /// Show size/token savings vs other formats
117 ///
118 /// Analyzes a HEDL file and compares its size and token count against
119 /// equivalent representations in JSON, YAML, XML, CSV, and Parquet.
120 Stats {
121 /// Input HEDL file
122 #[arg(value_name = "FILE")]
123 file: String,
124
125 /// Show estimated token counts for LLM context
126 #[arg(short, long)]
127 tokens: bool,
128 },
129}
130
131impl CoreCommands {
132 /// Execute the core command.
133 ///
134 /// # Returns
135 ///
136 /// Returns `Ok(())` on success, or an error message on failure.
137 ///
138 /// # Errors
139 ///
140 /// Returns `Err` if the command execution fails.
141 pub fn execute(self) -> Result<(), crate::error::CliError> {
142 match self {
143 CoreCommands::Validate {
144 file,
145 strict,
146 lenient,
147 } => commands::validate(&file, strict, lenient),
148 CoreCommands::Format {
149 file,
150 output,
151 check,
152 ditto,
153 with_counts,
154 } => commands::format(&file, output.as_deref(), check, ditto, with_counts),
155 CoreCommands::Lint {
156 file,
157 format,
158 warn_error,
159 } => commands::lint(&file, &format, warn_error),
160 CoreCommands::Inspect { file, verbose } => commands::inspect(&file, verbose),
161 CoreCommands::Stats { file, tokens } => commands::stats(&file, tokens),
162 }
163 }
164}