ConfigManager

ConfigManager: Manage(Get, set and update) your config with config path simply with a ruleset!

当前为 2022-08-18 提交的版本,查看 最新版本

此脚本不应直接安装,它是供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/449583/1082908/ConfigManager.js

  1. /* eslint-disable no-multi-spaces */
  2.  
  3. // ==UserScript==
  4. // @name ConfigManager
  5. // @namespace ConfigManager
  6. // @version 0.3
  7. // @description ConfigManager: Manage(Get, set and update) your config with config path simply with a ruleset!
  8. // @author PY-DNG
  9. // @license GPL-v3
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @grant GM_listValues
  13. // @grant GM_deleteValue
  14. // ==/UserScript==
  15.  
  16. function ConfigManager(Ruleset) {
  17. const CM = this;
  18. const ConfigBase = new Proxy({}, {
  19. get: function(target, property, reciever) {
  20. return GM_getValue(property);
  21. },
  22. set: function(target, property, value, reciever) {
  23. return (GM_setValue(property, value), true);
  24. },
  25. has: function(target, property) {
  26. return GM_listValues().includes(property);
  27. }
  28. });
  29.  
  30. CM.getConfig = getConfig;
  31. CM.setConfig = setConfig;
  32. CM.updateConfig = updateConfig;
  33. CM.updateAllConfigs = updateAllConfigs;
  34. CM.readPath = readPath;
  35. CM.pathExists = pathExists;
  36. CM.mergePath = mergePath;
  37. CM.getBaseName = getBaseName;
  38. CM.ConfigBase = ConfigBase;
  39. Object.freeze(CM);
  40.  
  41. // Get config value from path (e.g. 'Users/username/' or ['Users', 12345])
  42. function getConfig(path) {
  43. // Split path
  44. path = arrPath(path);
  45.  
  46. // Init config if need
  47. if (!GM_listValues().includes(path[0])) {
  48. ConfigBase[path[0]] = Ruleset.defaultValues[path[0]];
  49. }
  50.  
  51. // Get config by path
  52. const target = path.pop();
  53. let config = readPath(ConfigBase, path);
  54. return config[target];
  55. }
  56.  
  57. // Set config value to path
  58. function setConfig(path, value) {
  59. path = arrPath(path);
  60. const target = path.pop();
  61.  
  62. if (path.length > 0) {
  63. const basekey = path.shift();
  64. const baseobj = ConfigBase[basekey];
  65. let config = readPath(baseobj, path);
  66. if (isObject(config)) {
  67. config[target] = value;
  68. ConfigBase[basekey] = baseobj;
  69. } else {
  70. Err('Attempt to set a property to a non-object value')
  71. }
  72. } else {
  73. ConfigBase[target] = value;
  74. }
  75. }
  76.  
  77. function updateConfig(basename) {
  78. let updated = false;
  79.  
  80. // Get updaters and config
  81. const updaters = Ruleset.updaters.hasOwnProperty(basename) ? Ruleset.updaters[basename] : [];
  82. const verKey = Ruleset['version-key'];
  83. const config = getConfig(basename);
  84.  
  85. // Valid check
  86. if (Ruleset.ignores.includes(basename)) {
  87. return false;
  88. }
  89. if (!updaters.length) {
  90. return save();
  91. }
  92.  
  93. // Update
  94. for (let i = (config[verKey] || 0); i < updaters.length; i++) {
  95. const updater = updaters[i];
  96. config = updater(config);
  97. updated = true;
  98. }
  99.  
  100. // Set version and save
  101. return save();
  102.  
  103. function save() {
  104. config[verKey] = updaters.length;
  105. setConfig(basename, config);
  106. return updated;
  107. }
  108. }
  109.  
  110. function updateAllConfigs() {
  111. const keys = GM_listValues();
  112. keys.forEach((key) => (updateConfig(key)));
  113. }
  114.  
  115. function readPath(obj, path) {
  116. path = arrPath(path);
  117. while (path.length > 0) {
  118. const key = path.shift();
  119. if (isObject(obj) && hasProp(obj, key)) {
  120. obj = obj[key]
  121. } else {
  122. Err('Attempt to read a property that is not exist (reading "' + key + '" in path "' + path + '")')
  123. }
  124. }
  125. return obj;
  126. }
  127.  
  128. function pathExists(obj, path) {
  129. path = arrPath(path);
  130. while (path.length > 0) {
  131. const key = path.shift();
  132. if (isObject(obj) && hasProp(obj, key)) {
  133. obj = obj[key];
  134. } else {
  135. return false;
  136. }
  137. }
  138. return true;
  139. }
  140.  
  141. function mergePath() {
  142. return Array.from(arguments).join('/');
  143. }
  144.  
  145. function getBaseName(path) {
  146. return arrPath(path)[0];
  147. }
  148.  
  149. function getPathWithoutBase(path) {
  150. const p = arrPath(path);
  151. p.shift();
  152. return p;
  153. }
  154.  
  155. function arrPath(strpath) {
  156. return Array.isArray(strpath) ? [...strpath] : strpath.split('/');
  157. }
  158.  
  159. function isObject(obj) {
  160. return typeof obj === 'object' && obj !== null;
  161. }
  162.  
  163. function hasProp(obj, prop) {
  164. return obj === ConfigBase ? prop in obj : obj.hasOwnProperty(prop);
  165. }
  166.  
  167. // type: [Error, TypeError]
  168. function Err(msg, type=0) {
  169. throw new [Error, TypeError][type](msg);
  170. }
  171. }