Skip to content

Commit c653e7e

Browse files
greetclammyclaude
andcommitted
fix: Remove all any types and eslint-disable comments
- Replace `as any` casts with proper type assertions - Use `Record<string, unknown>` for dynamic property access - Define interfaces for undocumented Obsidian APIs (AppWithPlugins, WorkspaceWithSearchEvents, etc.) - Remove console.group/groupEnd (not allowed by Obsidian scanner) - Fix menu context types to use unknown with type guards - Add skipLibCheck to tsconfig for faster builds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 5e44188 commit c653e7e

File tree

12 files changed

+164
-111
lines changed

12 files changed

+164
-111
lines changed

main.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export default class FirstLineIsTitle extends Plugin {
177177
return;
178178
}
179179

180-
console.group("🔧 Settings (non-default values only)");
180+
console.debug("🔧 Settings (non-default values only):");
181181

182182
const nonDefaults: Record<string, unknown> = {};
183183

@@ -218,7 +218,6 @@ export default class FirstLineIsTitle extends Plugin {
218218

219219
if (Object.keys(nonDefaults).length === 0) {
220220
console.debug("All settings are at default values");
221-
console.groupEnd();
222221
return;
223222
}
224223

@@ -237,8 +236,6 @@ export default class FirstLineIsTitle extends Plugin {
237236
console.debug(`${key}:`, value);
238237
}
239238
}
240-
241-
console.groupEnd();
242239
}
243240

244241
async insertTitleOnCreation(file: TFile): Promise<void> {

manifest.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
2-
"id": "first-line-is-title",
3-
"name": "First Line is Title",
4-
"minAppVersion": "1.8.0",
5-
"description": "Automatically set the first line as note title.",
6-
"author": "greetclammy",
7-
"isDesktopOnly": false,
8-
"version": "3.10.0"
2+
"id": "first-line-is-title",
3+
"name": "First Line is Title",
4+
"minAppVersion": "1.8.0",
5+
"description": "Automatically set the first line as note title.",
6+
"author": "greetclammy",
7+
"isDesktopOnly": false,
8+
"version": "3.10.0"
99
}

src/core/event-handler-manager.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ import { RenameModal, DisableEnableModal } from "../modals";
1313
import { around } from "monkey-around";
1414
import { detectTagFromDOM, detectTagFromEditor } from "../utils/tag-detection";
1515

16+
/**
17+
18+
/**
19+
* Extended Workspace interface with undocumented search results event
20+
*/
21+
interface WorkspaceWithSearchEvents {
22+
on(
23+
name: "search:results-menu",
24+
callback: (menu: Menu, leaf: Record<string, unknown>) => void,
25+
): EventRef;
26+
}
27+
1628
/**
1729
* Manages all event handler registration for the First Line is Title plugin.
1830
* Centralizes event handler logic previously scattered in main.ts.
@@ -240,8 +252,7 @@ export class EventHandlerManager {
240252
*/
241253
private registerSearchResultsMenuHandler(): void {
242254
this.registerEvent(
243-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
244-
(this.plugin.app.workspace as any).on(
255+
(this.plugin.app.workspace as unknown as WorkspaceWithSearchEvents).on(
245256
"search:results-menu",
246257
(menu: Menu, leaf: Record<string, unknown>) => {
247258
if (!this.plugin.settings.core.enableVaultSearchContextMenu) return;

src/core/file-creation-coordinator.ts

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,27 @@
1-
import { TFile, getFrontMatterInfo } from "obsidian";
1+
import { TFile, getFrontMatterInfo, EventRef } from "obsidian";
22
import FirstLineIsTitlePlugin from "../../main";
33
import { verboseLog } from "../utils";
44

5+
/**
6+
* Extended App interface with plugin manager access
7+
*/
8+
interface AppWithPlugins {
9+
plugins?: {
10+
plugins?: Record<string, unknown>;
11+
};
12+
}
13+
14+
/**
15+
* Extended Workspace interface with custom events
16+
*/
17+
interface WorkspaceWithCustomEvents {
18+
on(
19+
name: "templater:new-note-from-template",
20+
callback: (data: Record<string, unknown>) => void,
21+
): EventRef;
22+
offref(ref: EventRef): void;
23+
}
24+
525
/**
626
* Context information for file creation decisions
727
*/
@@ -347,8 +367,8 @@ export class FileCreationCoordinator {
347367
*/
348368
private isTemplaterOn(): boolean {
349369
// Check if Templater plugin exists in app.plugins
350-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
351-
const templater = (this.plugin.app as any).plugins?.plugins;
370+
const templater = (this.plugin.app as unknown as AppWithPlugins).plugins
371+
?.plugins;
352372
return (
353373
templater !== undefined &&
354374
typeof templater === "object" &&
@@ -360,24 +380,22 @@ export class FileCreationCoordinator {
360380
* Node 5: Check if Templater's "Trigger on new file creation" is enabled
361381
*/
362382
private isTemplaterTriggerOn(): boolean {
363-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
364-
const templater = (this.plugin.app as any).plugins?.plugins?.[
365-
"templater-obsidian"
366-
];
383+
const templater = (this.plugin.app as unknown as AppWithPlugins).plugins
384+
?.plugins?.["templater-obsidian"] as Record<string, unknown> | undefined;
367385
if (!templater) return false;
368-
return templater.settings?.trigger_on_file_creation === true;
386+
const settings = templater.settings as Record<string, unknown> | undefined;
387+
return settings?.trigger_on_file_creation === true;
369388
}
370389

371390
/**
372391
* Node 6: Check if file path matches Templater's template folder location
373392
*/
374393
private isInTemplateFolder(file: TFile): boolean {
375-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
376-
const templater = (this.plugin.app as any).plugins?.plugins?.[
377-
"templater-obsidian"
378-
];
394+
const templater = (this.plugin.app as unknown as AppWithPlugins).plugins
395+
?.plugins?.["templater-obsidian"] as Record<string, unknown> | undefined;
379396
if (!templater) return false;
380-
const templateFolder = templater.settings?.templates_folder || "";
397+
const settings = templater.settings as Record<string, unknown> | undefined;
398+
const templateFolder = (settings?.templates_folder as string) || "";
381399

382400
if (!templateFolder || templateFolder === "/") return false;
383401

@@ -388,25 +406,23 @@ export class FileCreationCoordinator {
388406
* Node 7: Check if Templater's "Enable folder templates" is ON
389407
*/
390408
private isFolderTemplatesEnabled(): boolean {
391-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
392-
const templater = (this.plugin.app as any).plugins?.plugins?.[
393-
"templater-obsidian"
394-
];
409+
const templater = (this.plugin.app as unknown as AppWithPlugins).plugins
410+
?.plugins?.["templater-obsidian"] as Record<string, unknown> | undefined;
395411
if (!templater) return false;
396-
return templater.settings?.enable_folder_templates === true;
412+
const settings = templater.settings as Record<string, unknown> | undefined;
413+
return settings?.enable_folder_templates === true;
397414
}
398415

399416
/**
400417
* Node 9: Check if any Templater folder template matches current path
401418
* Uses Templater's walk-up algorithm (deepest match wins)
402419
*/
403420
private folderTemplateMatches(file: TFile): boolean {
404-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
405-
const templater = (this.plugin.app as any).plugins?.plugins?.[
406-
"templater-obsidian"
407-
];
421+
const templater = (this.plugin.app as unknown as AppWithPlugins).plugins
422+
?.plugins?.["templater-obsidian"] as Record<string, unknown> | undefined;
408423
if (!templater) return false;
409-
const folderTemplates = templater.settings?.folder_templates;
424+
const settings = templater.settings as Record<string, unknown> | undefined;
425+
const folderTemplates = settings?.folder_templates;
410426
if (!Array.isArray(folderTemplates)) return false;
411427

412428
let folder = file.parent;
@@ -436,24 +452,22 @@ export class FileCreationCoordinator {
436452
* Node 10: Check if Templater's "Enable file regex templates" is ON
437453
*/
438454
private isFileRegexEnabled(): boolean {
439-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
440-
const templater = (this.plugin.app as any).plugins?.plugins?.[
441-
"templater-obsidian"
442-
];
455+
const templater = (this.plugin.app as unknown as AppWithPlugins).plugins
456+
?.plugins?.["templater-obsidian"] as Record<string, unknown> | undefined;
443457
if (!templater) return false;
444-
return templater.settings?.enable_file_templates === true;
458+
const settings = templater.settings as Record<string, unknown> | undefined;
459+
return settings?.enable_file_templates === true;
445460
}
446461

447462
/**
448463
* Node 11: Check if any Templater file regex matches current path
449464
*/
450465
private fileRegexMatches(file: TFile): boolean {
451-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
452-
const templater = (this.plugin.app as any).plugins?.plugins?.[
453-
"templater-obsidian"
454-
];
466+
const templater = (this.plugin.app as unknown as AppWithPlugins).plugins
467+
?.plugins?.["templater-obsidian"] as Record<string, unknown> | undefined;
455468
if (!templater) return false;
456-
const fileTemplates = templater.settings?.file_templates;
469+
const settings = templater.settings as Record<string, unknown> | undefined;
470+
const fileTemplates = settings?.file_templates;
457471
if (!Array.isArray(fileTemplates)) return false;
458472

459473
for (const ft of fileTemplates) {
@@ -520,8 +534,9 @@ export class FileCreationCoordinator {
520534
}, remainingTime);
521535

522536
// Listen for Templater event
523-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
524-
const eventRef = (this.plugin.app.workspace as any).on(
537+
const eventRef = (
538+
this.plugin.app.workspace as unknown as WorkspaceWithCustomEvents
539+
).on(
525540
"templater:new-note-from-template",
526541
(data: Record<string, unknown>) => {
527542
if (

src/core/plugin-initializer.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export class PluginInitializer {
101101
// Check if Excalidraw plugin is installed and enabled
102102
const excalidrawPlugin = this.plugin.app.plugins.getPlugin(
103103
"obsidian-excalidraw-plugin",
104-
);
104+
) as { _loaded?: boolean } | null;
105105
if (excalidrawPlugin && excalidrawPlugin._loaded) {
106106
// Check if excalidraw-plugin property already exists
107107
const hasExcalidrawProperty =
@@ -179,8 +179,9 @@ export class PluginInitializer {
179179
// Check Templater plugin
180180
if (this.settings.core.verboseLogging)
181181
console.debug("Checking for Templater community plugin");
182-
const templaterPlugin =
183-
this.plugin.app.plugins.getPlugin("templater-obsidian");
182+
const templaterPlugin = this.plugin.app.plugins.getPlugin(
183+
"templater-obsidian",
184+
) as { _loaded?: boolean } | null;
184185
if (this.settings.core.verboseLogging)
185186
console.debug(
186187
"Templater plugin found:",

src/i18n.ts

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@ export function initI18n(): void {
2626

2727
// Load translations
2828
if (state.availableTranslations[state.currentLocale]) {
29-
state.translations =
30-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
31-
state.availableTranslations[state.currentLocale] as any;
29+
state.translations = state.availableTranslations[
30+
state.currentLocale
31+
] as typeof enTranslations;
3232
} else {
3333
// Fallback to English if locale not available
3434
state.currentLocale = "en";
35-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
36-
state.translations = state.availableTranslations["en"] as any;
35+
state.translations = state.availableTranslations[
36+
"en"
37+
] as typeof enTranslations;
3738
}
3839
}
3940

@@ -66,8 +67,7 @@ export function t(
6667

6768
for (const key of keys) {
6869
if (value && typeof value === "object" && key in value && value !== null) {
69-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
70-
value = (value as any)[key];
70+
value = (value as Record<string, unknown>)[key];
7171
} else {
7272
// Key not found, use fallback
7373
let result = fb || keyPath;
@@ -151,8 +151,7 @@ export function tp(keyPath: string, count: number, fallback?: string): string {
151151

152152
for (const key of keys) {
153153
if (value && typeof value === "object" && key in value && value !== null) {
154-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
155-
value = (value as any)[key];
154+
value = (value as Record<string, unknown>)[key];
156155
} else {
157156
return (fallback || keyPath).replace("{{count}}", String(count));
158157
}
@@ -180,12 +179,13 @@ export function tp(keyPath: string, count: number, fallback?: string): string {
180179
}
181180
}
182181

182+
const valueRecord = value as Record<string, unknown>;
183183
const message =
184-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
185-
(value as any)[pluralKey] || (value as any)["many"] || fallback || keyPath;
186-
return typeof message === "string"
187-
? message.replace("{{count}}", String(count))
188-
: message;
184+
valueRecord[pluralKey] || valueRecord["many"] || fallback || keyPath;
185+
if (typeof message === "string") {
186+
return message.replace("{{count}}", String(count));
187+
}
188+
return String(message).replace("{{count}}", String(count));
189189
}
190190

191191
/**
@@ -203,8 +203,7 @@ export function tpSplit(
203203

204204
for (const key of keys) {
205205
if (value && typeof value === "object" && key in value && value !== null) {
206-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
207-
value = (value as any)[key];
206+
value = (value as Record<string, unknown>)[key];
208207
} else {
209208
return { before: keyPath, noun: "", after: "" };
210209
}
@@ -227,17 +226,22 @@ export function tpSplit(
227226
}
228227
}
229228

230-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
231-
const pluralForm = (value as any)[pluralKey] || (value as any)["many"];
229+
const valueRecord = value as Record<string, unknown>;
230+
const pluralForm = valueRecord[pluralKey] || valueRecord["many"];
232231

233232
if (pluralForm && typeof pluralForm === "object") {
233+
const pf = pluralForm as Record<string, string>;
234234
return {
235-
before: pluralForm.before || "",
236-
noun: pluralForm.noun || "",
237-
after: pluralForm.after || "",
235+
before: pf.before || "",
236+
noun: pf.noun || "",
237+
after: pf.after || "",
238238
};
239239
}
240240

241241
// Fallback for simple string format
242-
return { before: pluralForm || keyPath, noun: "", after: "" };
242+
return {
243+
before: typeof pluralForm === "string" ? pluralForm : keyPath,
244+
noun: "",
245+
after: "",
246+
};
243247
}

src/obsidian-ex.d.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ declare module "obsidian" {
2020
};
2121
plugins: {
2222
enabledPlugins: Set<string>;
23-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
24-
getPlugin(id: string): any;
23+
getPlugin(id: string): unknown;
2524
};
2625
}
2726

src/operations/tag-operations.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ export class TagOperations {
5353
cache.tags.forEach(
5454
(tagCache: {
5555
tag: string;
56-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
57-
position: any;
56+
position: { start: { line: number }; end: { line: number } };
5857
}) => {
5958
const cacheTag = tagCache.tag;
6059
let tagMatches = false;

src/settings/settings-base.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ export interface FirstLineIsTitlePlugin {
77
app: App;
88
settings: PluginSettings;
99
saveSettings(): Promise<void>;
10-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
11-
debugLog(settingName: string, value: any): void;
10+
debugLog(settingName: string, value: unknown): void;
1211
editorLifecycle?: { initializeCheckingSystem(): void };
1312
renameEngine?: {
1413
processFile(

0 commit comments

Comments
 (0)