fix: linter errors
This commit is contained in:
+1
-1
@@ -18,7 +18,7 @@ import type { RenderingEvent } from './core/audio-interface/KGOfflineRenderer';
|
|||||||
import { KGCore } from './core/KGCore';
|
import { KGCore } from './core/KGCore';
|
||||||
import { ConfigManager } from './core/config/ConfigManager';
|
import { ConfigManager } from './core/config/ConfigManager';
|
||||||
import { validateFunctionalChordsJSON } from './util/scaleUtil';
|
import { validateFunctionalChordsJSON } from './util/scaleUtil';
|
||||||
import { showAlert } from './components/common/DialogProvider';
|
import { showAlert } from './util/dialogUtil';
|
||||||
import { KGProjectStorage } from './core/io/KGProjectStorage';
|
import { KGProjectStorage } from './core/io/KGProjectStorage';
|
||||||
import { RESERVED_PROJECT_NAME } from './util/projectNameUtil';
|
import { RESERVED_PROJECT_NAME } from './util/projectNameUtil';
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { sliceAudioToWav } from '../util/audioUtil';
|
|||||||
import type { KeySignature } from '../core/KGProject';
|
import type { KeySignature } from '../core/KGProject';
|
||||||
import { ImportStemsCommand } from '../core/commands';
|
import { ImportStemsCommand } from '../core/commands';
|
||||||
import type { StemImportEntry } from '../core/commands';
|
import type { StemImportEntry } from '../core/commands';
|
||||||
import { showAlert } from './common/DialogProvider';
|
import { showAlert } from '../util/dialogUtil';
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import { clearChatHistoryAndUI } from '../util/chatUtil';
|
|||||||
import PianoIcon from './common/icons/PianoIcon';
|
import PianoIcon from './common/icons/PianoIcon';
|
||||||
import MetronomeIcon from './common/icons/MetronomeIcon';
|
import MetronomeIcon from './common/icons/MetronomeIcon';
|
||||||
import { ConfigManager } from '../core/config/ConfigManager';
|
import { ConfigManager } from '../core/config/ConfigManager';
|
||||||
import { showAlert, showConfirm, showPrompt, showTimeSigPrompt } from './common/DialogProvider';
|
import { showAlert, showConfirm, showPrompt, showTimeSigPrompt } from '../util/dialogUtil';
|
||||||
|
|
||||||
const Toolbar: React.FC = () => {
|
const Toolbar: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -1,60 +1,8 @@
|
|||||||
import React, { useState, useCallback, useRef } from 'react';
|
import React, { useState, useCallback, useRef } from 'react';
|
||||||
import './DialogProvider.css';
|
import './DialogProvider.css';
|
||||||
import { FaTimes } from 'react-icons/fa';
|
import { FaTimes } from 'react-icons/fa';
|
||||||
|
import { registerDialogFns } from '../../util/dialogUtil';
|
||||||
export interface ConfirmOptions {
|
import type { ConfirmOptions, PromptOptions, TimeSigResult } from '../../util/dialogUtil';
|
||||||
confirmLabel?: string;
|
|
||||||
cancelLabel?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PromptOptions {
|
|
||||||
confirmLabel?: string;
|
|
||||||
cancelLabel?: string;
|
|
||||||
placeholder?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TimeSigResult {
|
|
||||||
numerator: number;
|
|
||||||
denominator: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
let _showAlertFn: ((message: string) => Promise<void>) | null = null;
|
|
||||||
let _showConfirmFn: ((message: string, options?: ConfirmOptions) => Promise<boolean>) | null = null;
|
|
||||||
let _showPromptFn: ((message: string, defaultValue?: string, options?: PromptOptions) => Promise<string | null>) | null = null;
|
|
||||||
let _showTimeSigFn: ((message: string, defaultValue?: TimeSigResult) => Promise<TimeSigResult | null>) | null = null;
|
|
||||||
|
|
||||||
export function showAlert(message: string): Promise<void> {
|
|
||||||
if (!_showAlertFn) {
|
|
||||||
window.alert(message);
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
return _showAlertFn(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showConfirm(message: string, options?: ConfirmOptions): Promise<boolean> {
|
|
||||||
if (!_showConfirmFn) {
|
|
||||||
return Promise.resolve(window.confirm(message));
|
|
||||||
}
|
|
||||||
return _showConfirmFn(message, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showPrompt(message: string, defaultValue?: string, options?: PromptOptions): Promise<string | null> {
|
|
||||||
if (!_showPromptFn) {
|
|
||||||
return Promise.resolve(window.prompt(message, defaultValue));
|
|
||||||
}
|
|
||||||
return _showPromptFn(message, defaultValue, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showTimeSigPrompt(message: string, defaultValue?: TimeSigResult): Promise<TimeSigResult | null> {
|
|
||||||
if (!_showTimeSigFn) {
|
|
||||||
const raw = window.prompt(message, defaultValue ? `${defaultValue.numerator}/${defaultValue.denominator}` : '4/4');
|
|
||||||
if (!raw) return Promise.resolve(null);
|
|
||||||
const [n, d] = raw.split('/').map(Number);
|
|
||||||
if (!n || !d) return Promise.resolve(null);
|
|
||||||
return Promise.resolve({ numerator: n, denominator: d });
|
|
||||||
}
|
|
||||||
return _showTimeSigFn(message, defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DialogInfo {
|
interface DialogInfo {
|
||||||
type: 'alert' | 'confirm' | 'prompt' | 'timesig';
|
type: 'alert' | 'confirm' | 'prompt' | 'timesig';
|
||||||
@@ -129,10 +77,7 @@ const DialogProvider: React.FC<{ children: React.ReactNode }> = ({ children }) =
|
|||||||
const registered = useRef(false);
|
const registered = useRef(false);
|
||||||
if (!registered.current) {
|
if (!registered.current) {
|
||||||
registered.current = true;
|
registered.current = true;
|
||||||
_showAlertFn = openAlert;
|
registerDialogFns(openAlert, openConfirm, openPrompt, openTimeSig);
|
||||||
_showConfirmFn = openConfirm;
|
|
||||||
_showPromptFn = openPrompt;
|
|
||||||
_showTimeSigFn = openTimeSig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dialog) {
|
if (!dialog) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import './FileImportModal.css';
|
import './FileImportModal.css';
|
||||||
import { FaTimes } from 'react-icons/fa';
|
import { FaTimes } from 'react-icons/fa';
|
||||||
import { showAlert } from './DialogProvider';
|
import { showAlert } from '../../util/dialogUtil';
|
||||||
|
|
||||||
interface FileImportModalProps {
|
interface FileImportModalProps {
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { FaTimes, FaSortUp, FaSortDown, FaCopy, FaTrash, FaUndo } from 'react-ic
|
|||||||
import { KGProjectStorage, type ProjectMeta } from '../../core/io/KGProjectStorage';
|
import { KGProjectStorage, type ProjectMeta } from '../../core/io/KGProjectStorage';
|
||||||
import { isValidProjectName } from '../../util/projectNameUtil';
|
import { isValidProjectName } from '../../util/projectNameUtil';
|
||||||
import './OpenProjectModal.css';
|
import './OpenProjectModal.css';
|
||||||
import { showAlert, showConfirm, showPrompt } from './DialogProvider';
|
import { showAlert, showConfirm, showPrompt } from '../../util/dialogUtil';
|
||||||
|
|
||||||
interface OpenProjectModalProps {
|
interface OpenProjectModalProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
|||||||
@@ -3,5 +3,6 @@ export { default as Playhead } from './Playhead';
|
|||||||
export { default as FileImportModal } from './FileImportModal';
|
export { default as FileImportModal } from './FileImportModal';
|
||||||
export { default as LoadingOverlay } from './LoadingOverlay';
|
export { default as LoadingOverlay } from './LoadingOverlay';
|
||||||
export { default as OpenProjectModal } from './OpenProjectModal';
|
export { default as OpenProjectModal } from './OpenProjectModal';
|
||||||
export { default as DialogProvider, showAlert, showConfirm, showPrompt, showTimeSigPrompt } from './DialogProvider';
|
export { default as DialogProvider } from './DialogProvider';
|
||||||
export type { ConfirmOptions, PromptOptions, TimeSigResult } from './DialogProvider';
|
export { showAlert, showConfirm, showPrompt, showTimeSigPrompt } from '../../util/dialogUtil';
|
||||||
|
export type { ConfirmOptions, PromptOptions, TimeSigResult } from '../../util/dialogUtil';
|
||||||
@@ -15,7 +15,7 @@ import { ConfigManager } from '../../core/config/ConfigManager';
|
|||||||
import { beatsToBar } from '../../util/midiUtil';
|
import { beatsToBar } from '../../util/midiUtil';
|
||||||
import { UpdateRegionCommand } from '../../core/commands';
|
import { UpdateRegionCommand } from '../../core/commands';
|
||||||
import { getSuitableChords, noteNameToPitchClass } from '../../util/scaleUtil';
|
import { getSuitableChords, noteNameToPitchClass } from '../../util/scaleUtil';
|
||||||
import { showAlert, showPrompt } from '../common/DialogProvider';
|
import { showAlert, showPrompt } from '../../util/dialogUtil';
|
||||||
|
|
||||||
interface PianoRollProps {
|
interface PianoRollProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react';
|
|||||||
import { ConfigManager } from '../../../core/config/ConfigManager';
|
import { ConfigManager } from '../../../core/config/ConfigManager';
|
||||||
import { validateFunctionalChordsJSON } from '../../../util/scaleUtil';
|
import { validateFunctionalChordsJSON } from '../../../util/scaleUtil';
|
||||||
import { KGCore } from '../../../core/KGCore';
|
import { KGCore } from '../../../core/KGCore';
|
||||||
import { showAlert } from '../../common/DialogProvider';
|
import { showAlert } from '../../../util/dialogUtil';
|
||||||
|
|
||||||
const ChordGuideSettings: React.FC = () => {
|
const ChordGuideSettings: React.FC = () => {
|
||||||
const [chordDefinition, setChordDefinition] = useState<string>('');
|
const [chordDefinition, setChordDefinition] = useState<string>('');
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { KGAudioInterface } from '../../core/audio-interface/KGAudioInterface';
|
|||||||
import { KGAudioRegion } from '../../core/region/KGAudioRegion';
|
import { KGAudioRegion } from '../../core/region/KGAudioRegion';
|
||||||
import { generateNewRegionName } from '../../util/miscUtil';
|
import { generateNewRegionName } from '../../util/miscUtil';
|
||||||
import { KGAudioFileStorage } from '../../core/io/KGAudioFileStorage';
|
import { KGAudioFileStorage } from '../../core/io/KGAudioFileStorage';
|
||||||
import { showAlert } from '../common/DialogProvider';
|
import { showAlert } from '../../util/dialogUtil';
|
||||||
import { parseMidiFirstTrackNotes } from '../../util/midiUtil';
|
import { parseMidiFirstTrackNotes } from '../../util/midiUtil';
|
||||||
import * as Tone from 'tone';
|
import * as Tone from 'tone';
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { FLUIDR3_INSTRUMENT_MAP } from '../../constants/generalMidiConstants';
|
|||||||
import { DEBUG_MODE } from '../../constants/uiConstants';
|
import { DEBUG_MODE } from '../../constants/uiConstants';
|
||||||
import { KGAudioInterface } from '../../core/audio-interface/KGAudioInterface';
|
import { KGAudioInterface } from '../../core/audio-interface/KGAudioInterface';
|
||||||
import { AUDIO_INTERFACE_CONSTANTS } from '../../constants/coreConstants';
|
import { AUDIO_INTERFACE_CONSTANTS } from '../../constants/coreConstants';
|
||||||
import { showAlert, showConfirm, showPrompt } from '../common/DialogProvider';
|
import { showAlert, showConfirm, showPrompt } from '../../util/dialogUtil';
|
||||||
|
|
||||||
const UNITY_POS = 750;
|
const UNITY_POS = 750;
|
||||||
const SLIDER_MAX = 1000;
|
const SLIDER_MAX = 1000;
|
||||||
|
|||||||
@@ -513,8 +513,7 @@ export class KGDebugger {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
textarea.selectionStart = textarea.selectionEnd = typed.length;
|
textarea.selectionStart = textarea.selectionEnd = typed.length;
|
||||||
} catch {
|
} catch { /* setting cursor position can fail in read-only or special inputs */ }
|
||||||
}
|
|
||||||
|
|
||||||
textarea.scrollTop = textarea.scrollHeight;
|
textarea.scrollTop = textarea.scrollHeight;
|
||||||
|
|
||||||
@@ -583,8 +582,7 @@ export class KGDebugger {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
textarea.selectionStart = textarea.selectionEnd = typed.length;
|
textarea.selectionStart = textarea.selectionEnd = typed.length;
|
||||||
} catch {
|
} catch { /* setting cursor position can fail in read-only or special inputs */ }
|
||||||
}
|
|
||||||
|
|
||||||
textarea.scrollTop = textarea.scrollHeight;
|
textarea.scrollTop = textarea.scrollHeight;
|
||||||
|
|
||||||
|
|||||||
@@ -47,9 +47,8 @@ class MockFileHandle {
|
|||||||
async getFile() { return { text: () => Promise.resolve(this._content) }; }
|
async getFile() { return { text: () => Promise.resolve(this._content) }; }
|
||||||
async createWritable() {
|
async createWritable() {
|
||||||
const w = new MockWritable();
|
const w = new MockWritable();
|
||||||
const self = this;
|
|
||||||
const origClose = w.close.bind(w);
|
const origClose = w.close.bind(w);
|
||||||
w.close = async () => { self._content = w.data; await origClose(); };
|
w.close = async () => { this._content = w.data; await origClose(); };
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,9 @@ class MockFileSystemFileHandle {
|
|||||||
async createWritable() {
|
async createWritable() {
|
||||||
const stream = new MockFileSystemWritableFileStream();
|
const stream = new MockFileSystemWritableFileStream();
|
||||||
// When stream closes, update our content
|
// When stream closes, update our content
|
||||||
const self = this;
|
|
||||||
const origClose = stream.close.bind(stream);
|
const origClose = stream.close.bind(stream);
|
||||||
stream.close = async () => {
|
stream.close = async () => {
|
||||||
self._content = stream.data;
|
this._content = stream.data;
|
||||||
await origClose();
|
await origClose();
|
||||||
};
|
};
|
||||||
return stream;
|
return stream;
|
||||||
|
|||||||
@@ -5,11 +5,13 @@
|
|||||||
import { vi } from 'vitest';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
// In-memory storage for tests
|
// In-memory storage for tests
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const mockStorage = new Map<string, any>();
|
const mockStorage = new Map<string, any>();
|
||||||
|
|
||||||
export const mockIndexedDB = {
|
export const mockIndexedDB = {
|
||||||
openDB: vi.fn().mockImplementation(() => {
|
openDB: vi.fn().mockImplementation(() => {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
put: vi.fn().mockImplementation((storeName: string, data: any, key?: string) => {
|
put: vi.fn().mockImplementation((storeName: string, data: any, key?: string) => {
|
||||||
const actualKey = key || data.id || 'default';
|
const actualKey = key || data.id || 'default';
|
||||||
mockStorage.set(`${storeName}:${actualKey}`, data);
|
mockStorage.set(`${storeName}:${actualKey}`, data);
|
||||||
@@ -21,6 +23,7 @@ export const mockIndexedDB = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
getAll: vi.fn().mockImplementation((storeName: string) => {
|
getAll: vi.fn().mockImplementation((storeName: string) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const results: any[] = [];
|
const results: any[] = [];
|
||||||
for (const [key, value] of mockStorage.entries()) {
|
for (const [key, value] of mockStorage.entries()) {
|
||||||
if (key.startsWith(`${storeName}:`)) {
|
if (key.startsWith(`${storeName}:`)) {
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
export interface ConfirmOptions {
|
||||||
|
confirmLabel?: string;
|
||||||
|
cancelLabel?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptOptions {
|
||||||
|
confirmLabel?: string;
|
||||||
|
cancelLabel?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimeSigResult {
|
||||||
|
numerator: number;
|
||||||
|
denominator: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
let _showAlertFn: ((message: string) => Promise<void>) | null = null;
|
||||||
|
let _showConfirmFn: ((message: string, options?: ConfirmOptions) => Promise<boolean>) | null = null;
|
||||||
|
let _showPromptFn: ((message: string, defaultValue?: string, options?: PromptOptions) => Promise<string | null>) | null = null;
|
||||||
|
let _showTimeSigFn: ((message: string, defaultValue?: TimeSigResult) => Promise<TimeSigResult | null>) | null = null;
|
||||||
|
|
||||||
|
export function registerDialogFns(
|
||||||
|
alertFn: (message: string) => Promise<void>,
|
||||||
|
confirmFn: (message: string, options?: ConfirmOptions) => Promise<boolean>,
|
||||||
|
promptFn: (message: string, defaultValue?: string, options?: PromptOptions) => Promise<string | null>,
|
||||||
|
timeSigFn: (message: string, defaultValue?: TimeSigResult) => Promise<TimeSigResult | null>,
|
||||||
|
) {
|
||||||
|
_showAlertFn = alertFn;
|
||||||
|
_showConfirmFn = confirmFn;
|
||||||
|
_showPromptFn = promptFn;
|
||||||
|
_showTimeSigFn = timeSigFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showAlert(message: string): Promise<void> {
|
||||||
|
if (!_showAlertFn) {
|
||||||
|
window.alert(message);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return _showAlertFn(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showConfirm(message: string, options?: ConfirmOptions): Promise<boolean> {
|
||||||
|
if (!_showConfirmFn) {
|
||||||
|
return Promise.resolve(window.confirm(message));
|
||||||
|
}
|
||||||
|
return _showConfirmFn(message, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showPrompt(message: string, defaultValue?: string, options?: PromptOptions): Promise<string | null> {
|
||||||
|
if (!_showPromptFn) {
|
||||||
|
return Promise.resolve(window.prompt(message, defaultValue));
|
||||||
|
}
|
||||||
|
return _showPromptFn(message, defaultValue, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showTimeSigPrompt(message: string, defaultValue?: TimeSigResult): Promise<TimeSigResult | null> {
|
||||||
|
if (!_showTimeSigFn) {
|
||||||
|
const raw = window.prompt(message, defaultValue ? `${defaultValue.numerator}/${defaultValue.denominator}` : '4/4');
|
||||||
|
if (!raw) return Promise.resolve(null);
|
||||||
|
const [n, d] = raw.split('/').map(Number);
|
||||||
|
if (!n || !d) return Promise.resolve(null);
|
||||||
|
return Promise.resolve({ numerator: n, denominator: d });
|
||||||
|
}
|
||||||
|
return _showTimeSigFn(message, defaultValue);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { KGProjectStorage } from '../core/io/KGProjectStorage';
|
import { KGProjectStorage } from '../core/io/KGProjectStorage';
|
||||||
import { KGCore } from '../core/KGCore';
|
import { KGCore } from '../core/KGCore';
|
||||||
import { RESERVED_PROJECT_NAME } from './projectNameUtil';
|
import { RESERVED_PROJECT_NAME } from './projectNameUtil';
|
||||||
import { showAlert } from '../components/common/DialogProvider';
|
import { showAlert } from './dialogUtil';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save project utility function.
|
* Save project utility function.
|
||||||
|
|||||||
@@ -214,8 +214,8 @@ describe('xmlUtil', () => {
|
|||||||
|
|
||||||
it('should handle empty input', () => {
|
it('should handle empty input', () => {
|
||||||
expect(wrapXmlBlocksInContent('')).toBe('');
|
expect(wrapXmlBlocksInContent('')).toBe('');
|
||||||
expect(wrapXmlBlocksInContent(null as any)).toBeNull();
|
expect(wrapXmlBlocksInContent(null as unknown as string)).toBeNull();
|
||||||
expect(wrapXmlBlocksInContent(undefined as any)).toBeUndefined();
|
expect(wrapXmlBlocksInContent(undefined as unknown as string)).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should wrap XML blocks from multipleXmlBlocks fixture', () => {
|
it('should wrap XML blocks from multipleXmlBlocks fixture', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user