Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 36 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
[workspace]
resolver = "3"
members = ["crates/cli", "crates/render", "crates/core"]
members = [
"crates/cli",
"crates/core-invoice",
"crates/core-pdf",
"crates/render-invoice",
"crates/render-pdf",
]

[workspace.dependencies]
# Internal dependencies
klirr-core = { path = "crates/core", version = "0.2.1" }
klirr-render = { path = "crates/render", version = "0.2.1" }
klirr-core-invoice = { path = "crates/core-invoice", version = "0.2.1" }
klirr-core-pdf = { path = "crates/core-pdf", version = "0.2.1" }
klirr-render-invoice = { path = "crates/render-invoice", version = "0.2.1" }
klirr-render-pdf = { path = "crates/render-pdf", version = "0.2.1" }

# External dependencies
aes-gcm = { version = "=0.10.3", default-features = false, features = [
Expand Down
18 changes: 11 additions & 7 deletions HOW_IT_WORKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,17 @@ pub fn render(l18n: L18n, data: PreparedData, layout: Layout) -> Result<Pdf> {
"#,
TYPST_VIRTUAL_NAME_DATA, TYPST_VIRTUAL_NAME_L18N, TYPST_VIRTUAL_NAME_LAYOUT
);

let context =
TypstContext::with_inline(main, layout_typst_str, l18n_typst_str, data_typst_str)?;

let doc = typst::compile::<PagedDocument>(&context)?;
// convert to PDF
typst_pdf::pdf(doc)
let plan = DocumentPlan::new(
layout.required_fonts(),
InlineModule::new(TYPST_VIRTUAL_NAME_MAIN, main),
)
.with_modules(vec![
InlineModule::new(TYPST_VIRTUAL_NAME_LAYOUT, layout_typst_str),
InlineModule::new(TYPST_VIRTUAL_NAME_L18N, l18n_typst_str),
InlineModule::new(TYPST_VIRTUAL_NAME_DATA, data_typst_str),
]);

render_document(&plan)
}
```

Expand Down
6 changes: 3 additions & 3 deletions _typos.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[files]
extend-exclude = [
"crates/core/src/models/l18n/swedish.rs",
"crates/core/src/models/l18n/snapshots/klirr_core__models__l18n__localization__tests__l18n_swedish.snap",
"crates/core-invoice/src/models/l18n/swedish.rs",
"crates/core-invoice/src/models/l18n/snapshots/klirr_core_invoice__models__l18n__localization__tests__l18n_swedish.snap",
]

[default.extend-words]
typ = "typ"
cheduling = "cheduling"
cheduling = "cheduling"
4 changes: 2 additions & 2 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ repository = "https://github.com/Sajjon/klirr"

[dependencies]
# Internal dependencies
klirr-core.workspace = true
klirr-render.workspace = true
klirr-core-invoice.workspace = true
klirr-render-invoice.workspace = true

# External dependencies
bon.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/dispatch_command.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::prelude::*;
use klirr_render::prelude::render;
use klirr_render_invoice::prelude::render;
use secrecy::SecretString;

fn init_email_data(
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/input/time_off_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub struct TimeOffInput {
}

impl TryFrom<TimeOffInput> for TimeOff {
type Error = klirr_core::Error;
type Error = klirr_core_invoice::Error;

fn try_from(input: TimeOffInput) -> Result<Self, Self::Error> {
let decimal = Decimal::try_from(input.quantity)?;
Expand Down
2 changes: 1 addition & 1 deletion crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod run;
pub mod prelude {
pub(crate) use clap::{Parser, Subcommand};
pub(crate) use derive_more::FromStr;
pub(crate) use klirr_core::prelude::*;
pub(crate) use klirr_core_invoice::prelude::*;

pub(crate) use crate::dispatch_command::*;
pub(crate) use crate::init_logging::*;
Expand Down
5 changes: 3 additions & 2 deletions crates/core/Cargo.toml → crates/core-invoice/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
[package]
name = "klirr-core"
name = "klirr-core-invoice"
rust-version = "1.85.1"
version = "0.2.1"
edition = "2024"
description = "Zero-maintenance and smart FOSS generating beautiful invoices for services and expenses."
license = "MIT"
documentation = "https://docs.rs/klirr-core"
documentation = "https://docs.rs/klirr-core-invoice"
repository = "https://github.com/Sajjon/klirr"

[dependencies]
klirr-core-pdf.workspace = true
aes-gcm.workspace = true
bon.workspace = true
chrono.workspace = true
Expand Down
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions crates/core/src/lib.rs → crates/core-invoice/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod prelude {

pub use crate::logic::*;
pub use crate::models::*;
pub use klirr_core_pdf::prelude::*;

pub use std::{
collections::HashMap,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ impl YearAndMonth {
/// year is not a leap year, February will return 28, and for leap year
/// 29 is returned.
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
///
/// let year_and_month = YearAndMonth::january(2025);
/// assert_eq!(year_and_month.last_day_of_month(), Day::try_from(31).unwrap());
Expand All @@ -78,8 +78,8 @@ impl YearAndMonth {
/// Converts this `YearAndMonth` to a `Date` representing the last day of the month.
///
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
/// let month = YearAndMonth::january(2025);
/// let date = month.to_date_end_of_month();
/// assert_eq!(date.year(), &Year::from(2025));
Expand All @@ -101,8 +101,8 @@ impl YearAndMonth {
/// Returns a new `YearAndMonth` that is one month earlier than this one.
/// If the month is January, it will return December of the previous year.
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
/// let month = YearAndMonth::january(2025);
/// let one_month_earlier = month.one_month_earlier();
/// assert_eq!(one_month_earlier, YearAndMonth::december(2024));
Expand Down Expand Up @@ -136,8 +136,8 @@ impl YearAndMonth {
///
/// # Examples
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
/// let start = YearAndMonth::january(2025);
/// let end = YearAndMonth::april(2025);
/// assert_eq!(end.elapsed_months_since(start).unwrap(), 3);
Expand Down Expand Up @@ -224,8 +224,8 @@ impl IsPeriod for YearAndMonth {
/// adding an additional increment if the items are expenses.
///
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
/// let offset = TimestampedInvoiceNumber::<YearAndMonth>::builder().offset(100.into()).period(YearAndMonth::january(2024)).build();
/// let target_month = YearAndMonth::august(2024);
/// let is_expenses = true;
Expand Down Expand Up @@ -286,8 +286,8 @@ pub fn calculate_invoice_number<Period: IsPeriod>(
/// Returns an error if the target month is in the record of months off.
///
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
///
/// let target_month = YearAndMonth::january(2024);
/// let working_days = quantity_in_period(&target_month, Granularity::Day, Cadence::Monthly, &RecordOfPeriodsOff::default());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn create_pdf_with_data<Period: IsPeriod>(
create_folder_to_parent_of_path_if_needed(&output_path)?;
let prepared_data = data.clone();
let pdf = render(l18n, data, layout)?;
save_pdf(pdf.clone(), &output_path)?;
save_pdf(pdf.clone(), &output_path).map_err(|underlying| Error::SavePdf { underlying })?;
Ok(NamedPdf::builder()
.pdf(pdf)
.saved_at(output_path.clone())
Expand All @@ -36,18 +36,6 @@ pub fn create_pdf_with_data<Period: IsPeriod>(
.build())
}

/// Saves the PDF file `pdf` to the specified path `pdf_path`.
fn save_pdf(pdf: Pdf, pdf_path: impl AsRef<Path>) -> Result<PathBuf> {
info!("Saving PDF to: '{}'", pdf_path.as_ref().display());
// now save the PDF to a file
let output_path = PathBuf::from(pdf_path.as_ref());
std::fs::write(&output_path, pdf.as_ref()).map_err(|e| Error::SavePdf {
underlying: format!("Write PDF to {}: {}", output_path.display(), e),
})?;
info!("✅ Saved PDF to: '{}'", pdf_path.as_ref().display());
Ok(output_path)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ impl AesGcm256 {
///
/// # Examples
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
/// let secret = "super secret data";
/// let encryption_key = EncryptionKey([0xabu8; 32]);
/// // Seal the plaintext
Expand All @@ -90,8 +90,8 @@ impl AesGcm256 {
///
/// # Examples
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
/// let secret = "super secret data";
/// let encryption_key = EncryptionKey([0xabu8; 32]);
/// // Seal the plaintext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ mod prepare_data;
mod read_write_data;
mod save_pdf_location_to_tmp_file;
mod send_email;
mod serde_to_typst;

pub use calendar_logic::*;
pub use command::*;
Expand All @@ -20,4 +19,3 @@ pub use prepare_data::*;
pub use read_write_data::*;
pub use save_pdf_location_to_tmp_file::*;
pub use send_email::*;
pub use serde_to_typst::*;
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ mod tests {

use httpmock::Method::GET;
use httpmock::MockServer;
use std::panic::{self, AssertUnwindSafe};

#[derive(Debug, Deserialize, PartialEq)]
struct MyData {
Expand Down Expand Up @@ -317,9 +318,18 @@ mod tests {
assert!(rate.is_ok());
}

fn start_mock_server() -> Option<MockServer> {
panic::catch_unwind(AssertUnwindSafe(MockServer::start)).ok()
}

#[test]
fn test_successful_deserialization() {
let server = MockServer::start();
let Some(server) = start_mock_server() else {
eprintln!(
"Skipping test_successful_deserialization: unable to start mock server in sandbox"
);
return;
};

let mock = server.mock(|when, then| {
when.method(GET).path("/test");
Expand All @@ -345,7 +355,10 @@ mod tests {

#[test]
fn test_json_parse_error() {
let server = MockServer::start();
let Some(server) = start_mock_server() else {
eprintln!("Skipping test_json_parse_error: unable to start mock server in sandbox");
return;
};

server.mock(|when, then| {
when.method(GET).path("/badjson");
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ impl<Period: IsPeriod> Data<Period> {
/// Returns an error if the invoice information is invalid.
/// # Examples
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
/// let data = Data::<YearAndMonth>::sample();
/// let result = data.validate();
/// assert!(result.is_ok(), "Expected validation to succeed, got: {:?}", result);
Expand Down Expand Up @@ -77,8 +77,8 @@ impl<Period: IsPeriod> Data<Period> {
/// retrieving expenses for the month.
/// # Examples
/// ```
/// extern crate klirr_core;
/// use klirr_core::prelude::*;
/// extern crate klirr_core_invoice;
/// use klirr_core_invoice::prelude::*;
/// let data = Data::<YearAndMonth>::sample();
/// let input = ValidInput::sample();
/// let result = data.to_partial(input);
Expand Down
Loading
Loading