# Contributing to rok-utils

Thank you for your interest in contributing to rok-utils!

## Getting Started

1. Fork the repository
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/rok-utils.git`
3. Add upstream: `git remote add upstream https://github.com/ateeq1999/rok-utils.git`
4. Install Rust (latest stable)
5. Run tests: `cargo test --all-features`

## Development Workflow

### 1. Create a Branch

```bash
git checkout -b feature/your-feature-name
```

### 2. Make Changes

Follow the coding standards:
- Run `cargo fmt` before committing
- Run `cargo clippy --all-features -- -D warnings` to catch issues
- Add tests for new functionality
- Keep files under 400 lines

### 3. Test Your Changes

```bash
# Run all tests
cargo test --all-features

# Run doc tests
cargo test --doc

# Check formatting
cargo fmt --check

# Run clippy
cargo clippy --all-features -- -D warnings
```

### 4. Commit and Push

```bash
git add .
git commit -m "feat: add new feature"
git push origin feature/your-feature-name
```

### 5. Open a Pull Request

Open a PR against `main` with a clear description of your changes.

## Coding Standards

### Error Handling
- Never use `unwrap()` in library code
- Return `Result<T, RokError>` or `Option<T>` for fallible operations
- Use the `context()` method for adding error context

```rust
// Good
fn read_config(path: &str) -> Result<Config, RokError> {
    std::fs::read_to_string(path)
        .context("Failed to read config file")
        .and_then(|content| {
            serde_json::from_str(&content)
                .context("Failed to parse config")
        })
}

// Avoid
fn read_config(path: &str) -> Config {
    std::fs::read_to_string(path).unwrap() // Never do this!
}
```

### String Operations
- Use `chars()` for character iteration (UTF-8 native)
- Never assume ASCII-only input

### Naming Conventions
- Functions: `snake_case` (e.g., `to_snake_case`)
- Types: `PascalCase` (e.g., `RokError`, `Str`)
- Traits: `PascalCase` (e.g., `ResultExt`)
- Constants: `SCREAMING_SNAKE_CASE`

### Module Organization
- Each module should be under 400 lines
- Use feature flags for heavy dependencies
- Export only public API from `lib.rs`

## Adding New Functions

### 1. Function Template

```rust
/// Brief description of what the function does.
///
/// Longer description if needed, explaining behavior
/// and edge cases.
///
/// # Arguments
///
/// * `input` - Description of input parameter
///
/// # Examples
///
/// ```rust
/// use rok_utils::module_name::new_function;
/// assert_eq!(new_function("test"), "expected");
/// ```
///
/// # See Also
///
/// * [`related_function`] for similar functionality
pub fn new_function(input: &str) -> String {
    // Implementation
}
```

### 2. Add Tests

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_new_function_basic() {
        assert_eq!(new_function("test"), "expected");
    }

    #[test]
    fn test_new_function_empty() {
        assert_eq!(new_function(""), "");
    }
}
```

### 3. Feature Flag (if needed)

```rust
#[cfg(feature = "your-feature")]
pub fn new_function(input: &str) -> String {
    // Implementation
}
```

## Adding New Modules

1. Create the module file: `src/module_name.rs`
2. Add module declaration: `pub mod module_name;` in `lib.rs`
3. Add re-exports: `pub use module_name::*;`
4. Add tests inline with `#[cfg(test)] mod tests`
5. Update documentation

## Documentation

### Inline Documentation
- Document all public items
- Include examples for public functions
- Use proper Markdown formatting

### Module README
- Update `src/module_name/README.md` with overview
- Include quick start examples
- Document feature flags

## Reporting Issues

- Use GitHub Issues for bugs and feature requests
- Include minimal reproduction steps
- Specify Rust version and feature flags used

## Code of Conduct

- Be respectful and inclusive
- Focus on constructive feedback
- Follow Rust's community guidelines

## License

By contributing, you agree that your contributions will be licensed under the MIT License.
