Contributing
Guidelines for contributing to printwell.
Getting Started
-
Fork the repository
-
Clone your fork:
git clone https://github.com/YOUR_USERNAME/core cd core -
Set up the development environment:
# Initialize Chromium (first time only) cargo xtask init # Build native library cargo xtask build
Development Workflow
Running Tests
# All tests
cargo xtask test
# Rust unit tests only
cargo test --workspace
# E2E tests
cargo xtask e2e
# Specific test
cargo test --package printwell test_encryption
Running Lints
# All lints
cargo xtask lint
# Rust only
cargo clippy --workspace --all-targets
cargo fmt --check
# Fix formatting
cargo fmt
Running Benchmarks
cargo xtask bench
Code Style
Rust
- Follow standard Rust conventions
- Use
cargo fmtfor formatting - Use
cargo clippyfor linting - Write doc comments for public APIs
#![allow(unused)]
fn main() {
/// Converts HTML to PDF.
///
/// # Arguments
///
/// * `html` - The HTML content to convert
/// * `options` - Conversion options
///
/// # Returns
///
/// A `PdfResult` containing the generated PDF bytes.
///
/// # Errors
///
/// Returns `PrintwellError::Conversion` if the conversion fails.
pub fn convert_html(&self, html: &str, options: PdfOptions) -> Result<PdfResult> {
// ...
}
}
Commit Messages
Use conventional commits:
feat: add watermark rotation support
fix: handle empty HTML input
docs: update installation guide
test: add encryption round-trip test
refactor: simplify converter pool logic
Pull Request Process
-
Create a feature branch:
git checkout -b feature/my-feature -
Make your changes with tests
-
Ensure all checks pass:
cargo xtask test cargo xtask lint -
Push and create a PR:
git push origin feature/my-feature -
Fill out the PR template
-
Address review feedback
Adding New Features
To printwell (Pure Rust)
- Create module in
crates/printwell/src/ - Add exports to
crates/printwell/src/lib.rs - Add feature flag if needed in
Cargo.toml - Add tests in the module
- Update documentation
To printwell-core (Native)
- Add C++ code in
cpp/src/ - Update
cpp/BUILD.gnif needed - Add FFI in
crates/printwell-sys/src/lib.rs - Add safe wrapper in
crates/printwell-core/src/ - Rebuild native library:
cargo xtask build
To Bindings
- Add types to
bindings/shared/src/lib.rs - Add Node.js binding in
bindings/node/src/lib.rs - Add Python binding in
bindings/python/src/lib.rs - Update TypeScript types in
bindings/node/index.d.ts - Update Python stubs in
bindings/python/printwell/__init__.pyi - Add tests for both bindings
Testing Guidelines
Unit Tests
Test individual functions in isolation:
#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_watermark_position() {
let pos = WatermarkPosition::Center;
assert_eq!(pos.to_css(), "center");
}
}
}
Integration Tests
Test complete workflows:
#![allow(unused)]
fn main() {
#[test]
fn test_html_to_pdf_with_watermark() {
let converter = Converter::new().unwrap();
let result = converter.convert_html("<h1>Test</h1>", PdfOptions::default()).unwrap();
let watermark = Watermark::text("DRAFT");
let watermarked = add_watermark(&result.bytes, &watermark).unwrap();
assert!(!watermarked.is_empty());
}
}
E2E Tests
Located in e2e/ directory. Test CLI commands:
cargo xtask e2e
Documentation
API Documentation
Use rustdoc comments:
#![allow(unused)]
fn main() {
/// Brief description.
///
/// Longer description with more details.
///
/// # Examples
///
/// ```rust
/// use printwell::watermark::{add_watermark, Watermark};
///
/// let watermark = Watermark::text("CONFIDENTIAL");
/// let result = add_watermark(&pdf_data, &watermark)?;
/// ```
pub fn add_watermark(pdf: &[u8], watermark: &Watermark) -> Result<Vec<u8>> {
// ...
}
}
User Documentation
Update mdBook docs in docs/src/:
# Build and serve docs
cargo xtask docs --target book --serve
Reporting Issues
Bug Reports
Include:
- printwell version
- Operating system
- Minimal reproduction steps
- Expected vs actual behavior
Feature Requests
Include:
- Use case description
- Proposed API (if applicable)
- Any alternatives considered
License
Contributions are licensed under the same terms as the project (see LICENSE file).