Skip to content

Instantly share code, notes, and snippets.

@WomB0ComB0
Created January 24, 2025 20:12
Show Gist options
  • Save WomB0ComB0/1713769f4eea4390572daec45e8eb54c to your computer and use it in GitHub Desktop.
Save WomB0ComB0/1713769f4eea4390572daec45e8eb54c to your computer and use it in GitHub Desktop.
Simple ICS file parser
/**
* A script to parse ICS (iCalendar) files and convert them to JSON format.
* Supports processing either a single file or scanning a directory for multiple .ics files.
*
* @module ics-parser
*
* Usage:
* - Process single file: node ics-parser.ts path/to/file.ics
* - Process all .ics files in root: node ics-parser.ts --root
*
* @requires icalts - For parsing ICS file content into object tree
* @requires bun - For file operations and shell commands
*/
import { lines2tree } from 'icalts';
import { $ } from 'bun';
/**
* Processes one or more ICS files and converts them to JSON format.
* When processing multiple files, it will skip node_modules and .git directories.
* The output JSON files will be saved in the same location as the input files.
*
* @async
* @param {string} filePath - Path to a single .ics file, or directory path when useRoot is true
* @param {boolean} [useRoot=false] - When true, searches recursively from current directory for .ics files
* @returns {Promise<void>} Resolves when all files have been processed
* @throws {Error} If file reading or writing operations fail
*
* @example
* // Process a single file
* await processICSFiles('./calendar.ics');
*
* @example
* // Process all .ics files in root directory
* await processICSFiles('./', true);
*/
async function processICSFiles(filePath: string, useRoot = false): Promise<void> {
try {
let icsFiles;
if (useRoot) {
// Search for .ics files in the root directory, excluding node_modules and .git
icsFiles = (await $`find . -type d \( -name 'node_modules' -o -name '.git' \) -prune -o -type f -name '*.ics' -print`.text())
.split('\n')
.filter(Boolean);
} else {
// Use the provided file path
icsFiles = [filePath];
}
if (icsFiles.length === 0) {
console.error('No .ics files found.');
return;
}
for (const file of icsFiles) {
const content = await Bun.file(file).text();
const tree = lines2tree(content.split('\n'));
console.log(`Processed file: ${file}`);
console.log(tree);
const outputFilePath = file.replace(/\.ics$/, '.json');
await Bun.write(outputFilePath, JSON.stringify(tree, null, 2));
console.log(`JSON saved to: ${outputFilePath}`);
}
} catch (error) {
console.error('Error processing .ics files:', error);
}
}
// Parse command line arguments
const args = process.argv.slice(2);
const useRoot = args.includes('--root');
const filePath = args.find(arg => !arg.startsWith('--'));
// Validate arguments and execute
if (!filePath && !useRoot) {
console.error('Please provide a file path or use the --root flag to search in the root directory.');
process.exit(1);
} else {
(async () => {
await processICSFiles(filePath!, useRoot);
})();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment