{"id":13317,"library":"ical-expander","title":"iCal Expander","description":"ical-expander is a JavaScript/TypeScript library designed for parsing and expanding iCalendar (ICS) data. It acts as a wrapper around the `ical.js` library, simplifying the complexities of recurring events by automatically handling `EXDATE` (excluded occurrences), `RRULE` (recurrence rules), and `RECURRENCE-ID` (overridden instances). The package also incorporates timezone definitions from the IANA Time Zone Database, ensuring correct parsing even when timezone information is absent from the ICS file itself. The current stable version is 3.2.0, with a release cadence that indicates active maintenance and incremental improvements, such as recent updates to timezone data and fixes related to `ical.js` versions. A key consideration is its synchronous processing model, which can block the JavaScript event loop when dealing with large ICS files or high `maxIterations` values, requiring careful usage, particularly in performance-sensitive applications. Its primary differentiator is abstracting away the intricacies of `ical.js` for common expansion tasks.","status":"active","version":"3.2.0","language":"javascript","source_language":"en","source_url":"https://github.com/mifi/ical-expander","tags":["javascript","typescript"],"install":[{"cmd":"npm install ical-expander","lang":"bash","label":"npm"},{"cmd":"yarn add ical-expander","lang":"bash","label":"yarn"},{"cmd":"pnpm add ical-expander","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core parsing logic; ical-expander is a wrapper around this library for enhanced recurrence handling and timezone support.","package":"ical.js","optional":false}],"imports":[{"note":"The primary class `IcalExpander` is a named export, not a default export.","wrong":"import IcalExpander from 'ical-expander';","symbol":"IcalExpander","correct":"import { IcalExpander } from 'ical-expander';"},{"note":"In CommonJS environments, the module export is directly the IcalExpander class, not an object containing it.","wrong":"const { IcalExpander } = require('ical-expander');","symbol":"IcalExpander (CommonJS)","correct":"const IcalExpander = require('ical-expander');"},{"note":"Explicit type import for TypeScript for better tree-shaking and clarity, though `import { IcalExpander } from 'ical-expander';` works for both value and type.","symbol":"IcalExpander (TypeScript Type)","correct":"import type { IcalExpander } from 'ical-expander';"}],"quickstart":{"code":"const IcalExpander = require('ical-expander');\nconst fs = require('fs');\n\n// Assuming 'basic.ics' exists in the same directory\nconst ics = fs.readFileSync('./basic.ics', 'utf-8');\n\nconst icalExpander = new IcalExpander({ ics, maxIterations: 100 });\nconst events = icalExpander.between(\n  new Date('2017-01-24T00:00:00.000Z'),\n  new Date('2017-03-30T00:00:00.000Z')\n);\n\nconst mappedEvents = events.events.map(e => ({\n  startDate: e.startDate.toJSDate().toISOString(), // Convert to JS Date and then ISO string\n  summary: e.summary\n}));\nconst mappedOccurrences = events.occurrences.map(o => ({\n  startDate: o.startDate.toJSDate().toISOString(), // Convert to JS Date and then ISO string\n  summary: o.item.summary\n}));\nconst allEvents = [].concat(mappedEvents, mappedOccurrences);\n\nconsole.log(allEvents.map(e => `${e.startDate} - ${e.summary}`).join('\\n'));","lang":"javascript","description":"This example demonstrates how to load an ICS file, parse it using IcalExpander, and then retrieve all events and occurrences within a specified date range, logging their start dates and summaries."},"warnings":[{"fix":"For large ICS files, consider processing in a worker thread (e.g., Worker Threads in Node.js, Web Workers in browsers) to offload the synchronous work from the main thread. Keep `maxIterations` to a reasonable, bounded value.","message":"The library performs synchronous processing, which can block the JavaScript event loop. This is particularly problematic when parsing very large ICS files or setting a high `maxIterations` value.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always provide a finite, reasonable `maxIterations` value (default is 1000). Only set to `0` if you are absolutely certain of the ICS file's structure and performance implications, and can implement external timeouts.","message":"Using `maxIterations: 0` in the constructor disables the iteration limit, which can lead to infinite loops or extremely long processing times for complex or malformed recurrence rules.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Configure your build tools (e.g., Babel, Webpack) to transpile `node_modules/ical-expander` if necessary for your target environments.","message":"This package uses ES6 features. If targeting environments that do not fully support ES6 (e.g., older browsers), you might need to transpile `ical-expander` along with your application code.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Thoroughly test your application's event parsing logic after upgrading to `3.0.0` or later, especially for calendars containing events with modified recurring instances (`RECURRENCE-ID`).","message":"Version 3.0.0 introduced an update to `ical.js` to correctly handle modified recurrences. This change, while fixing previous bugs, might alter the output for specific edge cases involving `RECURRENCE-ID` if your application relied on the prior (potentially incorrect) behavior.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"If your application is sensitive to precise timezone interpretations, verify event parsing for critical dates and timezones after upgrading to `3.1.0` or later.","message":"Version 3.1.0 included an update to the IANA timezone data (`zones` and `zones-compiled`). While typically an improvement, this could subtly change the interpretation of timezones for certain events, especially those at daylight saving time boundaries or in historically complex timezones.","severity":"gotcha","affected_versions":">=3.1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"For ESM/TypeScript: `import { IcalExpander } from 'ical-expander';`. For CommonJS: `const IcalExpander = require('ical-expander');`.","cause":"Incorrect import statement; `IcalExpander` is a named export, not a default export in ESM, and directly exported in CJS.","error":"TypeError: IcalExpander is not a constructor"},{"fix":"Ensure the ICS content is valid. Add checks for `events.events` and `events.occurrences` being defined before attempting to map them, e.g., `(events.events || []).map(...)`.","cause":"This usually happens when `events.events` or `events.occurrences` are undefined, which can occur if the `between()` method returns an unexpected structure, possibly due to a malformed ICS or an empty result set that wasn't properly handled.","error":"TypeError: Cannot read properties of undefined (reading 'map')"},{"fix":"Reduce `maxIterations` to a reasonable value. For very large files, process the ICS data in a Web Worker (browser) or Worker Thread (Node.js) to avoid blocking the main event loop.","cause":"The synchronous nature of `ical-expander` blocks the main thread, especially with large ICS files or when `maxIterations` is set very high (or to `0`).","error":"Application becomes unresponsive or hangs when parsing ICS files."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":"","cli_version":null}