bashrs 6.66.0

Rust-to-Shell transpiler for deterministic bootstrap scripts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
//! # Rash - Rust to Shell Transpiler
// Allow uppercase TASK_IDs in test function names (EXTREME TDD naming convention)
#![cfg_attr(test, allow(non_snake_case))]
// Allow unwrap in test code - tests should panic on unexpected conditions
#![cfg_attr(test, allow(clippy::unwrap_used))]
// Allow indexing in test code - tests should panic on out-of-bounds
#![cfg_attr(test, allow(clippy::indexing_slicing))]
// Allow absurd extreme comparisons (defensive test assertions like usize >= 0)
// TODO(v2.1.0): Clean up these assertions - Issue #TBD
#![allow(clippy::absurd_extreme_comparisons)]
// Rust 1.93: doc comments before dead-code-eliminated items trigger unused_doc_comments
#![allow(unused_doc_comments)]
// Allow multiple crate versions - transitive dependencies from different crates
#![allow(clippy::multiple_crate_versions)]
//!
//! Rash is a Rust-to-POSIX shell script transpiler that generates safe, deterministic,
//! and verifiable shell scripts from a restricted Rust subset.
//!
//! ## Features
//!
//! - **POSIX Compliance**: Generated scripts work on sh, dash, bash, and ash
//! - **Safety**: Injection attack prevention, proper quoting, verified output
//! - **Determinism**: Same input always produces identical output
//! - **ShellCheck Integration**: All output passes shellcheck validation
//!
//! ## Quick Start
//!
//! ```rust
//! use bashrs::{transpile, Config};
//!
//! let rust_code = r#"
//!     fn main() {
//!         let greeting = "Hello, World!";
//!         echo(greeting);
//!     }
//!
//!     fn echo(msg: &str) {}
//! "#;
//!
//! let shell_script = transpile(rust_code, &Config::default()).unwrap();
//! assert!(shell_script.contains("#!/bin/sh"));
//! ```
//!
//! ## Main Functions
//!
//! - [`transpile`]: Convert Rust code to shell script
//! - [`check`]: Validate Rust code without generating output
//!
//! ## Configuration
//!
//! ```rust
//! use bashrs::{Config, transpile};
//! use bashrs::models::{ShellDialect, VerificationLevel};
//!
//! let config = Config {
//!     target: ShellDialect::Posix,
//!     verify: VerificationLevel::Strict,
//!     optimize: true,
//!     ..Config::default()
//! };
//!
//! let rust_code = "fn main() { let x = 42; }";
//! let result = transpile(rust_code, &config);
//! assert!(result.is_ok());
//! ```

// Contract assertions from YAML (pv codegen)
#[macro_use]
#[allow(unused_macros)]
mod generated_contracts;

/// Abstract syntax tree types and validation
pub mod ast;
/// Bash script parsing and AST generation
pub mod bash_parser;
/// Bash quality tools (test generation, coverage, formatting, scoring)
#[cfg(not(target_arch = "wasm32"))]
pub mod bash_quality;
/// Bash script transpilation and purification
pub mod bash_transpiler;
/// build.rs integration with auto-discovery
#[cfg(not(target_arch = "wasm32"))]
pub mod build_rs;
/// Command-line interface for bashrs
#[cfg(all(not(target_arch = "wasm32"), feature = "clap"))]
pub mod cli;
/// Rust compiler integration for transpilation
#[cfg(all(not(target_arch = "wasm32"), feature = "compile"))]
pub mod compiler;
/// Shell artifact compliance system (SPEC-COMPLY-2026-001)
#[cfg(not(target_arch = "wasm32"))]
pub mod comply;
/// Shell configuration file management and analysis
pub mod config;
/// Container and sandbox support
#[cfg(all(not(target_arch = "wasm32"), feature = "compile"))]
pub mod container;
/// Corpus-driven transpilation quality measurement (Popperian falsification)
#[cfg(not(target_arch = "wasm32"))]
pub mod corpus;
/// Shell script code emission
pub mod emitter;
/// Formal verification and proof generation
#[cfg(not(target_arch = "wasm32"))]
pub mod formal;
/// Shell script formatting
pub mod formatter;
/// Quality gate configuration and enforcement
#[cfg(not(target_arch = "wasm32"))]
pub mod gates;
/// TDD-first installer framework
#[cfg(not(target_arch = "wasm32"))]
pub mod installer;
/// Intermediate representation for transpilation
pub mod ir;
/// Shell script linting with ShellCheck-equivalent rules
pub mod linter;
/// Makefile parsing and purification
pub mod make_parser;
/// Configuration types and error handling
pub mod models;
/// Quality gates with rich reporting and fault localization (ML-001 to ML-012)
#[cfg(not(target_arch = "wasm32"))]
pub mod quality;
/// Interactive REPL with integrated debugger
#[cfg(all(not(target_arch = "wasm32"), feature = "rustyline"))]
pub mod repl;
/// Parser and compiler services
pub mod services;
/// Standard library function mappings
pub mod stdlib;
/// Stdlib function metadata (extracted for file-size discipline)
pub mod stdlib_metadata;
/// Test case generation from shell scripts
#[cfg(not(target_arch = "wasm32"))]
pub mod test_generator;
/// Tracing infrastructure for diagnostics and debugging
pub mod tracing;
/// Builder API for programmatic transpilation
pub mod transpiler;
/// Type system with taint tracking for injection safety
pub mod types;
/// AST and output validation
pub mod validation;
/// Output verification and shellcheck integration
#[cfg(not(target_arch = "wasm32"))]
pub mod verifier;

