@real1ty-obsidian-plugins/utils 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/evaluator/base.d.ts +22 -0
- package/dist/core/evaluator/base.d.ts.map +1 -0
- package/dist/core/evaluator/base.js +52 -0
- package/dist/core/evaluator/base.js.map +1 -0
- package/dist/core/evaluator/color.d.ts +19 -0
- package/dist/core/evaluator/color.d.ts.map +1 -0
- package/dist/core/evaluator/color.js +25 -0
- package/dist/core/evaluator/color.js.map +1 -0
- package/dist/core/evaluator/excluded.d.ts +32 -0
- package/dist/core/evaluator/excluded.d.ts.map +1 -0
- package/dist/core/evaluator/excluded.js +41 -0
- package/dist/core/evaluator/excluded.js.map +1 -0
- package/dist/core/evaluator/filter.d.ts +15 -0
- package/dist/core/evaluator/filter.d.ts.map +1 -0
- package/dist/core/evaluator/filter.js +27 -0
- package/dist/core/evaluator/filter.js.map +1 -0
- package/dist/core/evaluator/included.d.ts +36 -0
- package/dist/core/evaluator/included.d.ts.map +1 -0
- package/dist/core/evaluator/included.js +51 -0
- package/dist/core/evaluator/included.js.map +1 -0
- package/dist/core/evaluator/index.d.ts +6 -0
- package/dist/core/evaluator/index.d.ts.map +1 -0
- package/dist/core/evaluator/index.js +6 -0
- package/dist/core/evaluator/index.js.map +1 -0
- package/dist/core/expression-utils.d.ts +17 -0
- package/dist/core/expression-utils.d.ts.map +1 -0
- package/dist/core/expression-utils.js +40 -0
- package/dist/core/expression-utils.js.map +1 -0
- package/dist/core/frontmatter-value.d.ts +143 -0
- package/dist/core/frontmatter-value.d.ts.map +1 -0
- package/dist/core/frontmatter-value.js +408 -0
- package/dist/core/frontmatter-value.js.map +1 -0
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -1
- package/dist/core/index.js.map +1 -1
- package/dist/file/index.d.ts +1 -0
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +1 -0
- package/dist/file/index.js.map +1 -1
- package/dist/file/link-parser.d.ts +26 -0
- package/dist/file/link-parser.d.ts.map +1 -1
- package/dist/file/link-parser.js +59 -0
- package/dist/file/link-parser.js.map +1 -1
- package/dist/file/property-utils.d.ts +55 -0
- package/dist/file/property-utils.d.ts.map +1 -0
- package/dist/file/property-utils.js +90 -0
- package/dist/file/property-utils.js.map +1 -0
- package/package.json +2 -1
- package/src/core/evaluator/base.ts +71 -0
- package/src/core/evaluator/color.ts +37 -0
- package/src/core/evaluator/excluded.ts +63 -0
- package/src/core/evaluator/filter.ts +33 -0
- package/src/core/evaluator/included.ts +74 -0
- package/src/core/evaluator/index.ts +5 -0
- package/src/core/expression-utils.ts +53 -0
- package/src/core/frontmatter-value.ts +528 -0
- package/src/core/index.ts +3 -1
- package/src/file/index.ts +1 -0
- package/src/file/link-parser.ts +73 -0
- package/src/file/property-utils.ts +114 -0
- package/dist/core/evaluator-base.d.ts +0 -52
- package/dist/core/evaluator-base.d.ts.map +0 -1
- package/dist/core/evaluator-base.js +0 -84
- package/dist/core/evaluator-base.js.map +0 -1
- package/src/core/evaluator-base.ts +0 -118
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { normalizePath } from "obsidian";
|
|
2
|
+
|
|
3
|
+
import { formatWikiLink, parsePropertyLinks } from "./link-parser";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Adds a link to a property, avoiding duplicates using normalized path comparison.
|
|
7
|
+
* Prevents cycles and duplicate relationships by comparing normalized paths.
|
|
8
|
+
*
|
|
9
|
+
* **Important**: linkPath should be WITHOUT .md extension (wikilink format).
|
|
10
|
+
*
|
|
11
|
+
* @param currentValue - The current property value (can be string, string[], or undefined)
|
|
12
|
+
* @param linkPath - The file path to add (without .md extension, e.g., "folder/file")
|
|
13
|
+
* @returns New array with link added, or same array if link already exists
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* addLinkToProperty(undefined, "MyNote") // ["[[MyNote]]"]
|
|
18
|
+
* addLinkToProperty("[[Note1]]", "Note2") // ["[[Note1]]", "[[Note2]]"]
|
|
19
|
+
* addLinkToProperty(["[[Note1]]"], "Note2") // ["[[Note1]]", "[[Note2]]"]
|
|
20
|
+
* addLinkToProperty(["[[Note1]]"], "Note1") // ["[[Note1]]"] (no change - duplicate prevented)
|
|
21
|
+
* addLinkToProperty(["[[Folder/Note]]"], "folder/note") // ["[[Folder/Note]]", "[[folder/note|note]]"] (case-sensitive, different entry)
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function addLinkToProperty(
|
|
25
|
+
currentValue: string | string[] | undefined,
|
|
26
|
+
linkPath: string
|
|
27
|
+
): string[] {
|
|
28
|
+
// Handle undefined or null
|
|
29
|
+
if (currentValue === undefined || currentValue === null) {
|
|
30
|
+
return [formatWikiLink(linkPath)];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Normalize to array
|
|
34
|
+
const currentArray = Array.isArray(currentValue) ? currentValue : [currentValue];
|
|
35
|
+
|
|
36
|
+
const existingPaths = parsePropertyLinks(currentArray);
|
|
37
|
+
|
|
38
|
+
// Normalize paths for comparison to prevent duplicates with different casing or separators
|
|
39
|
+
const normalizedLinkPath = normalizePath(linkPath);
|
|
40
|
+
|
|
41
|
+
const normalizedExistingPaths = existingPaths.map((p) => normalizePath(p));
|
|
42
|
+
|
|
43
|
+
// Only add if not already present (using normalized path comparison)
|
|
44
|
+
if (!normalizedExistingPaths.includes(normalizedLinkPath)) {
|
|
45
|
+
return [...currentArray, formatWikiLink(linkPath)];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return currentArray;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Removes a link from a property using normalized path comparison.
|
|
53
|
+
*
|
|
54
|
+
* @param currentValue - The current property value (can be string, string[], or undefined)
|
|
55
|
+
* @param linkPath - The file path to remove (without .md extension)
|
|
56
|
+
* @returns New array with link removed (can be empty)
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* removeLinkFromProperty(["[[Note1]]", "[[Note2]]"], "Note1") // ["[[Note2]]"]
|
|
61
|
+
* removeLinkFromProperty(["[[Note1]]"], "Note1") // []
|
|
62
|
+
* removeLinkFromProperty("[[Note1]]", "Note1") // []
|
|
63
|
+
* removeLinkFromProperty(undefined, "Note1") // []
|
|
64
|
+
* removeLinkFromProperty(["[[Folder/Note]]"], "Folder/Note") // [] (case-sensitive removal)
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export function removeLinkFromProperty(
|
|
68
|
+
currentValue: string | string[] | undefined,
|
|
69
|
+
linkPath: string
|
|
70
|
+
): string[] {
|
|
71
|
+
if (currentValue === undefined || currentValue === null) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Normalize to array
|
|
76
|
+
const currentArray = Array.isArray(currentValue) ? currentValue : [currentValue];
|
|
77
|
+
|
|
78
|
+
const normalizedLinkPath = normalizePath(linkPath);
|
|
79
|
+
|
|
80
|
+
return currentArray.filter((item) => {
|
|
81
|
+
const parsed = parsePropertyLinks([item])[0];
|
|
82
|
+
|
|
83
|
+
if (!parsed) return true; // Keep invalid entries
|
|
84
|
+
|
|
85
|
+
return normalizePath(parsed) !== normalizedLinkPath;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Checks if a link exists in a property using normalized path comparison.
|
|
91
|
+
*
|
|
92
|
+
* @param currentValue - The current property value (can be string, string[], or undefined)
|
|
93
|
+
* @param linkPath - The file path to check (without .md extension)
|
|
94
|
+
* @returns True if the link exists
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* hasLinkInProperty(["[[Note1]]", "[[Note2]]"], "Note1") // true
|
|
99
|
+
* hasLinkInProperty("[[Note1]]", "Note1") // true
|
|
100
|
+
* hasLinkInProperty([], "Note1") // false
|
|
101
|
+
* hasLinkInProperty(undefined, "Note1") // false
|
|
102
|
+
* hasLinkInProperty(["[[Folder/Note]]"], "Folder/Note") // true (case-sensitive match)
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export function hasLinkInProperty(
|
|
106
|
+
currentValue: string | string[] | undefined,
|
|
107
|
+
linkPath: string
|
|
108
|
+
): boolean {
|
|
109
|
+
const existingPaths = parsePropertyLinks(currentValue);
|
|
110
|
+
|
|
111
|
+
const normalizedLinkPath = normalizePath(linkPath);
|
|
112
|
+
|
|
113
|
+
return existingPaths.some((path) => normalizePath(path) === normalizedLinkPath);
|
|
114
|
+
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { BehaviorSubject } from "rxjs";
|
|
2
|
-
export interface BaseRule {
|
|
3
|
-
id: string;
|
|
4
|
-
expression: string;
|
|
5
|
-
enabled: boolean;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Generic base class for evaluating JavaScript expressions against frontmatter objects.
|
|
9
|
-
* Provides reactive compilation of rules via RxJS subscription and safe evaluation.
|
|
10
|
-
*/
|
|
11
|
-
export declare abstract class BaseEvaluator<TRule extends BaseRule, TSettings> {
|
|
12
|
-
protected compiledRules: Array<TRule & {
|
|
13
|
-
fn: (frontmatter: Record<string, unknown>) => boolean;
|
|
14
|
-
}>;
|
|
15
|
-
private settingsSubscription;
|
|
16
|
-
constructor(settingsStore: BehaviorSubject<TSettings>);
|
|
17
|
-
/**
|
|
18
|
-
* Extract rules from settings object. Must be implemented by subclasses.
|
|
19
|
-
*/
|
|
20
|
-
protected abstract extractRules(settings: TSettings): TRule[];
|
|
21
|
-
/**
|
|
22
|
-
* Compile rules into executable functions with error handling.
|
|
23
|
-
*/
|
|
24
|
-
private compileRules;
|
|
25
|
-
/**
|
|
26
|
-
* Evaluate a single rule against frontmatter. Returns the result or undefined if error.
|
|
27
|
-
*/
|
|
28
|
-
protected evaluateRule(rule: TRule & {
|
|
29
|
-
fn: (frontmatter: Record<string, unknown>) => boolean;
|
|
30
|
-
}, frontmatter: Record<string, unknown>): boolean | undefined;
|
|
31
|
-
/**
|
|
32
|
-
* Convert evaluation result to boolean - only explicit true is considered truthy.
|
|
33
|
-
*/
|
|
34
|
-
protected isTruthy(result: boolean | undefined): boolean;
|
|
35
|
-
/**
|
|
36
|
-
* Clean up subscriptions and compiled rules.
|
|
37
|
-
*/
|
|
38
|
-
destroy(): void;
|
|
39
|
-
/**
|
|
40
|
-
* Get the number of active (compiled) rules.
|
|
41
|
-
*/
|
|
42
|
-
getActiveRuleCount(): number;
|
|
43
|
-
/**
|
|
44
|
-
* Get information about all rules including their validity.
|
|
45
|
-
*/
|
|
46
|
-
getRuleInfo(): Array<{
|
|
47
|
-
expression: string;
|
|
48
|
-
isValid: boolean;
|
|
49
|
-
enabled: boolean;
|
|
50
|
-
}>;
|
|
51
|
-
}
|
|
52
|
-
//# sourceMappingURL=evaluator-base.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"evaluator-base.d.ts","sourceRoot":"","sources":["../../src/core/evaluator-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,MAAM,CAAC;AAE1D,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,8BAAsB,aAAa,CAAC,KAAK,SAAS,QAAQ,EAAE,SAAS;IACpE,SAAS,CAAC,aAAa,EAAE,KAAK,CAC7B,KAAK,GAAG;QAAE,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAA;KAAE,CACjE,CAAM;IACP,OAAO,CAAC,oBAAoB,CAA6B;gBAE7C,aAAa,EAAE,eAAe,CAAC,SAAS,CAAC;IAUrD;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,GAAG,KAAK,EAAE;IAE7D;;OAEG;IACH,OAAO,CAAC,YAAY;IA6BpB;;OAEG;IACH,SAAS,CAAC,YAAY,CACrB,IAAI,EAAE,KAAK,GAAG;QAAE,EAAE,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAA;KAAE,EACvE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,GAAG,SAAS;IAStB;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO;IAIxD;;OAEG;IACH,OAAO,IAAI,IAAI;IAQf;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;OAEG;IACH,WAAW,IAAI,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAShF"}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic base class for evaluating JavaScript expressions against frontmatter objects.
|
|
3
|
-
* Provides reactive compilation of rules via RxJS subscription and safe evaluation.
|
|
4
|
-
*/
|
|
5
|
-
export class BaseEvaluator {
|
|
6
|
-
constructor(settingsStore) {
|
|
7
|
-
this.compiledRules = [];
|
|
8
|
-
this.settingsSubscription = null;
|
|
9
|
-
const initialRules = this.extractRules(settingsStore.value);
|
|
10
|
-
this.compileRules(initialRules);
|
|
11
|
-
this.settingsSubscription = settingsStore.subscribe((settings) => {
|
|
12
|
-
const newRules = this.extractRules(settings);
|
|
13
|
-
this.compileRules(newRules);
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Compile rules into executable functions with error handling.
|
|
18
|
-
*/
|
|
19
|
-
compileRules(rules) {
|
|
20
|
-
this.compiledRules = [];
|
|
21
|
-
for (const rule of rules) {
|
|
22
|
-
if (!rule.enabled || !rule.expression.trim())
|
|
23
|
-
continue;
|
|
24
|
-
try {
|
|
25
|
-
const cleanExpression = rule.expression.trim();
|
|
26
|
-
// Create a function that takes 'fm' (frontmatter) as parameter
|
|
27
|
-
// and evaluates the expression in that context
|
|
28
|
-
const fn = new Function("fm", `return (${cleanExpression});`);
|
|
29
|
-
// Test the function with a dummy object to catch syntax errors early
|
|
30
|
-
fn({});
|
|
31
|
-
this.compiledRules.push(Object.assign(Object.assign({}, rule), { expression: cleanExpression, fn }));
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
console.warn(`Invalid rule expression "${rule.expression}":`, error);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Evaluate a single rule against frontmatter. Returns the result or undefined if error.
|
|
40
|
-
*/
|
|
41
|
-
evaluateRule(rule, frontmatter) {
|
|
42
|
-
try {
|
|
43
|
-
return rule.fn(frontmatter);
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
console.warn(`Error evaluating rule "${rule.expression}":`, error);
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Convert evaluation result to boolean - only explicit true is considered truthy.
|
|
52
|
-
*/
|
|
53
|
-
isTruthy(result) {
|
|
54
|
-
return result === true;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Clean up subscriptions and compiled rules.
|
|
58
|
-
*/
|
|
59
|
-
destroy() {
|
|
60
|
-
if (this.settingsSubscription) {
|
|
61
|
-
this.settingsSubscription.unsubscribe();
|
|
62
|
-
this.settingsSubscription = null;
|
|
63
|
-
}
|
|
64
|
-
this.compiledRules = [];
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Get the number of active (compiled) rules.
|
|
68
|
-
*/
|
|
69
|
-
getActiveRuleCount() {
|
|
70
|
-
return this.compiledRules.length;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Get information about all rules including their validity.
|
|
74
|
-
*/
|
|
75
|
-
getRuleInfo() {
|
|
76
|
-
const validExpressions = new Set(this.compiledRules.map((r) => r.expression));
|
|
77
|
-
return this.compiledRules.map((rule) => ({
|
|
78
|
-
expression: rule.expression,
|
|
79
|
-
isValid: validExpressions.has(rule.expression),
|
|
80
|
-
enabled: rule.enabled,
|
|
81
|
-
}));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
//# sourceMappingURL=evaluator-base.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"evaluator-base.js","sourceRoot":"","sources":["../../src/core/evaluator-base.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorSubject, Subscription } from \"rxjs\";\n\nexport interface BaseRule {\n\tid: string;\n\texpression: string;\n\tenabled: boolean;\n}\n\n/**\n * Generic base class for evaluating JavaScript expressions against frontmatter objects.\n * Provides reactive compilation of rules via RxJS subscription and safe evaluation.\n */\nexport abstract class BaseEvaluator<TRule extends BaseRule, TSettings> {\n\tprotected compiledRules: Array<\n\t\tTRule & { fn: (frontmatter: Record<string, unknown>) => boolean }\n\t> = [];\n\tprivate settingsSubscription: Subscription | null = null;\n\n\tconstructor(settingsStore: BehaviorSubject<TSettings>) {\n\t\tconst initialRules = this.extractRules(settingsStore.value);\n\t\tthis.compileRules(initialRules);\n\n\t\tthis.settingsSubscription = settingsStore.subscribe((settings) => {\n\t\t\tconst newRules = this.extractRules(settings);\n\t\t\tthis.compileRules(newRules);\n\t\t});\n\t}\n\n\t/**\n\t * Extract rules from settings object. Must be implemented by subclasses.\n\t */\n\tprotected abstract extractRules(settings: TSettings): TRule[];\n\n\t/**\n\t * Compile rules into executable functions with error handling.\n\t */\n\tprivate compileRules(rules: TRule[]): void {\n\t\tthis.compiledRules = [];\n\n\t\tfor (const rule of rules) {\n\t\t\tif (!rule.enabled || !rule.expression.trim()) continue;\n\n\t\t\ttry {\n\t\t\t\tconst cleanExpression = rule.expression.trim();\n\n\t\t\t\t// Create a function that takes 'fm' (frontmatter) as parameter\n\t\t\t\t// and evaluates the expression in that context\n\t\t\t\tconst fn = new Function(\"fm\", `return (${cleanExpression});`) as (\n\t\t\t\t\tfrontmatter: Record<string, unknown>\n\t\t\t\t) => boolean;\n\n\t\t\t\t// Test the function with a dummy object to catch syntax errors early\n\t\t\t\tfn({});\n\n\t\t\t\tthis.compiledRules.push({\n\t\t\t\t\t...rule,\n\t\t\t\t\texpression: cleanExpression,\n\t\t\t\t\tfn,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(`Invalid rule expression \"${rule.expression}\":`, error);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Evaluate a single rule against frontmatter. Returns the result or undefined if error.\n\t */\n\tprotected evaluateRule(\n\t\trule: TRule & { fn: (frontmatter: Record<string, unknown>) => boolean },\n\t\tfrontmatter: Record<string, unknown>\n\t): boolean | undefined {\n\t\ttry {\n\t\t\treturn rule.fn(frontmatter);\n\t\t} catch (error) {\n\t\t\tconsole.warn(`Error evaluating rule \"${rule.expression}\":`, error);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Convert evaluation result to boolean - only explicit true is considered truthy.\n\t */\n\tprotected isTruthy(result: boolean | undefined): boolean {\n\t\treturn result === true;\n\t}\n\n\t/**\n\t * Clean up subscriptions and compiled rules.\n\t */\n\tdestroy(): void {\n\t\tif (this.settingsSubscription) {\n\t\t\tthis.settingsSubscription.unsubscribe();\n\t\t\tthis.settingsSubscription = null;\n\t\t}\n\t\tthis.compiledRules = [];\n\t}\n\n\t/**\n\t * Get the number of active (compiled) rules.\n\t */\n\tgetActiveRuleCount(): number {\n\t\treturn this.compiledRules.length;\n\t}\n\n\t/**\n\t * Get information about all rules including their validity.\n\t */\n\tgetRuleInfo(): Array<{ expression: string; isValid: boolean; enabled: boolean }> {\n\t\tconst validExpressions = new Set(this.compiledRules.map((r) => r.expression));\n\n\t\treturn this.compiledRules.map((rule) => ({\n\t\t\texpression: rule.expression,\n\t\t\tisValid: validExpressions.has(rule.expression),\n\t\t\tenabled: rule.enabled,\n\t\t}));\n\t}\n}\n"]}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import type { BehaviorSubject, Subscription } from "rxjs";
|
|
2
|
-
|
|
3
|
-
export interface BaseRule {
|
|
4
|
-
id: string;
|
|
5
|
-
expression: string;
|
|
6
|
-
enabled: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Generic base class for evaluating JavaScript expressions against frontmatter objects.
|
|
11
|
-
* Provides reactive compilation of rules via RxJS subscription and safe evaluation.
|
|
12
|
-
*/
|
|
13
|
-
export abstract class BaseEvaluator<TRule extends BaseRule, TSettings> {
|
|
14
|
-
protected compiledRules: Array<
|
|
15
|
-
TRule & { fn: (frontmatter: Record<string, unknown>) => boolean }
|
|
16
|
-
> = [];
|
|
17
|
-
private settingsSubscription: Subscription | null = null;
|
|
18
|
-
|
|
19
|
-
constructor(settingsStore: BehaviorSubject<TSettings>) {
|
|
20
|
-
const initialRules = this.extractRules(settingsStore.value);
|
|
21
|
-
this.compileRules(initialRules);
|
|
22
|
-
|
|
23
|
-
this.settingsSubscription = settingsStore.subscribe((settings) => {
|
|
24
|
-
const newRules = this.extractRules(settings);
|
|
25
|
-
this.compileRules(newRules);
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Extract rules from settings object. Must be implemented by subclasses.
|
|
31
|
-
*/
|
|
32
|
-
protected abstract extractRules(settings: TSettings): TRule[];
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Compile rules into executable functions with error handling.
|
|
36
|
-
*/
|
|
37
|
-
private compileRules(rules: TRule[]): void {
|
|
38
|
-
this.compiledRules = [];
|
|
39
|
-
|
|
40
|
-
for (const rule of rules) {
|
|
41
|
-
if (!rule.enabled || !rule.expression.trim()) continue;
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const cleanExpression = rule.expression.trim();
|
|
45
|
-
|
|
46
|
-
// Create a function that takes 'fm' (frontmatter) as parameter
|
|
47
|
-
// and evaluates the expression in that context
|
|
48
|
-
const fn = new Function("fm", `return (${cleanExpression});`) as (
|
|
49
|
-
frontmatter: Record<string, unknown>
|
|
50
|
-
) => boolean;
|
|
51
|
-
|
|
52
|
-
// Test the function with a dummy object to catch syntax errors early
|
|
53
|
-
fn({});
|
|
54
|
-
|
|
55
|
-
this.compiledRules.push({
|
|
56
|
-
...rule,
|
|
57
|
-
expression: cleanExpression,
|
|
58
|
-
fn,
|
|
59
|
-
});
|
|
60
|
-
} catch (error) {
|
|
61
|
-
console.warn(`Invalid rule expression "${rule.expression}":`, error);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Evaluate a single rule against frontmatter. Returns the result or undefined if error.
|
|
68
|
-
*/
|
|
69
|
-
protected evaluateRule(
|
|
70
|
-
rule: TRule & { fn: (frontmatter: Record<string, unknown>) => boolean },
|
|
71
|
-
frontmatter: Record<string, unknown>
|
|
72
|
-
): boolean | undefined {
|
|
73
|
-
try {
|
|
74
|
-
return rule.fn(frontmatter);
|
|
75
|
-
} catch (error) {
|
|
76
|
-
console.warn(`Error evaluating rule "${rule.expression}":`, error);
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Convert evaluation result to boolean - only explicit true is considered truthy.
|
|
83
|
-
*/
|
|
84
|
-
protected isTruthy(result: boolean | undefined): boolean {
|
|
85
|
-
return result === true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Clean up subscriptions and compiled rules.
|
|
90
|
-
*/
|
|
91
|
-
destroy(): void {
|
|
92
|
-
if (this.settingsSubscription) {
|
|
93
|
-
this.settingsSubscription.unsubscribe();
|
|
94
|
-
this.settingsSubscription = null;
|
|
95
|
-
}
|
|
96
|
-
this.compiledRules = [];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Get the number of active (compiled) rules.
|
|
101
|
-
*/
|
|
102
|
-
getActiveRuleCount(): number {
|
|
103
|
-
return this.compiledRules.length;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Get information about all rules including their validity.
|
|
108
|
-
*/
|
|
109
|
-
getRuleInfo(): Array<{ expression: string; isValid: boolean; enabled: boolean }> {
|
|
110
|
-
const validExpressions = new Set(this.compiledRules.map((r) => r.expression));
|
|
111
|
-
|
|
112
|
-
return this.compiledRules.map((rule) => ({
|
|
113
|
-
expression: rule.expression,
|
|
114
|
-
isValid: validExpressions.has(rule.expression),
|
|
115
|
-
enabled: rule.enabled,
|
|
116
|
-
}));
|
|
117
|
-
}
|
|
118
|
-
}
|