瀏覽代碼

ref!: change GM storage keys, update comments

Sven 1 年之前
父節點
當前提交
734a12c76a
共有 1 個文件被更改,包括 42 次插入25 次删除
  1. 42 25
      lib/config.ts

+ 42 - 25
lib/config.ts

@@ -37,7 +37,8 @@ export interface ConfigManagerOptions<TData> {
  * Manages a user configuration that is cached in memory and persistently saved across sessions.  
  * Supports migrating data from older versions of the configuration to newer ones and populating the cache with default data if no persistent data is found.  
  *   
- * ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue`
+ * ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue`  
+ * ⚠️ Make sure to call `loadData()` at least once after creating an instance, or the returned data will be the same as `options.defaultConfig`
  * 
  * @template TData The type of the data that is saved in persistent storage (will be automatically inferred from `config.defaultConfig`) - this should also be the type of the data format associated with the current `options.formatVersion`
  */
@@ -49,11 +50,15 @@ export class ConfigManager<TData = any> {
   private migrations?: MigrationsDict;
 
   /**
-   * Creates an instance of ConfigManager.  
+   * Creates an instance of ConfigManager to manage a user configuration that is cached in memory and persistently saved across sessions.  
+   * Supports migrating data from older versions of the configuration to newer ones and populating the cache with default data if no persistent data is found.  
    *   
+   * ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue`  
    * ⚠️ Make sure to call `loadData()` at least once after creating an instance, or the returned data will be the same as `options.defaultConfig`
+   * 
+   * @template TData The type of the data that is saved in persistent storage (will be automatically inferred from `config.defaultConfig`) - this should also be the type of the data format associated with the current `options.formatVersion`
    * @param options The options for this ConfigManager instance
-   */
+  */
   constructor(options: ConfigManagerOptions<TData>) {
     this.id = options.id;
     this.formatVersion = options.formatVersion;
@@ -69,14 +74,16 @@ export class ConfigManager<TData = any> {
    */
   public async loadData(): Promise<TData> {
     try {
-      const gmData = await GM.getValue(this.id, this.defaultConfig);
-      let gmFmtVer = Number(await GM.getValue(`_uufmtver-${this.id}`));
+      const gmData = await GM.getValue(`_uucfg-${this.id}`, this.defaultConfig);
+      let gmFmtVer = Number(await GM.getValue(`_uucfgver-${this.id}`));
 
-      if(typeof gmData !== "string")
-        return await this.saveDefaultData();
+      if(typeof gmData !== "string") {
+        await this.saveDefaultData();
+        return this.defaultConfig;
+      }
 
       if(isNaN(gmFmtVer))
-        await GM.setValue(`_uufmtver-${this.id}`, gmFmtVer = this.formatVersion);
+        await GM.setValue(`_uucfgver-${this.id}`, gmFmtVer = this.formatVersion);
 
       let parsed = JSON.parse(gmData);
 
@@ -86,7 +93,8 @@ export class ConfigManager<TData = any> {
       return this.cachedConfig = typeof parsed === "object" ? parsed : undefined;
     }
     catch(err) {
-      return await this.saveDefaultData();
+      await this.saveDefaultData();
+      return this.defaultConfig;
     }
   }
 
@@ -98,33 +106,39 @@ export class ConfigManager<TData = any> {
   /** Saves the data synchronously to the in-memory cache and asynchronously to the persistent storage */
   public setData(data: TData) {
     this.cachedConfig = data;
-    return new Promise<TData>(async (resolve) => {
-      await GM.setValue(this.id, JSON.stringify(data));
-      await GM.setValue(`_uufmtver-${this.id}`, this.formatVersion);
-      resolve(data);
+    return new Promise<void>(async (resolve) => {
+      await Promise.allSettled([
+        GM.setValue(`_uucfg-${this.id}`, JSON.stringify(data)),
+        GM.setValue(`_uucfgver-${this.id}`, this.formatVersion),
+      ]);
+      resolve();
     });
   }
 
   /** Saves the default configuration data passed in the constructor synchronously to the in-memory cache and asynchronously to persistent storage */
   public async saveDefaultData() {
     this.cachedConfig = this.defaultConfig;
-    return new Promise<TData>(async (resolve) => {
-      await GM.setValue(this.id, JSON.stringify(this.defaultConfig));
-      await GM.setValue(`_uufmtver-${this.id}`, this.formatVersion);
-      resolve(this.defaultConfig);
+    return new Promise<void>(async (resolve) => {
+      await Promise.allSettled([
+        GM.setValue(`_uucfg-${this.id}`, JSON.stringify(this.defaultConfig)),
+        GM.setValue(`_uucfgver-${this.id}`, this.formatVersion),
+      ]);
+      resolve();
     });
   }
 
   /**
    * Call this method to clear all persistently stored data associated with this ConfigManager instance.  
-   * The in-memory cache will be left untouched, so you may still access the data with `getData()`  
+   * The in-memory cache will be left untouched, so you may still access the data with `getData()`.  
    * Calling `loadData()` or `setData()` after this method was called will recreate persistent storage with the cached or default data.  
    *   
    * ⚠️ This requires the additional directive `@grant GM.deleteValue`
    */
   public async deleteConfig() {
-    await GM.deleteValue(this.id);
-    await GM.deleteValue(`_uufmtver-${this.id}`);
+    await Promise.allSettled([
+      GM.deleteValue(`_uucfg-${this.id}`),
+      GM.deleteValue(`_uucfgver-${this.id}`),
+    ]);
   }
 
   /** Runs all necessary migration functions consecutively - may be overwritten in a subclass */
@@ -132,20 +146,19 @@ export class ConfigManager<TData = any> {
     if(!this.migrations)
       return oldData as TData;
 
-    console.info("#DEBUG - RUNNING MIGRATIONS", oldFmtVer, "->", this.formatVersion, "- oldData:", oldData);
-
-    // TODO: verify
     let newData = oldData;
     const sortedMigrations = Object.entries(this.migrations)
       .sort(([a], [b]) => Number(a) - Number(b));
 
+    let lastFmtVer = oldFmtVer;
+
     for(const [fmtVer, migrationFunc] of sortedMigrations) {
       const ver = Number(fmtVer);
       if(oldFmtVer < this.formatVersion && oldFmtVer < ver) {
         try {
           const migRes = migrationFunc(newData);
           newData = migRes instanceof Promise ? await migRes : migRes;
-          oldFmtVer = ver;
+          lastFmtVer = oldFmtVer = ver;
         }
         catch(err) {
           console.error(`Error while running migration function for format version ${fmtVer}:`, err);
@@ -153,7 +166,11 @@ export class ConfigManager<TData = any> {
       }
     }
 
-    await GM.setValue(`_uufmtver-${this.id}`, this.formatVersion);
+    await Promise.allSettled([
+      GM.setValue(`_uucfg-${this.id}`, JSON.stringify(newData)),
+      GM.setValue(`_uucfgver-${this.id}`, lastFmtVer),
+    ]);
+
     return newData as TData;
   }