@real1ty-obsidian-plugins/utils 2.7.0 → 2.8.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.
@@ -8,4 +8,14 @@ export interface BatchOperationResult {
8
8
  }
9
9
  export declare function runBatchOperation<T>(items: T[], operationLabel: string, handler: (item: T) => Promise<void>, showResult?: boolean): Promise<BatchOperationResult>;
10
10
  export declare function showBatchOperationResult(operation: string, successCount: number, errorCount: number): void;
11
+ /**
12
+ * Executes an async operation with a lock to prevent concurrent execution for the same key.
13
+ * If a lock already exists for the key, waits for it to complete instead of starting a new operation.
14
+ *
15
+ * @param lockMap - Map storing active locks by key
16
+ * @param key - Unique identifier for the lock
17
+ * @param operation - Async function to execute with the lock
18
+ * @returns Promise resolving to the operation's result
19
+ */
20
+ export declare function withLock<T>(lockMap: Map<string, Promise<T>>, key: string, operation: () => Promise<T>): Promise<T>;
11
21
  //# sourceMappingURL=batch-operations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"batch-operations.d.ts","sourceRoot":"","sources":["../../src/async/batch-operations.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,iBAAiB,CAAC,CAAC,EACxC,KAAK,EAAE,CAAC,EAAE,EACV,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EACnC,UAAU,GAAE,OAAc,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;AAED,wBAAgB,wBAAwB,CACvC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GAChB,IAAI,CAUN"}
1
+ {"version":3,"file":"batch-operations.d.ts","sourceRoot":"","sources":["../../src/async/batch-operations.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,iBAAiB,CAAC,CAAC,EACxC,KAAK,EAAE,CAAC,EAAE,EACV,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EACnC,UAAU,GAAE,OAAc,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;AAED,wBAAgB,wBAAwB,CACvC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GAChB,IAAI,CAUN;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC/B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAChC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,CAAC,CAkBZ"}
@@ -28,4 +28,33 @@ export function showBatchOperationResult(operation, successCount, errorCount) {
28
28
  new Notice(`${operation}: ${successCount} succeeded, ${errorCount} failed. Check console for details.`);
29
29
  }
30
30
  }
