Compare commits

...

14 Commits

Author SHA1 Message Date
c9a703975d chore: Bump version to 0.3.32
All checks were successful
Build SilverBullet Plug / build (push) Successful in 49s
2026-02-20 13:49:14 -08:00
842586c129 chore(conductor): Mark track 'Fix RRULE UNTIL conversion' as complete 2026-02-20 13:49:14 -08:00
c6532e5aca conductor(plan): Mark phase 'Verification & Cleanup' as complete 2026-02-20 13:49:14 -08:00
42fb8be61c conductor(checkpoint): Checkpoint end of Phase 3 2026-02-20 13:49:14 -08:00
f8a6fbafda conductor(plan): Mark regression check as complete 2026-02-20 13:49:14 -08:00
dbc7ef29aa conductor(plan): Mark phase 'Fix Implementation' as complete 2026-02-20 13:49:14 -08:00
7edc0997b2 conductor(checkpoint): Checkpoint end of Phase 2 2026-02-20 13:49:14 -08:00
c3fd3aee20 conductor(plan): Mark fix implementation task as complete 2026-02-20 13:49:14 -08:00
e5b063269f fix(icalendar): Correctly format nested objects (dates) in RRULE properties 2026-02-20 13:49:14 -08:00
31ca364a7c conductor(plan): Mark phase 'Reproduction' as complete 2026-02-20 13:49:14 -08:00
e7c69aa3f7 conductor(checkpoint): Checkpoint end of Phase 1 2026-02-20 13:49:14 -08:00
255988e6f3 conductor(plan): Mark reproduction task as complete 2026-02-20 13:49:14 -08:00
ada9f6694c test(icalendar): Add reproduction test for UNTIL object mismatch 2026-02-20 13:49:14 -08:00
cd0fdf5f98 chore(conductor): Add new track 'Fix RRULE UNTIL conversion' 2026-02-20 13:49:14 -08:00
10 changed files with 95 additions and 5 deletions

View File

@@ -1,6 +1,6 @@
---
name: Library/sstent/icalendar
version: "0.3.31"
version: "0.3.32"
tags: meta/library
files:
- icalendar.plug.js

View File

@@ -16,3 +16,8 @@ This file tracks all major tracks for the project. Each track has its own detail
- [x] **Track: Fix RRULE object expansion error by correctly mapping object keys to standard iCalendar RRULE properties.**
*Link: [./tracks/fix_rrule_object_mapping_20260219/](./tracks/fix_rrule_object_mapping_20260219/)*
---
- [x] **Track: Fix RRULE UNTIL object conversion error: Invalid UNTIL value: [object Object]**
*Link: [./tracks/fix_rrule_until_conversion_20260219/](./tracks/fix_rrule_until_conversion_20260219/)*

View File

@@ -0,0 +1,5 @@
# Track fix_rrule_until_conversion_20260219 Context
- [Specification](./spec.md)
- [Implementation Plan](./plan.md)
- [Metadata](./metadata.json)

View File

@@ -0,0 +1,8 @@
{
"track_id": "fix_rrule_until_conversion_20260219",
"type": "bug",
"status": "new",
"created_at": "2026-02-19T00:00:00Z",
"updated_at": "2026-02-19T00:00:00Z",
"description": "Fix RRULE UNTIL object conversion error: Invalid UNTIL value: [object Object]"
}

View File

@@ -0,0 +1,19 @@
# Implementation Plan - Fix RRULE UNTIL Conversion
## Phase 1: Reproduction [checkpoint: 02fcb7e]
- [x] Task: Reproduce `Invalid UNTIL value` error 17de604
- [x] Add a test case in `icalendar_test.ts` where `rrule` object has an `until` property as a `Date`.
- [x] Run the test and confirm it fails with `Error: Invalid UNTIL value: [object Object]`.
- [x] Task: Conductor - User Manual Verification 'Reproduction' (Protocol in workflow.md)
## Phase 2: Fix Implementation [checkpoint: 0f334b2]
- [x] Task: Implement value formatting logic in `icalendar.ts` 331d0ab
- [x] Update `expandRecurrences` to use a helper for property value conversion.
- [x] Ensure `Date` objects are formatted as `YYYYMMDDTHHMMSSZ`.
- [x] Run the test to confirm it passes.
- [x] Task: Conductor - User Manual Verification 'Fix Implementation' (Protocol in workflow.md)
## Phase 3: Verification & Cleanup [checkpoint: a02f228]
- [x] Task: Full Regression Check d090334
- [x] Run all tests in `icalendar_test.ts`.
- [x] Task: Conductor - User Manual Verification 'Verification & Cleanup' (Protocol in workflow.md)

