SimpleFilter

A filter framework.

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/441383/1027327/SimpleFilter.js

  1. // ==UserScript==
  2. // @name SimpleFilter
  3. // @namespace ckylin-script-lib-filter-processor
  4. // @version 1.0
  5. // @match http://*
  6. // @match https://*
  7. // @author CKylinMC
  8. // @license GPLv3 License
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. class SimpleFilter{
  13. static debug = true;
  14. static log = (...args)=>SimpleFilter.debug&&SimpleFilter.logger(...args);
  15. constructor(filterObj){
  16. if(!SimpleFilter.verify(filterObj)) {
  17. throw new Error("filter is invalid, turn on debug mode to see the details.");
  18. }
  19. this.filterObj = filterObj;
  20. this.datas = null;
  21. }
  22. static logger(...args){
  23. console.log("[Filter]",...args);
  24. }
  25. static async $and(...conditions){
  26. for(const condition of conditions){
  27. if(condition instanceof Promise){
  28. if(!(await condition)) return false;
  29. }
  30. if(!condition) return false;
  31. }
  32. return true;
  33. }
  34. static async $or(...conditions){
  35. for(const condition of conditions){
  36. if(condition instanceof Promise){
  37. if(await condition) return false;
  38. }
  39. if(condition) return true;
  40. }
  41. return false;
  42. }
  43. static verify(obj, depth=0, isroot=true){
  44. SimpleFilter.log('-'.repeat(depth+1)+'>','start validate',obj);
  45. if(Array.isArray(obj)){
  46. SimpleFilter.log('-'.repeat(depth+1)+'>','type: arr',obj);
  47. for(const item of obj){
  48. if(!SimpleFilter.verify(item, depth+1, false)) return (SimpleFilter.log('-'.repeat(depth+1)+'>','[ERR]','array validator not passed for',item),false);
  49. }
  50. }else if(typeof(obj)=='function') return (SimpleFilter.log('-'.repeat(depth+1)+'>','[OK]','passed due to function type',obj),true);
  51. else{
  52. SimpleFilter.log('-'.repeat(depth+1)+'>','type: logic selector',obj);
  53. const keys = Object.keys(obj);
  54. if(isroot&&keys.length!==1) return (SimpleFilter.log('-'.repeat(depth+1)+'>','[ERR]','subkey length validator not passed for', keys), false);
  55. for(const k of keys){
  56. if(["$and","$or"].includes(k.toLowerCase())){
  57. if(!SimpleFilter.verify(obj[k], depth+1, false)) return (SimpleFilter.log('-'.repeat(depth+1)+'>','[ERR]','value validator not passed for', k), false);
  58. }else return (SimpleFilter.log('-'.repeat(depth+1)+'>','[ERR]','key validator not passed for', k),false);
  59. }
  60. }
  61. SimpleFilter.log('-'.repeat(depth+1)+'>','[OK]','passed',obj);
  62. return true;
  63. }
  64. async applyFilterToAll(datas=[]){
  65. try{
  66. let pool = datas.map(data=>this.applyFilterTo(data));
  67. return Promise.all(pool);
  68. }catch(e){
  69. return null;
  70. }
  71. }
  72. async applyFilterTo(data=null){
  73. if(!SimpleFilter.verify(this.filterObj)) return false;
  74. this.data = data;
  75. try{
  76. return await this.applyFilter(this.filterObj);
  77. }
  78. catch(e){
  79. SimpleFilter.log('[ERR]',e);
  80. return false;
  81. }
  82. finally{
  83. this.data = null;
  84. }
  85. }
  86. async applyFilter(obj, mode = '$and'){
  87. if(Array.isArray(obj)){
  88. for(const item of obj){
  89. return this.applyFilter(item);
  90. }
  91. }else if(typeof(obj)=='function'){
  92. if(obj.constructor.name=='AsyncFunction'){
  93. try{
  94. return !!(await obj(this.data));
  95. }catch(e){
  96. SimpleFilter.log('[ERR]',e);
  97. return false;
  98. }
  99. }else{
  100. try{
  101. return !!obj(this.data);
  102. }catch(e){
  103. SimpleFilter.log('[ERR]',e);
  104. return false;
  105. }
  106. }
  107. }else{
  108. const keys = Object.keys(obj);
  109. try{
  110. return await SimpleFilter[mode](...keys.map(async k=>{
  111. return await this.applyFilter(obj[k],k);
  112. }));
  113. }catch(e){
  114. SimpleFilter.log('[ERR]',e);
  115. return false;
  116. }
  117. }
  118. }
  119. }