mirror of
https://github.com/groldsf/obsidian_check_plugin.git
synced 2026-07-22 05:37:48 +00:00
ref and add test
This commit is contained in:
parent
a851cc8428
commit
0b797bed5a
7 changed files with 413 additions and 101 deletions
234
__tests__/TextSyncPipeline.test.ts
Normal file
234
__tests__/TextSyncPipeline.test.ts
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
import { CheckboxUtils } from "src/checkboxUtils";
|
||||
import { FileFilter } from "src/FileFilter";
|
||||
import TextSyncPipeline from "src/TextSyncPipeline";
|
||||
import { CheckboxSyncPluginSettings, DEFAULT_SETTINGS } from "src/types";
|
||||
import { InMemoryFilePathStateHolder } from "./fakes/InMemoryFilePathStateHolder";
|
||||
|
||||
describe('TextSyncPipeline E2E-like Tests', () => {
|
||||
let fakeFileStateHolder: InMemoryFilePathStateHolder;
|
||||
let checkboxUtils: CheckboxUtils;
|
||||
let fileFilter: FileFilter;
|
||||
let pipeline: TextSyncPipeline;
|
||||
let settings: CheckboxSyncPluginSettings;
|
||||
|
||||
beforeEach(() => {
|
||||
// Используем настройки по умолчанию для большинства тестов,
|
||||
// их можно переопределять для специфических сценариев
|
||||
settings = { ...DEFAULT_SETTINGS };
|
||||
|
||||
fakeFileStateHolder = new InMemoryFilePathStateHolder();
|
||||
checkboxUtils = new CheckboxUtils(settings);
|
||||
fileFilter = new FileFilter(settings); // Инициализируем с настройками
|
||||
|
||||
pipeline = new TextSyncPipeline(checkboxUtils, fakeFileStateHolder, fileFilter);
|
||||
});
|
||||
|
||||
// --- Тесты на разрешение путей и кеширование ---
|
||||
|
||||
describe('Path Filtering and Caching Logic', () => {
|
||||
it('process: when path is NOT allowed, should return original text and cache original text', () => {
|
||||
// Настраиваем FileFilter, чтобы он запрещал путь
|
||||
settings.pathGlobs = ["restricted/path.md"]; // Этот путь будет игнорироваться
|
||||
fileFilter.updateSettings(settings); // Обновляем фильтр с новыми глобами
|
||||
|
||||
const filePath = "restricted/path.md";
|
||||
const currentText = "- [ ] task 1\n- [x] task 2";
|
||||
|
||||
// Act
|
||||
const resultText = pipeline.applySyncLogic(currentText, filePath);
|
||||
|
||||
// Assert
|
||||
// 1. Текст не должен измениться
|
||||
expect(resultText).toBe(currentText);
|
||||
// 2. Оригинальный текст должен быть закеширован
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(currentText);
|
||||
});
|
||||
|
||||
it('process: when path IS allowed, but no sync changes occur, should return original text and cache original (synced) text', () => {
|
||||
// Путь разрешен по умолчанию (pathGlobs пустой)
|
||||
settings.pathGlobs = [];
|
||||
fileFilter.updateSettings(settings);
|
||||
|
||||
const filePath = "allowed/path.md";
|
||||
// Текст, который не будет изменен CheckboxUtils при текущих настройках
|
||||
// (например, нет родительских/дочерних для пропагации, или они уже синхронизованы)
|
||||
const currentText = "- [ ] task 1\n- [ ] task 2";
|
||||
const previousTextInHolder = "- [ ] task 1\n- [ ] task 2"; // Предположим, предыдущее состояние было таким же
|
||||
|
||||
fakeFileStateHolder.setInitialStates({ [filePath]: previousTextInHolder });
|
||||
|
||||
// Act
|
||||
const resultText = pipeline.applySyncLogic(currentText, filePath);
|
||||
|
||||
// Assert
|
||||
// 1. Текст не должен измениться (т.к. syncText вернул то же самое)
|
||||
expect(resultText).toBe(currentText);
|
||||
// 2. В кеше должен быть этот же (оригинальный/синхронизированный) текст
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(currentText);
|
||||
});
|
||||
|
||||
it('process: when path IS allowed and sync changes occur, should return modified text and cache modified text', () => {
|
||||
// Путь разрешен
|
||||
settings.pathGlobs = [];
|
||||
fileFilter.updateSettings(settings);
|
||||
// Включаем автоматическую пропагацию, чтобы изменения точно были
|
||||
settings.enableAutomaticChildState = true;
|
||||
checkboxUtils = new CheckboxUtils(settings); // Пересоздаем с новыми настройками
|
||||
pipeline = new TextSyncPipeline(checkboxUtils, fakeFileStateHolder, fileFilter);
|
||||
|
||||
|
||||
const filePath = "allowed/changes.md";
|
||||
const currentText = "- [x] parent\n - [ ] child"; // Родитель изменен, дочерний должен измениться
|
||||
const previousTextInHolder = "- [ ] parent\n - [ ] child"; // Предыдущее состояние
|
||||
|
||||
fakeFileStateHolder.setInitialStates({ [filePath]: previousTextInHolder });
|
||||
|
||||
// Act
|
||||
const resultText = pipeline.applySyncLogic(currentText, filePath);
|
||||
const expectedTextAfterSync = "- [x] parent\n - [x] child"; // Ожидаемый результат от CheckboxUtils
|
||||
|
||||
// Assert
|
||||
// 1. Текст должен измениться
|
||||
expect(resultText).toBe(expectedTextAfterSync);
|
||||
// 2. В кеше должен быть измененный текст
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(expectedTextAfterSync);
|
||||
});
|
||||
|
||||
it('process: when path IS allowed and file was not in state holder, should process and cache result', () => {
|
||||
settings.pathGlobs = [];
|
||||
fileFilter.updateSettings(settings);
|
||||
settings.enableAutomaticChildState = true;
|
||||
checkboxUtils = new CheckboxUtils(settings);
|
||||
pipeline = new TextSyncPipeline(checkboxUtils, fakeFileStateHolder, fileFilter);
|
||||
|
||||
const filePath = "allowed/new_file.md";
|
||||
const currentText = "- [x] parent\n - [ ] child";
|
||||
// Предыдущего состояния нет в fakeFileStateHolder
|
||||
|
||||
// Act
|
||||
const resultText = pipeline.applySyncLogic(currentText, filePath);
|
||||
const expectedTextAfterSync = "- [ ] parent\n - [ ] child";
|
||||
|
||||
// Assert
|
||||
expect(resultText).toBe(expectedTextAfterSync);
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(expectedTextAfterSync);
|
||||
});
|
||||
|
||||
it('process: subsequent calls for the same allowed path should use updated cached state', () => {
|
||||
settings.pathGlobs = [];
|
||||
fileFilter.updateSettings(settings);
|
||||
settings.enableAutomaticChildState = true;
|
||||
checkboxUtils = new CheckboxUtils(settings);
|
||||
pipeline = new TextSyncPipeline(checkboxUtils, fakeFileStateHolder, fileFilter);
|
||||
|
||||
const filePath = "allowed/sequential.md";
|
||||
const initialText = "- [ ] parent\n - [ ] child 1";
|
||||
const textAfterFirstEdit = "- [x] parent\n - [ ] child 1"; // Пользователь изменил родителя
|
||||
const expectedAfterFirstPipeline = "- [x] parent\n - [x] child 1";
|
||||
|
||||
// Первый вызов (например, после первого изменения в редакторе)
|
||||
fakeFileStateHolder.setByPath(filePath, initialText);
|
||||
let resultText = pipeline.applySyncLogic(textAfterFirstEdit, filePath); // previousText будет undefined
|
||||
expect(resultText).toBe(expectedAfterFirstPipeline);
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(expectedAfterFirstPipeline);
|
||||
|
||||
// Второе изменение (пользователь снимает галочку с родителя)
|
||||
const textAfterSecondEdit = "- [ ] parent\n - [x] child 1"; // previousText теперь expectedAfterFirstPipeline
|
||||
const expectedAfterSecondPipeline = "- [ ] parent\n - [ ] child 1";
|
||||
|
||||
resultText = pipeline.applySyncLogic(textAfterSecondEdit, filePath);
|
||||
expect(resultText).toBe(expectedAfterSecondPipeline);
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(expectedAfterSecondPipeline);
|
||||
});
|
||||
});
|
||||
|
||||
// --- Можно добавить тесты на специфическое поведение CheckboxUtils через pipeline ---
|
||||
// Например, если enableAutomaticParentState = true и т.д.
|
||||
|
||||
describe('CheckboxUtils Behavior through Pipeline (Path Allowed)', () => {
|
||||
beforeEach(() => {
|
||||
// Убедимся, что путь всегда разрешен для этих тестов
|
||||
settings.pathGlobs = [];
|
||||
fileFilter.updateSettings(settings);
|
||||
});
|
||||
|
||||
it('process: should propagate state to children if enabled', () => {
|
||||
settings.enableAutomaticChildState = true;
|
||||
checkboxUtils = new CheckboxUtils(settings); // Обновляем CheckboxUtils
|
||||
pipeline = new TextSyncPipeline(checkboxUtils, fakeFileStateHolder, fileFilter);
|
||||
|
||||
const filePath = "test.md";
|
||||
const previousText = "- [ ] Parent\n - [ ] Child";
|
||||
const currentText = "- [x] Parent\n - [ ] Child"; // Пользователь отметил родителя
|
||||
const expectedText = "- [x] Parent\n - [x] Child";
|
||||
|
||||
fakeFileStateHolder.setInitialStates({ [filePath]: previousText });
|
||||
const result = pipeline.applySyncLogic(currentText, filePath);
|
||||
expect(result).toBe(expectedText);
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(expectedText);
|
||||
});
|
||||
|
||||
it('process: should propagate state from children if enabled', () => {
|
||||
settings.enableAutomaticParentState = true;
|
||||
// Убедимся, что child state не влияет на этот тест, если он не нужен
|
||||
settings.enableAutomaticChildState = false;
|
||||
checkboxUtils = new CheckboxUtils(settings);
|
||||
pipeline = new TextSyncPipeline(checkboxUtils, fakeFileStateHolder, fileFilter);
|
||||
|
||||
const filePath = "test.md";
|
||||
// Предыдущее состояние не так важно, если мы не проверяем diff-логику
|
||||
const currentText = "- [ ] Parent\n - [x] Child 1\n - [x] Child 2"; // Дети отмечены
|
||||
const expectedText = "- [x] Parent\n - [x] Child 1\n - [x] Child 2"; // Родитель должен стать отмеченным
|
||||
|
||||
const result = pipeline.applySyncLogic(currentText, filePath);
|
||||
expect(result).toBe(expectedText);
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(expectedText);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Text content variations (Path Allowed)', () => {
|
||||
beforeEach(() => {
|
||||
// Убедимся, что путь всегда разрешен для этих тестов
|
||||
settings.pathGlobs = [];
|
||||
fileFilter.updateSettings(settings);
|
||||
// Оставляем настройки CheckboxUtils по умолчанию, если не указано иное
|
||||
checkboxUtils = new CheckboxUtils(settings);
|
||||
pipeline = new TextSyncPipeline(checkboxUtils, fakeFileStateHolder, fileFilter);
|
||||
});
|
||||
|
||||
it('process: text with no checkboxes should return original text and cache it', () => {
|
||||
const filePath = "text_files/no_checkboxes.md";
|
||||
const currentText = "This is a line.\nAnd another line without any checkboxes.";
|
||||
const previousTextInHolder = "Some old text";
|
||||
|
||||
fakeFileStateHolder.setInitialStates({ [filePath]: previousTextInHolder });
|
||||
|
||||
// Act
|
||||
const resultText = pipeline.applySyncLogic(currentText, filePath);
|
||||
|
||||
// Assert
|
||||
expect(resultText).toBe(currentText);
|
||||
// CheckboxUtils.syncText не должен был ничего изменить
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(currentText);
|
||||
});
|
||||
|
||||
it('process: text with only ignored checkboxes should return original text and cache it', () => {
|
||||
settings.ignoreSymbols = ["~"];
|
||||
checkboxUtils = new CheckboxUtils(settings); // Обновляем с новыми ignoreSymbols
|
||||
pipeline = new TextSyncPipeline(checkboxUtils, fakeFileStateHolder, fileFilter);
|
||||
|
||||
const filePath = "text_files/ignored_checkboxes.md";
|
||||
const currentText = "- [~] An ignored task\n - [~] Another sub-task also ignored";
|
||||
const previousTextInHolder = "- [~] An old ignored task";
|
||||
|
||||
fakeFileStateHolder.setInitialStates({ [filePath]: previousTextInHolder });
|
||||
|
||||
// Act
|
||||
const resultText = pipeline.applySyncLogic(currentText, filePath);
|
||||
|
||||
// Assert
|
||||
expect(resultText).toBe(currentText);
|
||||
expect(fakeFileStateHolder.getInternalState(filePath)).toBe(currentText);
|
||||
});
|
||||
});
|
||||
});
|
||||
35
__tests__/fakes/InMemoryFilePathStateHolder.ts
Normal file
35
__tests__/fakes/InMemoryFilePathStateHolder.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { IFilePathStateHolder } from "src/IFilePathStateHolder";
|
||||
|
||||
export class InMemoryFilePathStateHolder implements IFilePathStateHolder {
|
||||
private states: Map<string, string>;
|
||||
|
||||
constructor() {
|
||||
this.states = new Map<string, string>();
|
||||
}
|
||||
|
||||
public setByPath(filePath: string, text: string): void {
|
||||
console.log(`InMemoryFileStateHolder: Setting state for "${filePath}"`);
|
||||
this.states.set(filePath, text);
|
||||
}
|
||||
|
||||
public getByPath(filePath: string): string | undefined {
|
||||
const state = this.states.get(filePath);
|
||||
console.log(`InMemoryFileStateHolder: Getting state for "${filePath}". Found: ${!!state}`);
|
||||
return state;
|
||||
}
|
||||
|
||||
// Вспомогательные методы для тестов (не часть интерфейса, но полезны)
|
||||
public clear(): void {
|
||||
this.states.clear();
|
||||
}
|
||||
|
||||
public getInternalState(filePath: string): string | undefined {
|
||||
return this.states.get(filePath); // Для прямых проверок в тестах
|
||||
}
|
||||
|
||||
public setInitialStates(initialStates: Record<string, string>): void {
|
||||
for (const path in initialStates) {
|
||||
this.states.set(path, initialStates[path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +1,84 @@
|
|||
import { Mutex } from "async-mutex";
|
||||
import { TFile, Vault } from "obsidian";
|
||||
import { IFilePathStateHolder } from "./IFilePathStateHolder";
|
||||
|
||||
|
||||
export default class FileStateHolder {
|
||||
private map: Map<TFile, string>;
|
||||
private vault: Vault;
|
||||
private mutex: Mutex;
|
||||
export default class FileStateHolder implements IFilePathStateHolder{
|
||||
private map: Map<TFile, string>;
|
||||
private vault: Vault;
|
||||
private mutex: Mutex;
|
||||
|
||||
constructor(vault: Vault) {
|
||||
this.vault = vault;
|
||||
this.map = new Map();
|
||||
this.mutex = new Mutex();
|
||||
}
|
||||
constructor(vault: Vault) {
|
||||
this.vault = vault;
|
||||
this.map = new Map();
|
||||
this.mutex = new Mutex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the file's data if it hasn't been initialized yet.
|
||||
*
|
||||
* @param file - The file object to initialize.
|
||||
* @param text - Optional text content to associate with the file. If not provided, it will be read from the vault.
|
||||
* @returns A promise that resolves to `true` if the file was initialized, or `false` if it was already initialized.
|
||||
*/
|
||||
async initIfNeeded(file: TFile, text?: string): Promise<boolean> {
|
||||
if (this.has(file)) {
|
||||
return false;
|
||||
}
|
||||
let res = await this.mutex.runExclusive<boolean>(async () => {
|
||||
if (this.has(file)) {
|
||||
return false;
|
||||
}
|
||||
// console.log(`updateIfNeeded "${file.name}" start`);
|
||||
if (!text) {
|
||||
text = await this.vault.read(file);
|
||||
}
|
||||
this.set(file, text);
|
||||
return true;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* Initializes the file's data if it hasn't been initialized yet.
|
||||
*
|
||||
* @param file - The file object to initialize.
|
||||
* @param text - Optional text content to associate with the file. If not provided, it will be read from the vault.
|
||||
* @returns A promise that resolves to `true` if the file was initialized, or `false` if it was already initialized.
|
||||
*/
|
||||
async initIfNeeded(file: TFile, text?: string): Promise<boolean> {
|
||||
if (this.has(file)) {
|
||||
return false;
|
||||
}
|
||||
let res = await this.mutex.runExclusive<boolean>(async () => {
|
||||
if (this.has(file)) {
|
||||
return false;
|
||||
}
|
||||
// console.log(`updateIfNeeded "${file.name}" start`);
|
||||
if (!text) {
|
||||
text = await this.vault.read(file);
|
||||
}
|
||||
this.set(file, text);
|
||||
return true;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
has(file: TFile) {
|
||||
return this.map.has(file);
|
||||
}
|
||||
has(file: TFile) {
|
||||
return this.map.has(file);
|
||||
}
|
||||
|
||||
set(file: TFile, text: string) {
|
||||
if (text !== this.map.get(file)) {
|
||||
console.log(`File "${file.name}" load to holder`);
|
||||
this.map.set(file, text);
|
||||
}
|
||||
}
|
||||
set(file: TFile, text: string) {
|
||||
if (text !== this.map.get(file)) {
|
||||
console.log(`File "${file.name}" load to holder`);
|
||||
this.map.set(file, text);
|
||||
}
|
||||
}
|
||||
|
||||
get(file: TFile) {
|
||||
return this.map.get(file);
|
||||
}
|
||||
setByPath(filePath: string, text: string) {
|
||||
const file = this.vault.getFileByPath(filePath);
|
||||
if (file) {
|
||||
this.set(file, text);
|
||||
} else {
|
||||
throw new Error(`file not found by path: ${filePath}.`);
|
||||
}
|
||||
}
|
||||
|
||||
getAllFiles(): TFile[] {
|
||||
const keysIterator = this.map.keys();
|
||||
const keysArray = Array.from(keysIterator);
|
||||
return keysArray;
|
||||
}
|
||||
get(file: TFile) {
|
||||
return this.map.get(file);
|
||||
}
|
||||
|
||||
delete(file: TFile): boolean {
|
||||
const existed = this.map.delete(file);
|
||||
return existed;
|
||||
}
|
||||
}
|
||||
getByPath(filePath: string) {
|
||||
const file = this.vault.getFileByPath(filePath);
|
||||
if (file) {
|
||||
return this.get(file);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getAllFiles(): TFile[] {
|
||||
const keysIterator = this.map.keys();
|
||||
const keysArray = Array.from(keysIterator);
|
||||
return keysArray;
|
||||
}
|
||||
|
||||
delete(file: TFile): boolean {
|
||||
const existed = this.map.delete(file);
|
||||
return existed;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
16
src/IFilePathStateHolder.ts
Normal file
16
src/IFilePathStateHolder.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export interface IFilePathStateHolder {
|
||||
/**
|
||||
* Sets or updates the text state associated with a file identified by its path.
|
||||
* @param filePath - The path of the file.
|
||||
* @param text - The text content to store.
|
||||
* @throws Error if the file is not found by path (implementations may vary).
|
||||
*/
|
||||
setByPath(filePath: string, text: string): void;
|
||||
|
||||
/**
|
||||
* Retrieves the text state associated with a file identified by its path.
|
||||
* @param filePath - The path of the file.
|
||||
* @returns The stored text content, or `undefined` if not found or file not found.
|
||||
*/
|
||||
getByPath(filePath: string): string | undefined;
|
||||
}
|
||||
|
|
@ -1,24 +1,19 @@
|
|||
import { Mutex } from "async-mutex";
|
||||
import { Editor, EditorChange, MarkdownFileInfo, MarkdownView, TFile, Vault } from "obsidian";
|
||||
import { CheckboxUtils } from "./checkboxUtils";
|
||||
import FileStateHolder from "./FileStateHolder";
|
||||
import { FileFilter } from "./FileFilter";
|
||||
import TextSyncPipeline from "./TextSyncPipeline";
|
||||
|
||||
export default class SyncController {
|
||||
// private plugin: CheckboxSyncPlugin;//delete
|
||||
private vault: Vault;
|
||||
private checkboxUtils: CheckboxUtils;
|
||||
private fileStateHolder: FileStateHolder;
|
||||
private fileFilter: FileFilter;
|
||||
textSyncPipeline: TextSyncPipeline
|
||||
|
||||
private mutex: Mutex;
|
||||
|
||||
constructor(vault: Vault, checkboxUtils: CheckboxUtils, fileStateHolder: FileStateHolder, fileFilter: FileFilter) {
|
||||
// this.plugin = plugin;//delete
|
||||
constructor(vault: Vault, checkboxUtils: CheckboxUtils, textSyncPipeline: TextSyncPipeline) {
|
||||
this.vault = vault;
|
||||
this.checkboxUtils = checkboxUtils;
|
||||
this.fileStateHolder = fileStateHolder;
|
||||
this.fileFilter = fileFilter;
|
||||
this.textSyncPipeline = textSyncPipeline;
|
||||
this.mutex = new Mutex();
|
||||
}
|
||||
|
||||
|
|
@ -27,27 +22,10 @@ export default class SyncController {
|
|||
return;
|
||||
}
|
||||
await this.mutex.runExclusive(async () => {
|
||||
const file = info.file!;
|
||||
console.log(`sync editor "${file.path}" start.`);
|
||||
|
||||
const text = editor.getValue();
|
||||
|
||||
if (!this.fileFilter.isPathAllowed(file.path)) {
|
||||
console.log(`sync editor "${file.path}" skip, path is not allowed.`);
|
||||
this.fileStateHolder.set(file, text);
|
||||
return;
|
||||
}
|
||||
|
||||
const textBefore = this.fileStateHolder.get(file);
|
||||
|
||||
let newText = this.checkboxUtils.syncText(text, textBefore);
|
||||
this.fileStateHolder.set(file, newText);
|
||||
|
||||
if (newText === text) {
|
||||
console.log(`sync editor "${file.basename}" stop. new text equals old text.`);
|
||||
} else {
|
||||
this.editEditor(editor, text, newText);
|
||||
console.log(`syncEditor "${file.basename}" stop.`);
|
||||
const currentText = editor.getValue();
|
||||
const resultingText = this.textSyncPipeline.applySyncLogic(currentText, info.file!.path);
|
||||
if (resultingText !== currentText) {
|
||||
this.editEditor(editor, currentText, resultingText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -57,21 +35,9 @@ export default class SyncController {
|
|||
return;
|
||||
}
|
||||
await this.mutex.runExclusive(async () => {
|
||||
console.log(`sync file "${file.path}" start.`);
|
||||
|
||||
if (!this.fileFilter.isPathAllowed(file.path)) {
|
||||
console.log(`sync file "${file.path}" skip, path is not allowed.`);
|
||||
const text = await this.vault.read(file);
|
||||
this.fileStateHolder.set(file, text);
|
||||
} else {
|
||||
const newText = await this.vault.process(file, (text) => {
|
||||
let textBefore = this.fileStateHolder.get(file);
|
||||
let newText = this.checkboxUtils.syncText(text, textBefore);
|
||||
return newText;
|
||||
});
|
||||
this.fileStateHolder.set(file, newText);
|
||||
}
|
||||
console.log(`sync file "${file.basename}" stop.`);
|
||||
this.vault.process(file, (currentText) => {
|
||||
return this.textSyncPipeline.applySyncLogic(currentText, file.path);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
40
src/TextSyncPipeline.ts
Normal file
40
src/TextSyncPipeline.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { CheckboxUtils } from "./checkboxUtils";
|
||||
import { FileFilter } from "./FileFilter";
|
||||
import { IFilePathStateHolder } from "./IFilePathStateHolder";
|
||||
|
||||
export default class TextSyncPipeline {
|
||||
private checkboxUtils: CheckboxUtils;
|
||||
private fileStateHolder: IFilePathStateHolder;
|
||||
private fileFilter: FileFilter;
|
||||
|
||||
|
||||
constructor(checkboxUtils: CheckboxUtils, fileStateHolder: IFilePathStateHolder, fileFilter: FileFilter) {
|
||||
this.checkboxUtils = checkboxUtils;
|
||||
this.fileStateHolder = fileStateHolder;
|
||||
this.fileFilter = fileFilter;
|
||||
}
|
||||
|
||||
public applySyncLogic(currentText: string, filePath: string): string {
|
||||
return this.fileStateHolderDecorator(currentText, filePath);
|
||||
}
|
||||
|
||||
private coreDecorator(currentText: string, textBefore: string | undefined): string {
|
||||
const resultingText = this.checkboxUtils.syncText(currentText, textBefore);
|
||||
return resultingText;
|
||||
}
|
||||
|
||||
private pathAllowedDecorator(currentText: string, textBefore: string | undefined, filePath: string): string {
|
||||
if (!this.fileFilter.isPathAllowed(filePath)) {
|
||||
console.log(`pathAllowedDecorator "${filePath}" skip, path is not allowed.`);
|
||||
return currentText;
|
||||
}
|
||||
return this.coreDecorator(currentText, textBefore);
|
||||
}
|
||||
|
||||
private fileStateHolderDecorator(currentText: string, filePath: string): string {
|
||||
const textBefore = this.fileStateHolder.getByPath(filePath);
|
||||
const resultingText = this.pathAllowedDecorator(currentText, textBefore, filePath);
|
||||
this.fileStateHolder.setByPath(filePath, resultingText);
|
||||
return resultingText;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import { CheckboxSyncPluginSettingTab } from "./ui/CheckboxSyncPluginSettingTab"
|
|||
import SyncController from "./SyncController";
|
||||
import { CheckboxSyncPluginSettings, DEFAULT_SETTINGS } from "./types";
|
||||
import { FileFilter } from "./FileFilter";
|
||||
import TextSyncPipeline from "./TextSyncPipeline";
|
||||
|
||||
const DEBUG_FLAG_NAME = 'CHECKBOX_SYNC_DEBUG';
|
||||
|
||||
|
|
@ -27,6 +28,7 @@ export default class CheckboxSyncPlugin extends Plugin {
|
|||
private fileLoadEventHandler: FileLoadEventHandler;
|
||||
private fileChangeEventHandler: FileChangeEventHandler;
|
||||
private fileFilter: FileFilter;
|
||||
private textSyncPipeline: TextSyncPipeline;
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
|
|
@ -34,7 +36,8 @@ export default class CheckboxSyncPlugin extends Plugin {
|
|||
this.fileFilter = new FileFilter(this.settings);
|
||||
this.fileStateHolder = new FileStateHolder(this.app.vault);
|
||||
this.checkboxUtils = new CheckboxUtils(this.settings);
|
||||
this.syncController = new SyncController(this.app.vault, this.checkboxUtils, this.fileStateHolder, this.fileFilter);
|
||||
this.textSyncPipeline = new TextSyncPipeline(this.checkboxUtils,this.fileStateHolder, this.fileFilter);
|
||||
this.syncController = new SyncController(this.app.vault, this.checkboxUtils, this.textSyncPipeline);
|
||||
this.fileLoadEventHandler = new FileLoadEventHandler(this, this.app, this.syncController, this.fileStateHolder);
|
||||
this.fileChangeEventHandler = new FileChangeEventHandler(this, this.app, this.syncController, this.fileStateHolder);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue