Skip to content

refactor(rrule): centralize Temporal rule creation#529

Merged
jens-maus merged 2 commits into
jens-maus:masterfrom
KristjanESPERANTO:temporal
Jul 20, 2026
Merged

refactor(rrule): centralize Temporal rule creation#529
jens-maus merged 2 commits into
jens-maus:masterfrom
KristjanESPERANTO:temporal

Conversation

@KristjanESPERANTO

@KristjanESPERANTO KristjanESPERANTO commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

I noticed the RRULE building logic was spread across three chained calls at the use site (DTSTART embedding, rule string prep, Temporal wrapper), so I pulled it into one createTemporalRule() function to make it easier to follow. Export surface shrinks from six internal helpers to one.

Summary by CodeRabbit

  • Bug Fixes
    • Improved recurrence rule handling for calendar events, including more reliable conversion and normalization when processing temporal recurrence data.
    • Preserved exact local midnight for recurring all-day events using DTSTART;VALUE=DATE, including when expanding occurrences.
  • Tests
    • Added a regression test covering daily recurring all-day events with DTSTART;VALUE=DATE, verifying each expanded occurrence retains zeroed time components.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fb6aa5d8-e56f-41be-8f31-a12457f0661a

📥 Commits

Reviewing files that changed from the base of the PR and between 47f7fbe and d01e4b2.

📒 Files selected for processing (2)
  • lib/ical-parser-utils.js
  • test/regression-fixes.test.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/regression-fixes.test.js
  • lib/ical-parser-utils.js

📝 Walkthrough

Walkthrough

Recurrence rule construction is centralized in the exported createTemporalRule helper. Component finalization delegates RRULE creation to it, and regression coverage verifies that date-only recurring events remain at local midnight.

Changes

Temporal rule construction

Layer / File(s) Summary
Temporal rule helper
lib/ical-parser-utils.js
Adds and exports createTemporalRule, removes the replaced helper exports, validates the start value, strips milliseconds, normalizes the RRULE, and creates the compatibility wrapper.
Recurrence finalization integration
ical.js
Replaces the previous multi-step RRULE construction in the END handler with a call to createTemporalRule.
Date-only recurrence regression coverage
test/regression-fixes.test.js
Verifies that a VALUE=DATE event and all expanded daily occurrences remain at 00:00:00.000.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: consolidating RRULE creation into a single Temporal-based helper.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
lib/ical-parser-utils.js (2)

579-579: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix the variable name in the error message.

The parameter is named entry, but the error message references curr (likely a leftover from when this logic was inline in ical.js).

🔨 Proposed fix
-    throw new Error('No toISOString function in curr.start ' + entry.start);
+    throw new Error('No toISOString function in entry.start ' + entry.start);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/ical-parser-utils.js` at line 579, Update the error message in the
surrounding parser logic to reference the existing entry.start value instead of
curr.start, keeping the “No toISOString function” error behavior unchanged.

582-584: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the redundant ensureRruleHasDtstart call.

This block is effectively dead code. The buildRruleStringForTemporal function invoked on line 586 explicitly filters out any segments starting with DTSTART, VALUE=, or TZID=. As a result, the DTSTART segment appended by ensureRruleHasDtstart is immediately discarded.

Unless this call is relied upon for hidden side effects, it can be safely removed.

♻️ Proposed refactor
-  if (entry.start.dateOnly) {
-    rule = ensureRruleHasDtstart(rule, entry, tzUtil);
-  }
-
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/ical-parser-utils.js` around lines 582 - 584, Remove the
ensureRruleHasDtstart call and its surrounding entry.start.dateOnly conditional
from the rule-building flow before buildRruleStringForTemporal, leaving the
existing rule processing unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/ical-parser-utils.js`:
- Line 586: Update the regular expression in the rruleOnly construction to
remove the unsupported v flag and use the g flag, ensuring every three-digit
millisecond fragment is removed without causing load-time failures in older
Node.js environments.

---

Nitpick comments:
In `@lib/ical-parser-utils.js`:
- Line 579: Update the error message in the surrounding parser logic to
reference the existing entry.start value instead of curr.start, keeping the “No
toISOString function” error behavior unchanged.
- Around line 582-584: Remove the ensureRruleHasDtstart call and its surrounding
entry.start.dateOnly conditional from the rule-building flow before
buildRruleStringForTemporal, leaving the existing rule processing unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 156db305-5342-4da1-9a1d-fb3097246982

📥 Commits

Reviewing files that changed from the base of the PR and between 9c6d962 and e5277ed.

📒 Files selected for processing (2)
  • ical.js
  • lib/ical-parser-utils.js

Comment thread lib/ical-parser-utils.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
test/regression-fixes.test.js (1)

515-517: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Check all time components to strictly assert exact local midnight.

The test description specifies "exact local midnight", and event.start is thoroughly checked for minutes, seconds, and milliseconds. However, the loop only checks that the occurrence's hour is 0. Consider checking all time components to ensure no fractional offsets are introduced.

♻️ Proposed fix
     for (const occurrence of occurrences) {
       assert.equal(occurrence.getHours(), 0, `occurrence ${occurrence.toISOString()} should stay at local midnight`);
+      assert.equal(occurrence.getMinutes(), 0);
+      assert.equal(occurrence.getSeconds(), 0);
+      assert.equal(occurrence.getMilliseconds(), 0);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/regression-fixes.test.js` around lines 515 - 517, Update the occurrence
assertions in the regression test loop to verify exact local midnight: assert
hours are 0 and also minutes, seconds, and milliseconds are 0, matching the
existing event.start checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/regression-fixes.test.js`:
- Around line 515-517: Update the occurrence assertions in the regression test
loop to verify exact local midnight: assert hours are 0 and also minutes,
seconds, and milliseconds are 0, matching the existing event.start checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12cb4e47-4508-4b0f-8cce-bf483d4528b5

📥 Commits

Reviewing files that changed from the base of the PR and between e5277ed and 47f7fbe.

📒 Files selected for processing (2)
  • lib/ical-parser-utils.js
  • test/regression-fixes.test.js

@KristjanESPERANTO

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@jens-maus
jens-maus merged commit 1b72a38 into jens-maus:master Jul 20, 2026
14 checks passed
@KristjanESPERANTO
KristjanESPERANTO deleted the temporal branch July 20, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants