mirror of
https://github.com/mssoftjp/obsidian-voice-input.git
synced 2026-07-22 06:44:48 +00:00
fix(core): resolve lint issues in services and view
This commit is contained in:
parent
9cb8378f44
commit
7ddd851713
9 changed files with 70 additions and 32 deletions
|
|
@ -106,7 +106,7 @@ export class ErrorHandler implements IDisposable {
|
|||
// i18n service might not be available yet during initialization
|
||||
try {
|
||||
this.i18n = getI18n();
|
||||
} catch (_error) {
|
||||
} catch {
|
||||
// i18n service will be available later
|
||||
}
|
||||
|
||||
|
|
@ -130,22 +130,21 @@ export class ErrorHandler implements IDisposable {
|
|||
// Unhandled promise rejections
|
||||
this.unhandledRejectionHandler = (event: PromiseRejectionEvent) => {
|
||||
// Filter out errors that are not from our plugin
|
||||
const error = event.reason;
|
||||
const errorString = error?.toString?.() || String(error);
|
||||
const reasonSummary = this.describeReason(event.reason);
|
||||
|
||||
// Ignore errors from other plugins/sources
|
||||
if (errorString.includes('inputEl') ||
|
||||
errorString.includes('Cannot read properties of undefined') ||
|
||||
!errorString.includes('voice-input')) {
|
||||
if (reasonSummary.includes('inputEl') ||
|
||||
reasonSummary.includes('Cannot read properties of undefined') ||
|
||||
!reasonSummary.includes('voice-input')) {
|
||||
// Log in development mode only
|
||||
if (this.options.isDevelopment) {
|
||||
this.logger.debug('[VoiceInput] Ignored external error', error);
|
||||
this.logger.debug('[VoiceInput] Ignored external error', { reason: reasonSummary });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleError(
|
||||
new Error(`Unhandled Promise Rejection: ${event.reason}`),
|
||||
new Error(`Unhandled Promise Rejection: ${reasonSummary}`),
|
||||
{
|
||||
component: 'Global',
|
||||
operation: 'UnhandledRejection',
|
||||
|
|
@ -159,8 +158,9 @@ export class ErrorHandler implements IDisposable {
|
|||
|
||||
// Global error events
|
||||
this.errorHandler = (event: ErrorEvent) => {
|
||||
const eventError = event.error instanceof Error ? event.error : new Error(event.message);
|
||||
this.handleError(
|
||||
event.error || new Error(event.message),
|
||||
eventError,
|
||||
{
|
||||
component: 'Global',
|
||||
operation: 'UncaughtError',
|
||||
|
|
@ -247,7 +247,7 @@ export class ErrorHandler implements IDisposable {
|
|||
let contextSummary: string;
|
||||
try {
|
||||
contextSummary = JSON.stringify(context);
|
||||
} catch (_error) {
|
||||
} catch {
|
||||
contextSummary = '[Unserializable context]';
|
||||
}
|
||||
throw lastError || new Error(`Retry operation failed after ${this.options.maxRetries} attempts in context: ${contextSummary}`);
|
||||
|
|
@ -319,6 +319,20 @@ export class ErrorHandler implements IDisposable {
|
|||
}
|
||||
}
|
||||
|
||||
private describeReason(reason: unknown): string {
|
||||
if (typeof reason === 'string') {
|
||||
return reason;
|
||||
}
|
||||
if (reason instanceof Error) {
|
||||
return reason.message || reason.name;
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(reason);
|
||||
} catch {
|
||||
return String(reason);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ユーザーに通知
|
||||
*/
|
||||
|
|
@ -343,7 +357,7 @@ export class ErrorHandler implements IDisposable {
|
|||
if (!this.i18n) {
|
||||
try {
|
||||
this.i18n = getI18n();
|
||||
} catch (_error) {
|
||||
} catch {
|
||||
// Fallback to English messages
|
||||
switch (severity) {
|
||||
case ErrorSeverity.FATAL:
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export class TranscriptionError extends Error {
|
|||
|
||||
try {
|
||||
i18n = getI18n();
|
||||
} catch (_error) {
|
||||
} catch {
|
||||
// Fallback to original message if i18n is not available
|
||||
return this.message;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// Main entry point for Voice Memo Plugin
|
||||
export { default } from './plugin';
|
||||
export { default } from './plugin';
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export class ViewManager extends Disposable {
|
|||
// ServiceLocatorからLoggerを取得
|
||||
try {
|
||||
this.logger = createServiceLogger('ViewManager');
|
||||
} catch (_error) {
|
||||
} catch {
|
||||
// フォールバック: ServiceLocatorが初期化されていない場合
|
||||
// 基本のLoggerインスタンスを作成
|
||||
this.logger = Logger.getLogger('ViewManager');
|
||||
|
|
|
|||
|
|
@ -11,6 +11,14 @@ import { serviceLocator, ServiceKeys, getI18nService } from '../services';
|
|||
import { getObsidianLocale } from '../types';
|
||||
import { SafeStorageService } from '../security';
|
||||
|
||||
type LegacyVoiceInputSettings = Partial<VoiceInputSettings> & {
|
||||
language?: string;
|
||||
interfaceLanguage?: string;
|
||||
recordingMode?: string;
|
||||
autoStopSilenceDuration?: number;
|
||||
minSpeechDuration?: number;
|
||||
};
|
||||
|
||||
export default class VoiceInputPlugin extends Plugin {
|
||||
settings: VoiceInputSettings;
|
||||
private viewManager: ViewManager;
|
||||
|
|
@ -110,7 +118,7 @@ export default class VoiceInputPlugin extends Plugin {
|
|||
// Add ribbon icon
|
||||
this.addRibbonIcon('microphone', i18n.t('ui.titles.main'), () => {
|
||||
this.logger.debug('Ribbon icon clicked');
|
||||
this.viewManager.activateVoiceInputView();
|
||||
void this.viewManager.activateVoiceInputView();
|
||||
});
|
||||
this.logger.debug('Ribbon icon added');
|
||||
|
||||
|
|
@ -120,7 +128,7 @@ export default class VoiceInputPlugin extends Plugin {
|
|||
name: i18n.t('ui.commands.openView'),
|
||||
callback: () => {
|
||||
this.logger.debug('Command executed: open-view');
|
||||
this.viewManager.activateVoiceInputView();
|
||||
void this.viewManager.activateVoiceInputView();
|
||||
}
|
||||
});
|
||||
this.logger.debug('Commands registered');
|
||||
|
|
@ -212,7 +220,7 @@ export default class VoiceInputPlugin extends Plugin {
|
|||
}
|
||||
|
||||
async loadSettings() {
|
||||
const data = await this.loadData();
|
||||
const data = this.parseStoredSettings(await this.loadData());
|
||||
|
||||
// まずデフォルト設定から開始
|
||||
this.settings = { ...DEFAULT_SETTINGS };
|
||||
|
|
@ -475,4 +483,11 @@ export default class VoiceInputPlugin extends Plugin {
|
|||
getLogger(): Logger | null {
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
private parseStoredSettings(data: unknown): LegacyVoiceInputSettings | null {
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
return data as LegacyVoiceInputSettings;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,16 @@ const isElectronWindow = (win: Window): win is ElectronWindow => {
|
|||
return 'require' in win && typeof (win as ElectronWindow).require === 'function';
|
||||
};
|
||||
|
||||
const resolveElectronRenderer = (): ElectronRenderer | null => {
|
||||
if (isElectronWindow(window) && typeof (window as ElectronWindow).require === 'function') {
|
||||
return (window as ElectronWindow).require('electron') ?? null;
|
||||
}
|
||||
if ((window as ElectronWindow).electron) {
|
||||
return (window as ElectronWindow).electron ?? null;
|
||||
}
|
||||
return (globalThis as ElectronGlobal).electron ?? null;
|
||||
};
|
||||
|
||||
export class SafeStorageService {
|
||||
private static safeStorage: ElectronSafeStorage | null = null;
|
||||
private static logger: Logger = getLogger('SafeStorageService');
|
||||
|
|
@ -53,15 +63,10 @@ export class SafeStorageService {
|
|||
this.logger.debug(`window.require exists: ${'require' in window}`);
|
||||
this.logger.debug(`window.require is function: ${typeof (window as ElectronWindow).require === 'function'}`);
|
||||
|
||||
const electron = isElectronWindow(window) ? window.require?.('electron') : null;
|
||||
const electron = resolveElectronRenderer();
|
||||
|
||||
if (!electron) {
|
||||
// Alternative access method
|
||||
const globalElectron = (window as ElectronWindow).electron || (global as ElectronGlobal).electron;
|
||||
if (globalElectron) {
|
||||
this.logger.debug('Found electron via global access');
|
||||
this.safeStorage = globalElectron.remote?.safeStorage || globalElectron.safeStorage || null;
|
||||
}
|
||||
this.logger.debug('Electron renderer not available');
|
||||
} else {
|
||||
this.logger.debug(`Electron object exists: ${!!electron}`);
|
||||
this.logger.debug(`Electron.remote exists: ${!!electron?.remote}`);
|
||||
|
|
|
|||
|
|
@ -127,8 +127,10 @@ export class I18nServiceImpl implements I18nService {
|
|||
* Supports {paramName} syntax
|
||||
*/
|
||||
private substituteParams(translation: string, params: Record<string, string | number>): string {
|
||||
return translation.replace(/{(\w+)}/g, (match, paramName) => {
|
||||
return params[paramName]?.toString() || match;
|
||||
return translation.replace(/{(\w+)}/g, (match, captured) => {
|
||||
const paramKey = captured as keyof typeof params;
|
||||
const value = params[paramKey];
|
||||
return value !== undefined ? value.toString() : match;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ export class ObsidianHttpClient {
|
|||
}): Promise<{ status: number; json: unknown; text: string }> {
|
||||
const { url, method = 'GET', headers = {}, body } = opts;
|
||||
const res = await requestUrl({ url, method, headers, body, throw: false });
|
||||
return { status: res.status, json: res.json, text: res.text };
|
||||
const jsonBody: unknown = res.json;
|
||||
return { status: res.status, json: jsonBody, text: res.text };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +44,8 @@ export class ObsidianHttpClient {
|
|||
body: JSON.stringify(data),
|
||||
throw: false
|
||||
});
|
||||
return { status: res.status, json: res.json };
|
||||
const jsonBody: unknown = res.json;
|
||||
return { status: res.status, json: jsonBody };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -63,8 +65,8 @@ export class ObsidianHttpClient {
|
|||
body,
|
||||
throw: false
|
||||
});
|
||||
|
||||
return { status: response.status, json: response.json };
|
||||
const jsonBody: unknown = response.json;
|
||||
return { status: response.status, json: jsonBody };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ export class VoiceInputViewUI {
|
|||
secondRowContainer: HTMLElement;
|
||||
|
||||
// Settings controls
|
||||
correctionToggle: ToggleComponent;
|
||||
transcriptionModelDropdown: DropdownComponent;
|
||||
correctionToggle: ToggleComponent | null = null;
|
||||
transcriptionModelDropdown: DropdownComponent | null = null;
|
||||
|
||||
// Event handlers
|
||||
private clickHandler: ((e: MouseEvent) => void) | null = null;
|
||||
|
|
|
|||
Loading…
Reference in a new issue