Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: convert Rust errors into JS errors #18

Merged
merged 1 commit into from
Dec 24, 2023
Merged
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
72 changes: 72 additions & 0 deletions __test__/parsing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,75 @@ test('Should properly parse monthly recurrence', () => {
'DTSTART;TZID=US/Eastern:19970907T090000\nFREQ=monthly;COUNT=10;INTERVAL=2;BYHOUR=9;BYMINUTE=0;BYSECOND=0;BYDAY=-1SU,SU',
);
});

test('Should throw error on missing start date', () => {
expect(() => RRuleSet.parse('Invalid')).toThrowErrorMatchingInlineSnapshot(
`"RRule parsing error: Missing start date. There needs to be a unique start date which the iteration can start from."`,
);
});

test('Should throw error on invalid timezone', () => {
expect(() =>
RRuleSet.parse('DTSTART;TZID=Invalid:19970907T090000'),
).toThrowErrorMatchingInlineSnapshot(
`"RRule parsing error: \`Invalid\` is not a valid timezone."`,
);
});

test('Should throw error on invalid recurrence rule', () => {
expect(() =>
RRuleSet.parse('DTSTART;TZID=US/Eastern:19970907T090000\nRRULE:Invalid'),
).toThrowErrorMatchingInlineSnapshot(
`"RRule parsing error: \`Invalid\` is a malformed property parameter. Parameter should be specified as \`key=value\`"`,
);
});

test('Should throw error on invalid frequency', () => {
expect(() =>
RRuleSet.parse(
'DTSTART;TZID=US/Eastern:19970907T090000\nRRULE:FREQ=Invalid',
),
).toThrowErrorMatchingInlineSnapshot(
`"RRule parsing error: \`INVALID\` is not a valid frequency."`,
);
});

test('Should throw error on invalid interval', () => {
expect(() =>
RRuleSet.parse(
'DTSTART;TZID=US/Eastern:19970907T090000\nRRULE:FREQ=DAILY;INTERVAL=Invalid',
),
).toThrowErrorMatchingInlineSnapshot(
`"RRule parsing error: \`Invalid\` is not a valid INTERVAL value."`,
);
});

test('Should throw error on invalid count', () => {
expect(() =>
RRuleSet.parse(
'DTSTART;TZID=US/Eastern:19970907T090000\nRRULE:FREQ=DAILY;COUNT=Invalid',
),
).toThrowErrorMatchingInlineSnapshot(
`"RRule parsing error: \`Invalid\` is not a valid COUNT value."`,
);
});

test('Should throw error on invalid until', () => {
expect(() =>
RRuleSet.parse(
'DTSTART;TZID=US/Eastern:19970907T090000\nRRULE:FREQ=DAILY;UNTIL=Invalid',
),
).toThrowErrorMatchingInlineSnapshot(
`"RRule parsing error: \`Invalid\` is not a valid datetime format for \`UNTIL\`."`,
);
});

