groldsf_obsidian_check_plugin/src/ui/components/BaseTextArraySettingComponent.ts

130 lines
5.5 KiB
TypeScript
Raw Normal View History

import { TextComponent } from "obsidian";
import { ValidationError } from "../validation/types";
import { validateJsonStringArray } from "../validation/validators";
import { BaseSettingComponent } from "./BaseSettingComponent";
/**
* Абстрактный базовый класс для компонентов настроек,
* которые управляют массивом строк через текстовое поле с JSON.
*/
export abstract class BaseTextArraySettingComponent extends BaseSettingComponent {
/** Ссылка на текстовое поле ввода */
protected textInput: TextComponent;
constructor() {
super();
}
/**
* Форматирует массив строк в JSON строку для отображения в UI.
* @param symbols Массив строк.
* @returns Форматированная JSON строка.
*/
protected arrayToJsonString(symbols: string[] | undefined): string {
if (!symbols) {
return '[]';
}
try {
return JSON.stringify(symbols);
} catch (e) {
console.error(`[${this.getSettingKey()}] Error stringifying array to JSON:`, e);
return '[]'; // Возвращаем безопасное значение
}
}
/**
* Получает JSON строку из UI и парсит ее в массив строк.
* @returns Распарсенный массив строк.
* @throws Error если компонент не отрисован или если строка не является валидным JSON.
*/
getValueFromUi(): string[] {
if (this.textInput) {
const rawJson = this.textInput.getValue();
const trimmedValue = rawJson.trim();
// Считаем пустую строку или '[]' валидным представлением пустого массива
if (trimmedValue === '' || trimmedValue === '[]') {
return [];
}
try {
const parsed = JSON.parse(trimmedValue);
// Дополнительная проверка, что результат парсинга - массив
if (!Array.isArray(parsed)) {
// Эта ошибка также будет поймана validateJsonStringArray,
// но для надежности можно оставить.
throw new Error("Input must be a valid JSON array.");
}
// Предполагаем, что содержимое массива будет проверено валидатором.
// Возвращаем как string[] для TypeScript.
return parsed as string[];
} catch (e: any) {
// Оборачиваем ошибку парсинга
throw new Error(`Invalid JSON format: ${e.message}`);
}
}
// Если компонент не был отрисован
throw new Error(`[${this.getSettingKey()}] Cannot get value from UI before component is rendered.`);
}
/**
* Устанавливает значение (массив строк) в UI, предварительно форматируя его в JSON.
* @param value Массив строк для установки.
* @throws Error если компонент не отрисован.
*/
setValueInUi(value: any): void {
if (this.textInput) {
// Убедимся, что на вход пришел массив, прежде чем его форматировать
if (!Array.isArray(value)) {
console.warn(`[${this.getSettingKey()}] Attempted to set non-array value in TextArray component. Value:`, value);
// Можно установить пустой массив или выбросить ошибку?
// Установим пустой массив для безопасности UI.
this.textInput.setValue('[]');
return;
}
const jsonStringValue = this.arrayToJsonString(value as string[]);
this.textInput.setValue(jsonStringValue);
} else {
// Если компонент не был отрисован
throw new Error(`[${this.getSettingKey()}] Cannot set value before component is rendered.`);
}
}
/**
* Выполняет базовую валидацию: проверяет, что строка в UI является
* валидным JSON-массивом строк по одному символу без дубликатов.
* Не проверяет на пустоту массива.
* @returns Объект ValidationError при ошибке, иначе null.
*/
validate(): ValidationError | null {
let rawValue: string;
try {
if (this.textInput) {
rawValue = this.textInput.getValue();
} else {
// Если UI нет, валидация невозможна
throw new Error("UI component not available for validation.");
}
// Вызываем внешний валидатор для проверки формата JSON и содержимого
const jsonError = validateJsonStringArray(rawValue);
if (jsonError) {
// Добавляем ключ поля к ошибке
return {
field: this.getSettingKey(),
message: jsonError.message
};
}
} catch (error: any) {
// Ловим ошибки доступа к UI
return {
field: this.getSettingKey(),
message: error instanceof Error ? error.message : String(error)
};
}
// Базовая валидация JSON и содержимого прошла успешно
return null;
}
}