andOrNotEvaluator.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /**
  2. * Class used to evaluate queries containing `and` and `or` operators
  3. */
  4. export class AndOrNotEvaluator {
  5. /**
  6. * Evaluate a query
  7. * @param query defines the query to evaluate
  8. * @param evaluateCallback defines the callback used to filter result
  9. * @returns true if the query matches
  10. */
  11. static Eval(query, evaluateCallback) {
  12. if (!query.match(/\([^()]*\)/g)) {
  13. query = AndOrNotEvaluator._HandleParenthesisContent(query, evaluateCallback);
  14. }
  15. else {
  16. query = query.replace(/\([^()]*\)/g, (r) => {
  17. // remove parenthesis
  18. r = r.slice(1, r.length - 1);
  19. return AndOrNotEvaluator._HandleParenthesisContent(r, evaluateCallback);
  20. });
  21. }
  22. if (query === "true") {
  23. return true;
  24. }
  25. if (query === "false") {
  26. return false;
  27. }
  28. return AndOrNotEvaluator.Eval(query, evaluateCallback);
  29. }
  30. static _HandleParenthesisContent(parenthesisContent, evaluateCallback) {
  31. evaluateCallback =
  32. evaluateCallback ||
  33. ((r) => {
  34. return r === "true" ? true : false;
  35. });
  36. let result;
  37. const or = parenthesisContent.split("||");
  38. for (const i in or) {
  39. if (Object.prototype.hasOwnProperty.call(or, i)) {
  40. let ori = AndOrNotEvaluator._SimplifyNegation(or[i].trim());
  41. const and = ori.split("&&");
  42. if (and.length > 1) {
  43. for (let j = 0; j < and.length; ++j) {
  44. const andj = AndOrNotEvaluator._SimplifyNegation(and[j].trim());
  45. if (andj !== "true" && andj !== "false") {
  46. if (andj[0] === "!") {
  47. result = !evaluateCallback(andj.substring(1));
  48. }
  49. else {
  50. result = evaluateCallback(andj);
  51. }
  52. }
  53. else {
  54. result = andj === "true" ? true : false;
  55. }
  56. if (!result) {
  57. // no need to continue since 'false && ... && ...' will always return false
  58. ori = "false";
  59. break;
  60. }
  61. }
  62. }
  63. if (result || ori === "true") {
  64. // no need to continue since 'true || ... || ...' will always return true
  65. result = true;
  66. break;
  67. }
  68. // result equals false (or undefined)
  69. if (ori !== "true" && ori !== "false") {
  70. if (ori[0] === "!") {
  71. result = !evaluateCallback(ori.substring(1));
  72. }
  73. else {
  74. result = evaluateCallback(ori);
  75. }
  76. }
  77. else {
  78. result = ori === "true" ? true : false;
  79. }
  80. }
  81. }
  82. // the whole parenthesis scope is replaced by 'true' or 'false'
  83. return result ? "true" : "false";
  84. }
  85. static _SimplifyNegation(booleanString) {
  86. booleanString = booleanString.replace(/^[\s!]+/, (r) => {
  87. // remove whitespaces
  88. r = r.replace(/[\s]/g, () => "");
  89. return r.length % 2 ? "!" : "";
  90. });
  91. booleanString = booleanString.trim();
  92. if (booleanString === "!true") {
  93. booleanString = "false";
  94. }
  95. else if (booleanString === "!false") {
  96. booleanString = "true";
  97. }
  98. return booleanString;
  99. }
  100. }
  101. //# sourceMappingURL=andOrNotEvaluator.js.map