test('Should throw error on invalid week start', () => {
expect(() =>
RRuleSet.parse(
'DTSTART;TZID=US/Eastern:19970907T090000\nRRULE:FREQ=DAILY;WKST=Invalid',
),
).toThrowErrorMatchingInlineSnapshot(
`"RRule parsing error: \`Invalid\` is not a valid weekday start. Valid values are \`MO\`, \`TU\`, \`WE\`, \`TH\`, \`FR\`, \`SA\` and \`SU\`."`,
);
});
42 changes: 21 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,15 @@ impl JsRRule {
#[napi(getter, ts_return_type = "Weekday[]")]
pub fn by_weekday(&self, env: Env) -> napi::Result<Array> {
let ndays = self.rrule.get_by_weekday();
let mut arr = env.create_array(0).unwrap();
let mut arr = env.create_array(0)?;

for nday in ndays.iter() {
let day = match nday {
NWeekday::Every(day) => *day,
_ => panic!("Unsupported"),
};

arr.insert(map_rust_weekday(day)).unwrap();
arr.insert(map_rust_weekday(day))?;
}

Ok(arr)
Expand Down Expand Up @@ -120,10 +120,10 @@ impl JsRRule {
#[napi(getter, ts_return_type = "Month[]")]
pub fn by_month(&self, env: Env) -> napi::Result<Array> {
let months = self.rrule.get_by_month();
let mut arr = env.create_array(0).unwrap();
let mut arr = env.create_array(0)?;

for month in months.iter() {
arr.insert(map_rust_month(month)).unwrap();
arr.insert(map_rust_month(month))?;
}

Ok(arr)
Expand Down Expand Up @@ -296,8 +296,8 @@ impl JsRRule {
Ok(self)
}

pub fn validate(&self, dt_start: DateTime<Tz>) -> RRule {
self.rrule.clone().validate(dt_start).unwrap()
pub fn validate(&self, dt_start: DateTime<Tz>) -> napi::Result<RRule> {
return Ok(self.rrule.clone().validate(dt_start).map_err(|e| napi::Error::new(napi::Status::GenericFailure, e))?);
}
}

Expand All @@ -310,21 +310,21 @@ pub struct JsRRuleSet {
#[napi]
impl JsRRuleSet {
#[napi(constructor)]
pub fn new(dtstart: i64, tzid: String) -> Self {
let tz = map_js_tz(&tzid);
pub fn new(dtstart: i64, tzid: String) -> napi::Result<Self> {
let tz = map_js_tz(&tzid)?;
let date = timestamp_to_date_with_tz(dtstart, &tz);
let rrule_set = RRuleSet::new(date);

JsRRuleSet { rrule_set, tz }
Ok(JsRRuleSet { rrule_set, tz })
}

#[napi(factory, ts_return_type = "RRuleSet")]
pub fn parse(str: String) -> Self {
let rrule_set: RRuleSet = str.parse().unwrap();
pub fn parse(str: String) -> napi::Result<Self> {
let rrule_set: RRuleSet = str.parse().map_err(|e| napi::Error::new(napi::Status::GenericFailure, e))?;
let dtstart = rrule_set.get_dt_start();
let tz = dtstart.timezone();

JsRRuleSet { rrule_set, tz }
Ok(JsRRuleSet { rrule_set, tz })
}

#[napi]
Expand All @@ -335,7 +335,7 @@ impl JsRRuleSet {
#[napi]
pub fn add_rrule(&mut self, js_rrule: &JsRRule) -> napi::Result<&Self> {
let dt_start = self.rrule_set.get_dt_start().clone();
let rrule = js_rrule.validate(dt_start);
let rrule = js_rrule.validate(dt_start)?;

replace_with_or_abort(&mut self.rrule_set, |self_| self_.rrule(rrule));

Expand All @@ -344,7 +344,7 @@ impl JsRRuleSet {

#[napi]
pub fn add_exrule(&mut self, js_rrule: &JsRRule) -> napi::Result<&Self> {
let rrule = js_rrule.validate(*self.rrule_set.get_dt_start());
let rrule = js_rrule.validate(*self.rrule_set.get_dt_start())?;

replace_with_or_abort(&mut self.rrule_set, |self_| self_.exrule(rrule));

Expand Down Expand Up @@ -410,7 +410,7 @@ impl JsRRuleSet {

#[napi(ts_return_type = "number[]")]
pub fn all(&self, env: Env, limit: Option<u32>) -> napi::Result<Array> {
let mut arr = env.create_array(0).unwrap();
let mut arr = env.create_array(0)?;
let mut left = match limit {
Some(number) => number,
None => 0,
Expand All @@ -424,7 +424,7 @@ impl JsRRuleSet {
}

let timestamp = date.timestamp_millis();
arr.insert(timestamp).unwrap();
arr.insert(timestamp)?;
}

Ok(arr)
Expand All @@ -438,15 +438,15 @@ impl JsRRuleSet {
before: i64,
inclusive: Option<bool>,
) -> napi::Result<Array> {
let mut arr = env.create_array(0).unwrap();
let mut arr = env.create_array(0)?;

for date in self.rrule_set.into_iter() {
let timestamp = date.timestamp_millis();
let is_after = self.is_after(timestamp, after, inclusive);
let is_before = self.is_before(timestamp, before, inclusive);

if is_after && is_before {
arr.insert(timestamp).unwrap();
arr.insert(timestamp)?;
} else if !is_before {
break;
}
Expand Down Expand Up @@ -548,9 +548,9 @@ fn map_rust_month(month: &u8) -> JsMonth {
}
}

fn map_js_tz(tz: &str) -> Tz {
let chrono_tz = tz.parse().unwrap();
Tz::Tz(chrono_tz)
fn map_js_tz(tz: &str) -> napi::Result<Tz> {
let chrono_tz = tz.parse().map_err(|e| napi::Error::new(napi::Status::GenericFailure, e))?;
Ok(Tz::Tz(chrono_tz))
}

fn timestamp_to_date_with_tz(timestamp: i64, tz: &Tz) -> DateTime<Tz> {
Expand Down
Loading