31
+ /**
32
+ * Executes an async operation with a lock to prevent concurrent execution for the same key.
33
+ * If a lock already exists for the key, waits for it to complete instead of starting a new operation.
34
+ *
35
+ * @param lockMap - Map storing active locks by key
36
+ * @param key - Unique identifier for the lock
37
+ * @param operation - Async function to execute with the lock
38
+ * @returns Promise resolving to the operation's result
39
+ */
40
+ export function withLock(lockMap, key, operation) {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ // Check if there's already an operation in progress for this key
43
+ const existingLock = lockMap.get(key);
44
+ if (existingLock) {
45
+ // Wait for the existing operation to complete instead of starting a new one
46
+ return yield existingLock;
47
+ }
48
+ // Create a new locked operation
49
+ const lockPromise = operation();
50
+ lockMap.set(key, lockPromise);
51
+ try {
52
+ return yield lockPromise;
53
+ }
54
+ finally {
55
+ // Always remove the lock when done
56
+ lockMap.delete(key);
57
+ }
58
+ });
59
+ }
31
60
  //# sourceMappingURL=batch-operations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"batch-operations.js","sourceRoot":"","sources":["../../src/async/batch-operations.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAYlC,MAAM,UAAgB,iBAAiB;yDACtC,KAAU,EACV,cAAsB,EACtB,OAAmC,EACnC,aAAsB,IAAI;QAE1B,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACJ,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBACpB,YAAY,EAAE,CAAC;YAChB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,GAAG,cAAc,0BAA0B,EAAE,KAAK,CAAC,CAAC;gBAClE,UAAU,EAAE,CAAC;YACd,CAAC;QACF,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YAChB,wBAAwB,CAAC,cAAc,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACrC,CAAC;CAAA;AAED,MAAM,UAAU,wBAAwB,CACvC,SAAiB,EACjB,YAAoB,EACpB,UAAkB;IAElB,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACtB,IAAI,MAAM,CACT,GAAG,SAAS,KAAK,YAAY,QAAQ,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,yBAAyB,CAC3F,CAAC;IACH,CAAC;SAAM,CAAC;QACP,IAAI,MAAM,CACT,GAAG,SAAS,KAAK,YAAY,eAAe,UAAU,qCAAqC,CAC3F,CAAC;IACH,CAAC;AACF,CAAC","sourcesContent":["import { Notice } from \"obsidian\";\n\nexport interface BatchOperationOptions {\n\tcloseAfter?: boolean;\n\tcallOnComplete?: boolean;\n}\n\nexport interface BatchOperationResult {\n\tsuccessCount: number;\n\terrorCount: number;\n}\n\nexport async function runBatchOperation<T>(\n\titems: T[],\n\toperationLabel: string,\n\thandler: (item: T) => Promise<void>,\n\tshowResult: boolean = true\n): Promise<BatchOperationResult> {\n\tlet successCount = 0;\n\tlet errorCount = 0;\n\n\tfor (const item of items) {\n\t\ttry {\n\t\t\tawait handler(item);\n\t\t\tsuccessCount++;\n\t\t} catch (error) {\n\t\t\tconsole.error(`${operationLabel}: error processing item:`, error);\n\t\t\terrorCount++;\n\t\t}\n\t}\n\n\tif (showResult) {\n\t\tshowBatchOperationResult(operationLabel, successCount, errorCount);\n\t}\n\n\treturn { successCount, errorCount };\n}\n\nexport function showBatchOperationResult(\n\toperation: string,\n\tsuccessCount: number,\n\terrorCount: number\n): void {\n\tif (errorCount === 0) {\n\t\tnew Notice(\n\t\t\t`${operation}: ${successCount} item${successCount === 1 ? \"\" : \"s\"} processed successfully`\n\t\t);\n\t} else {\n\t\tnew Notice(\n\t\t\t`${operation}: ${successCount} succeeded, ${errorCount} failed. Check console for details.`\n\t\t);\n\t}\n}\n"]}