View File

@@ -0,0 +1,20 @@
# Specification: Fix RRULE UNTIL Object Conversion
## Overview
The conversion of RRULE objects to strings fails for nested objects like `UNTIL` dates, resulting in `UNTIL=[object Object]`. This causes the `rrule` library to fail during expansion.
## Functional Requirements
- **Robust Value Formatting:** Implement `formatRRuleValue` to handle various types of RRULE values:
- **Date Objects:** Convert to `YYYYMMDDTHHMMSSZ`.
- **Nested Date Objects:** (e.g., `{ date: Date }` from `ts-ics`) Extract and convert.
- **Other Types:** Default to string conversion.
- **Mapping Preservation:** Maintain the existing `RRULE_KEY_MAP` for key translation.
## Implementation Steps
1. **Reproduce:** Add test `expandRecurrences - object rrule with until` in `icalendar_test.ts` using a Date object for `until`. Verify it fails with `Invalid UNTIL value`.
2. **Fix:** Update `expandRecurrences` in `icalendar.ts` to use a formatting helper for values.
3. **Verify:** Confirm the test case passes.
## Acceptance Criteria
- [ ] Test `expandRecurrences - object rrule with until` passes.
- [ ] The generated string correctly represents the date (e.g., `UNTIL=20260219T000000Z`).

View File

@@ -1,6 +1,6 @@
{
"name": "icalendar-plug",
"version": "0.3.31",
"version": "0.3.32",
"nodeModulesDir": "auto",
"tasks": {
"sync-version": "deno run -A scripts/sync-version.ts",

View File

@@ -1,5 +1,5 @@
name: icalendar
version: 0.3.31
version: 0.3.32
author: sstent
index: icalendar.ts
# Legacy SilverBullet permission name

View File

@@ -3,7 +3,7 @@ import { convertIcsCalendar } from "https://esm.sh/ts-ics@2.4.0";
import { RRule, RRuleSet } from "rrule";
import { getUtcOffsetMs, resolveIanaName } from "./timezones.ts";
const VERSION = "0.3.31";
const VERSION = "0.3.32";
const CACHE_KEY = "icalendar:lastSync";
console.log(`[iCalendar] Plug script executing at top level (Version ${VERSION})`);
@@ -29,6 +29,20 @@ const RRULE_KEY_MAP: Record<string, string> = {
"freq": "FREQ", // Just in case
};
/**
* Formats an RRULE value for the string representation.
* Specifically handles Date objects and nested date objects from ts-ics.
*/
function formatRRuleValue(v: any): string {
if (v instanceof Date) {
return v.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z";
}
if (typeof v === "object" && v !== null && v.date instanceof Date) {
return v.date.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z";
}
return String(v);
}
// ============================================================================
// Utility Functions
// ============================================================================
@@ -186,7 +200,7 @@ export function expandRecurrences(icsEvent: any, windowDays = 365): any[] {
cleanRule = Object.entries(rruleStr)
.map(([k, v]) => {
const standardKey = RRULE_KEY_MAP[k.toLowerCase()] || k.toUpperCase();
return `${standardKey}=${v}`;
return `${standardKey}=${formatRRuleValue(v)}`;
})
.join(";");
} else {

View File

@@ -206,3 +206,22 @@ Deno.test("expandRecurrences - object rrule (Reproduction of missing events)", (
assert(!warningLogged, "Should NOT have logged a warning for object rrule");
});
Deno.test("expandRecurrences - object rrule with until", () => {
const now = new Date();
const start = new Date(now.getTime() - 10 * 86400000);
const startStr = localDateString(start);
const untilDate = new Date(now.getTime() + 10 * 86400000);
const icsEvent = {
summary: "Object RRULE UNTIL Event",
start: startStr,
rrule: { frequency: "DAILY", until: { date: untilDate } }
};
const results = expandRecurrences(icsEvent, 30);
// Should now return multiple occurrences
assert(results.length > 1, `Expected > 1 occurrences, got ${results.length}`);
assertEquals(results[0].recurrent, true);
});