/// Terminal User Interface (TUI) with ratatui
#[cfg(feature = "tui")]
pub mod tui;

#[cfg(test)]
pub mod testing;

#[cfg(test)]
#[path = "coverage_integration_tests.rs"]
mod coverage_integration_tests;

// WebAssembly support removed - use probar/simular/jugar instead

pub use emitter::{DecisionTrace, TranspilerDecision};
pub use models::{Config, Error, Result};
pub use transpiler::Transpiler;

/// Transpile Rust source code to POSIX shell script.
///
/// This is the main entry point for the Rash transpiler. It takes Rust source code
/// and converts it to a POSIX-compliant shell script with full validation.
///
/// # Arguments
///
/// * `input` - Rust source code as a string
/// * `config` - Configuration options for transpilation
///
/// # Returns
///
/// * `Ok(String)` - Generated shell script
/// * `Err(Error)` - Transpilation error (parse, validation, emission)
///
/// # Examples
///
/// ## Basic Usage
///
/// ```rust
/// use bashrs::{transpile, Config};
///
/// let rust_code = r#"
///     fn main() {
///         let message = "Hello from Rash";
///         echo(message);
///     }
///     fn echo(msg: &str) {}
/// "#;
///
/// let shell_script = transpile(rust_code, &Config::default()).unwrap();
/// assert!(shell_script.contains("#!/bin/sh"));
/// assert!(shell_script.contains("message="));
/// ```
///
/// ## With Custom Configuration
///
/// ```rust
/// use bashrs::{transpile, Config};
/// use bashrs::models::{ShellDialect, VerificationLevel};
///
/// let config = Config {
///     target: ShellDialect::Bash,
///     verify: VerificationLevel::Paranoid,
///     optimize: true,
///     ..Config::default()
/// };
///
/// let rust_code = "fn main() { let x = 1 + 2; }";
/// let result = transpile(rust_code, &config);
/// assert!(result.is_ok());
/// ```
///
/// ## Variable Assignment
///
/// ```rust
/// use bashrs::{transpile, Config};
///
/// let rust_code = r#"
///     fn main() {
///         let name = "Alice";
///         let age = 30;
///         let active = true;
///     }
/// "#;
///
/// let shell_script = transpile(rust_code, &Config::default()).unwrap();
/// assert!(shell_script.contains("name="));
/// assert!(shell_script.contains("age="));
/// ```
///
/// ## Function Calls
///
/// ```rust
/// use bashrs::{transpile, Config};
///
/// let rust_code = r#"
///     fn main() {
///         greet("World");
///     }
///     fn greet(name: &str) {}
/// "#;
///
/// let shell_script = transpile(rust_code, &Config::default()).unwrap();
/// assert!(shell_script.contains("greet"));
/// ```
///
/// # Errors
///
/// Returns `Err` if:
/// - Input cannot be parsed as valid Rust
/// - AST validation fails (unsupported features)
/// - IR generation fails
/// - Shell code emission fails
/// - Output validation fails (shellcheck, safety checks)
pub fn transpile(input: &str, config: &Config) -> Result<String> {
    let validation_pipeline = validation::pipeline::ValidationPipeline::new(config);

    let ast = services::parser::parse(input)?;
    ast::validate(&ast)?;
    validation_pipeline.validate_ast(&ast)?;

    let ir = ir::from_ast(&ast)?;
    validation_pipeline.validate_ir(&ir)?;

    let optimized = ir::optimize(ir, config)?;
    let shell_code = emitter::emit(&optimized)?;

    validation_pipeline.validate_output(&shell_code)?;

    Ok(shell_code)
}

/// Transpile Rust source code to POSIX shell script with decision tracing.
///
/// Same pipeline as [`transpile`], but collects a trace of emitter decisions
/// for fault localization via the SBFL module.
///
/// # Returns
///
/// * `Ok((String, DecisionTrace))` - Generated shell script and decision trace
/// * `Err(Error)` - Transpilation error
pub fn transpile_with_trace(input: &str, config: &Config) -> Result<(String, DecisionTrace)> {
    let validation_pipeline = validation::pipeline::ValidationPipeline::new(config);

    let ast = services::parser::parse(input)?;
    ast::validate(&ast)?;
    validation_pipeline.validate_ast(&ast)?;

    let ir = ir::from_ast(&ast)?;
    validation_pipeline.validate_ir(&ir)?;

    let optimized = ir::optimize(ir, config)?;
    let (shell_code, trace) = emitter::emit_with_trace(&optimized)?;

    validation_pipeline.validate_output(&shell_code)?;

    Ok((shell_code, trace))
}

