Added rule matcher and implemented logic to move files if they fit a regex and use regex groups

This commit is contained in:
Al0cam 2024-11-14 17:20:32 +01:00
parent 4abc23113c
commit 9908d8b924
3 changed files with 154 additions and 10 deletions

View file

@ -1,3 +1,4 @@
import { MovingRule } from "Models/MovingRule";
import { App, Notice, TFile, TFolder } from "obsidian";

94
Utils/RuleMatcherUtil.ts Normal file
View file

@ -0,0 +1,94 @@
import { MovingRule } from "Models/MovingRule";
import { TFile } from "obsidian";
class RuleMatcherUtil {
private static instance: RuleMatcherUtil;
private constructor() {}
public static getInstance(): RuleMatcherUtil {
if (!RuleMatcherUtil.instance) {
RuleMatcherUtil.instance = new RuleMatcherUtil();
}
return RuleMatcherUtil.instance;
}
/**
* Returns the first rule that matches the file
* If no rule matches, returns null
*
* @param file
* @param rules
* @returns MovingRule | null
*/
public getMatchingRule(file: TFile, rules: MovingRule[]): MovingRule | null {
for(let rule of rules) {
if(rule.regex == null || rule.regex == "") {
console.error("Rule does not have a regex: ", rule);
continue;
} else if(!this.isValidRegex(rule.regex)) {
console.error("Rule has an invalid regex: ", rule);
continue;
}
console.log("Checking if matches: ", file.name.match(rule.regex));
console.log("Rule: ", rule);
if(file.name.match(rule.regex)) {
return rule;
}
}
return null;
}
/**
* Returns the regex groups of the file that match the rule
* If no groups match, returns an empty array
*
* @param file
* @param rule
* @returns string[]
*/
public getGroupMatches(file: TFile, rule: MovingRule): RegExpMatchArray | null {
let matches = file.name.match(rule.regex);
return matches;
}
/**
* Checks if the regex pattern is valid
* Meaning, syntax errors are caught, but not logical errors
*
* @param pattern
* @returns boolean
*/
private isValidRegex(pattern: string): boolean {
try {
new RegExp(pattern);
return true;
} catch (e) {
if (e instanceof SyntaxError) {
console.error(`Invalid regex pattern: ${e.message}`);
}
return false;
}
}
// TODO: implement the distinction between named and unnamed groups
public constructFinalDesinationPath(rule: MovingRule, matches: RegExpMatchArray): string {
let folderPath = rule.folder;
return folderPath;
}
private hasUnnamedGroups(pattern: string): boolean {
return /\(/.test(pattern);
}
private getNamedGroups(pattern: string): RegExpMatchArray | null {
return pattern.match(/\(\?<\w+>/g);
}
private getUnnamedGroups(pattern: string): RegExpMatchArray | null {
return pattern.match(/\(/g);
}
}
const ruleMatcherUtil = RuleMatcherUtil.getInstance();
export default ruleMatcherUtil;

69
main.ts
View file

@ -2,6 +2,7 @@ import { Plugin, TFile } from "obsidian";
import { AutoMoverSettings, DEFAULT_SETTINGS } from "Settings/Settings";
import { SettingsTab } from "Settings/SettingsTab";
import movingUtil from "Utils/MovingUtil";
import ruleMatcherUtil from "Utils/RuleMatcherUtil";
export default class AutoMoverPlugin extends Plugin {
settings: AutoMoverSettings;
@ -9,19 +10,43 @@ export default class AutoMoverPlugin extends Plugin {
async onload() {
console.log('loading plugin')
movingUtil.init(this.app);
// create file
// let newFile: TFile;
// if(this.app.vault.getAbstractFileByPath("Something.md") === null) {
// newFile = await this.app.vault.create("./Something.md", "This is a test file")
// } else {
// newFile = this.app.vault.getAbstractFileByPath("Something.md") as TFile;
// }
// delete file
// await this.app.vault.delete(this.app.vault.getAbstractFileByPath("amFolder/Something.md") as TFile);
/**
* Loading settings and creating the settings tab
*/
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
this.addSettingTab(new SettingsTab(this.app, this));
console.log(this.settings);
// TODO: chec if there are any settings on when to apply the rules,
// because if you arent doing on open, save, close or create, then there is no point in checking for rules
if(this.checkIfMovingTriggersAreEnabled() && this.checkIfThereAreRulesToApply() && this.checkIfRulesAreValid()) {
if(this.settings.moveOnOpen) {
this.registerEvent(this.app.workspace.on("file-open", (file: TFile) => {
if(file == null || file.path == null)
return;
console.log("File opened: ", file.path);
// Question: what if there are multiple rules that apply to the same file?
// so far only the first one is applied and the rest are ignored
// i can live with that
// TODO: what if the file is already in the correct folder?
// do nothing...
// TODO: what if the folder which the file is supposed to be moved to does not exist?
// create the whole path to the folder and the folder itself
// having it do nothing would be conflicting with the idea to use regex groups in the first place
let rule = ruleMatcherUtil.getMatchingRule(file, this.settings.movingRules);
if(rule != null) {
// TODO: Construct the folder path using the regex groups
let matches = ruleMatcherUtil.getGroupMatches(file, rule);
console.log("Matches: ", matches);
console.log("Moving file to: ", rule.folder);
// movingUtil.moveFile(file, rule.folder);
}
}));
}
}
}
async asyncloadSettings() {
@ -31,4 +56,28 @@ export default class AutoMoverPlugin extends Plugin {
async onunload() {
console.log('unloading plugin')
}
/**
* No point in doing anything if there is no trigger set which will cause you to move the files
* @returns boolean
*/
checkIfMovingTriggersAreEnabled(): boolean {
return this.settings.moveOnClose || this.settings.moveOnCreate || this.settings.moveOnOpen || this.settings.moveOnSave;
}
/**
* If there are no rules to apply, then there is no point in checking for them
* @returns boolean
*/
checkIfThereAreRulesToApply(): boolean {
return this.settings.movingRules.length > 0;
}
/**
* Superficail check if the rules are valid
* @returns boolean
*/
checkIfRulesAreValid(): boolean {
return this.settings.movingRules.every(rule => rule.regex !== '' && rule.folder !== '');
}
}