1
+ {"version":3,"file":"batch-operations.js","sourceRoot":"","sources":["../../src/async/batch-operations.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAYlC,MAAM,UAAgB,iBAAiB;yDACtC,KAAU,EACV,cAAsB,EACtB,OAAmC,EACnC,aAAsB,IAAI;QAE1B,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACJ,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBACpB,YAAY,EAAE,CAAC;YAChB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,GAAG,cAAc,0BAA0B,EAAE,KAAK,CAAC,CAAC;gBAClE,UAAU,EAAE,CAAC;YACd,CAAC;QACF,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YAChB,wBAAwB,CAAC,cAAc,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACrC,CAAC;CAAA;AAED,MAAM,UAAU,wBAAwB,CACvC,SAAiB,EACjB,YAAoB,EACpB,UAAkB;IAElB,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACtB,IAAI,MAAM,CACT,GAAG,SAAS,KAAK,YAAY,QAAQ,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,yBAAyB,CAC3F,CAAC;IACH,CAAC;SAAM,CAAC;QACP,IAAI,MAAM,CACT,GAAG,SAAS,KAAK,YAAY,eAAe,UAAU,qCAAqC,CAC3F,CAAC;IACH,CAAC;AACF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAgB,QAAQ,CAC7B,OAAgC,EAChC,GAAW,EACX,SAA2B;;QAE3B,iEAAiE;QACjE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,YAAY,EAAE,CAAC;YAClB,4EAA4E;YAC5E,OAAO,MAAM,YAAY,CAAC;QAC3B,CAAC;QAED,gCAAgC;QAChC,MAAM,WAAW,GAAG,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAE9B,IAAI,CAAC;YACJ,OAAO,MAAM,WAAW,CAAC;QAC1B,CAAC;gBAAS,CAAC;YACV,mCAAmC;YACnC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;IACF,CAAC;CAAA","sourcesContent":["import { Notice } from \"obsidian\";\n\nexport interface BatchOperationOptions {\n\tcloseAfter?: boolean;\n\tcallOnComplete?: boolean;\n}\n\nexport interface BatchOperationResult {\n\tsuccessCount: number;\n\terrorCount: number;\n}\n\nexport async function runBatchOperation<T>(\n\titems: T[],\n\toperationLabel: string,\n\thandler: (item: T) => Promise<void>,\n\tshowResult: boolean = true\n): Promise<BatchOperationResult> {\n\tlet successCount = 0;\n\tlet errorCount = 0;\n\n\tfor (const item of items) {\n\t\ttry {\n\t\t\tawait handler(item);\n\t\t\tsuccessCount++;\n\t\t} catch (error) {\n\t\t\tconsole.error(`${operationLabel}: error processing item:`, error);\n\t\t\terrorCount++;\n\t\t}\n\t}\n\n\tif (showResult) {\n\t\tshowBatchOperationResult(operationLabel, successCount, errorCount);\n\t}\n\n\treturn { successCount, errorCount };\n}\n\nexport function showBatchOperationResult(\n\toperation: string,\n\tsuccessCount: number,\n\terrorCount: number\n): void {\n\tif (errorCount === 0) {\n\t\tnew Notice(\n\t\t\t`${operation}: ${successCount} item${successCount === 1 ? \"\" : \"s\"} processed successfully`\n\t\t);\n\t} else {\n\t\tnew Notice(\n\t\t\t`${operation}: ${successCount} succeeded, ${errorCount} failed. Check console for details.`\n\t\t);\n\t}\n}\n\n/**\n * Executes an async operation with a lock to prevent concurrent execution for the same key.\n * If a lock already exists for the key, waits for it to complete instead of starting a new operation.\n *\n * @param lockMap - Map storing active locks by key\n * @param key - Unique identifier for the lock\n * @param operation - Async function to execute with the lock\n * @returns Promise resolving to the operation's result\n */\nexport async function withLock<T>(\n\tlockMap: Map<string, Promise<T>>,\n\tkey: string,\n\toperation: () => Promise<T>\n): Promise<T> {\n\t// Check if there's already an operation in progress for this key\n\tconst existingLock = lockMap.get(key);\n\tif (existingLock) {\n\t\t// Wait for the existing operation to complete instead of starting a new one\n\t\treturn await existingLock;\n\t}\n\n\t// Create a new locked operation\n\tconst lockPromise = operation();\n\tlockMap.set(key, lockPromise);\n\n\ttry {\n\t\treturn await lockPromise;\n\t} finally {\n\t\t// Always remove the lock when done\n\t\tlockMap.delete(key);\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real1ty-obsidian-plugins/utils",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "Shared utilities for Obsidian plugins",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -51,3 +51,36 @@ export function showBatchOperationResult(
51
51
  );
52
52
  }
53
53
  }
54
+
55
+ /**
56
+ * Executes an async operation with a lock to prevent concurrent execution for the same key.
57
+ * If a lock already exists for the key, waits for it to complete instead of starting a new operation.
58
+ *
59
+ * @param lockMap - Map storing active locks by key
60
+ * @param key - Unique identifier for the lock
61
+ * @param operation - Async function to execute with the lock
62
+ * @returns Promise resolving to the operation's result
63
+ */
64
+ export async function withLock<T>(
65
+ lockMap: Map<string, Promise<T>>,
66
+ key: string,
67
+ operation: () => Promise<T>
68
+ ): Promise<T> {
69
+ // Check if there's already an operation in progress for this key
70
+ const existingLock = lockMap.get(key);
71
+ if (existingLock) {
72
+ // Wait for the existing operation to complete instead of starting a new one
73
+ return await existingLock;
74
+ }
75
+
76
+ // Create a new locked operation
77
+ const lockPromise = operation();
78
+ lockMap.set(key, lockPromise);
79
+
80
+ try {
81
+ return await lockPromise;
82
+ } finally {
83
+ // Always remove the lock when done
84
+ lockMap.delete(key);
85
+ }
86
+ }