refactor(08-02): tighten ical.d.ts shim and fix 4 non-ambient any sites

- ical.d.ts: getValues() return tightened to Array<Time | Duration |
  string> (Amendment A2); add Property.jCal: unknown[] to codify the
  internal access used at CalendarService.ts:940 and IcsImportService.ts:101
- eslint.config.mjs: add **/*.d.ts no-explicit-any: off exclusion (D-08)
- CalendarService.ts:317 — isValidCache(cache: unknown) with the
  canonical narrowing from RESEARCH.md Pitfall 3 (Record<string, unknown>
  intermediate + typeof/Array.isArray checks)
- CalendarService.ts:771 — forEach((value: Time | Duration | string))
  via tightened getValues(); narrow via value instanceof Time
- CalendarService.ts:940 — (dtstart as any).jCal -> dtstart.jCal via shim
- IcsImportService.ts:101 — same
- SettingsTab.ts:1180 — generatePreviewPath(event: Pick<CalendarEvent,
  'title' | 'start' | 'end' | 'source'>)
This commit is contained in:
formax68 2026-05-17 09:32:23 +03:00
parent 0d27d263b1
commit 413b6f3bfc
5 changed files with 25 additions and 9 deletions

View file

@ -62,6 +62,14 @@ export default tseslint.config(
},
},
// D-08 — Ambient .d.ts shims are excluded from no-explicit-any. Hand-typing
// untyped third-party libraries (ical.js) is out of scope; the cheapest
// correct close per CONTEXT.md D-08.
{
files: ["**/*.d.ts"],
rules: { "@typescript-eslint/no-explicit-any": "off" },
},
// ---------------------------------------------------------------------------
// Phase 8 — DIR-01 / DIR-09 / DIR-10 will remove these when type-hygiene
// and console-discipline land.

View file

@ -1,5 +1,5 @@
import { requestUrl, Platform, Notice, TFile } from "obsidian";
import { Component, Event as ICalEvent, parse, Time } from "ical.js";
import { Component, Duration, Event as ICalEvent, parse, Time } from "ical.js";
import { CalendarSource } from "../settings/types";
import MemoChron from "../main";
import {
@ -314,9 +314,12 @@ export class CalendarService {
return JSON.parse(cacheFile);
}
private isValidCache(cache: any): cache is CacheData {
private isValidCache(cache: unknown): cache is CacheData {
if (!cache || typeof cache !== "object") return false;
const c = cache as Record<string, unknown>;
return (
cache && cache.timestamp && cache.events && Array.isArray(cache.events)
typeof c.timestamp === "number" &&
Array.isArray(c.events)
);
}
@ -768,8 +771,8 @@ export class CalendarService {
const exdateProps = vevent.getAllProperties("exdate");
for (const exdateProp of exdateProps) {
const values = exdateProp.getValues();
values.forEach((value: any) => {
if (value?.toJSDate) {
values.forEach((value: Time | Duration | string) => {
if (value instanceof Time) {
excludedDates.push(value.toJSDate());
}
});
@ -937,7 +940,7 @@ export class CalendarService {
// Also check if the type is 'date' in the jCal representation
// This handles cases where ical.js represents date-only values differently
const jcal = (dtstart as any).jCal;
const jcal = dtstart.jCal;
if (jcal && jcal[2] === "date") return true;
return false;

View file

@ -97,7 +97,7 @@ export class IcsImportService {
// Also check if the type is 'date' in the jCal representation
// This handles cases where ical.js represents date-only values differently
const jcal = (dtstart as any).jCal;
const jcal = dtstart.jCal;
if (jcal && jcal[2] === "date") return true;
return false;

View file

@ -12,6 +12,7 @@ import {
} from "obsidian";
import MemoChron from "../main";
import { CalendarSource } from "./types";
import { CalendarEvent } from "../services/CalendarService";
import { isValidColor } from "../utils/colorValidation";
import { errorMessage } from "../utils/errors";
@ -1177,7 +1178,10 @@ export class SettingsTab extends PluginSettingTab {
}
}
private generatePreviewPath(template: string, event: any): string {
private generatePreviewPath(
template: string,
event: Pick<CalendarEvent, "title" | "start" | "end" | "source">
): string {
const monthNames = [
"January",
"February",

3
src/types/ical.d.ts vendored
View file

@ -11,7 +11,8 @@ declare module "ical.js" {
export class Property {
getFirstValue(): any;
getParameter(name: string): string;
getValues(): any[];
getValues(): Array<Time | Duration | string>;
jCal: unknown[];
}
export class Event {