/// Transpile Rust source code to POSIX shell script with lint validation.
///
/// Like [`transpile`], but additionally runs the built-in linter on the generated
/// shell output. Returns both the shell script and any lint diagnostics found.
///
/// # Arguments
///
/// * `input` - Rust source code as a string
/// * `config` - Configuration options for transpilation
///
/// # Returns
///
/// * `Ok((String, LintResult))` - Generated shell script and lint results
/// * `Err(Error)` - Transpilation error
pub fn transpile_with_lint(input: &str, config: &Config) -> Result<(String, linter::LintResult)> {
    let shell_code = transpile(input, config)?;
    let lint_result = linter::rules::lint_shell(&shell_code);
    Ok((shell_code, lint_result))
}

/// Transpile Rust source code to a Makefile.
///
/// Converts a Rust DSL into a valid Makefile using conventions:
/// - `let` bindings -> Makefile variables (`CC := gcc`)
/// - `target("name", &["deps"], &["recipes"])` -> Make targets
/// - `phony_target("name", ...)` -> `.PHONY` targets
///
/// # Arguments
///
/// * `input` - Rust source code using the Makefile DSL
/// * `config` - Configuration options
///
/// # Returns
///
/// * `Ok(String)` - Generated Makefile content
/// * `Err(Error)` - Transpilation error
pub fn transpile_makefile(input: &str, config: &Config) -> Result<String> {
    let _validation_pipeline = validation::pipeline::ValidationPipeline::new(config);

    let ast = services::parser::parse(input)?;
    ast::validate(&ast)?;

    emitter::makefile::emit_makefile(&ast)
}

/// Transpile Rust source code to a Dockerfile.
///
/// Converts a Rust DSL into a valid Dockerfile using conventions:
/// - `from_image("rust", "1.75-alpine")` -> `FROM rust:1.75-alpine`
/// - `run(&["cmd1", "cmd2"])` -> `RUN cmd1 && cmd2`
/// - `copy("src", "dst")` -> `COPY src dst`
/// - `workdir("/app")` -> `WORKDIR /app`
/// - `user("65534")` -> `USER 65534`
/// - `entrypoint(&["/app"])` -> `ENTRYPOINT ["/app"]`
///
/// # Arguments
///
/// * `input` - Rust source code using the Dockerfile DSL
/// * `config` - Configuration options
///
/// # Returns
///
/// * `Ok(String)` - Generated Dockerfile content
/// * `Err(Error)` - Transpilation error
pub fn transpile_dockerfile(input: &str, config: &Config) -> Result<String> {
    let _validation_pipeline = validation::pipeline::ValidationPipeline::new(config);

    let ast = services::parser::parse(input)?;
    ast::validate(&ast)?;

    emitter::dockerfile::emit_dockerfile(&ast)
}

/// Check if the given Rust code is valid for transpilation without generating output.
///
/// This function parses and validates the input Rust code but does not generate
/// shell script output. Useful for quick validation or IDE integration.
///
/// # Arguments
///
/// * `input` - Rust source code as a string
///
/// # Returns
///
/// * `Ok(())` - Code is valid and can be transpiled
/// * `Err(Error)` - Code has syntax or validation errors
///
/// # Examples
///
/// ## Valid Code
///
/// ```rust
/// use bashrs::check;
///
/// let valid_code = r#"
///     fn main() {
///         let x = 42;
///         let y = "hello";
///     }
/// "#;
///
/// assert!(check(valid_code).is_ok());
/// ```
///
/// ## Invalid Syntax
///
/// ```rust
/// use bashrs::check;
///
/// let invalid_code = "fn main( { }"; // Missing closing paren
/// assert!(check(invalid_code).is_err());
/// ```
///
/// ## Unsupported Features
///
/// ```rust
/// use bashrs::check;
///
/// let unsupported = r#"
///     fn main() {
///         let v = vec![1, 2, 3]; // Vec not supported in v1.0
///     }
/// "#;
///
/// // This may fail validation depending on the restricted subset
/// let result = check(unsupported);
/// ```
///
/// # Use Cases
///
/// - **IDE Integration**: Fast syntax checking without full transpilation
/// - **CI/CD Validation**: Verify Rash code before transpilation
/// - **Development**: Quick feedback loop for code validity
pub fn check(input: &str) -> Result<()> {
    let ast = services::parser::parse(input)?;
    ast::validate(&ast)?;
    Ok(())
}