match.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. "use strict";
  2. var valueToString = require("@sinonjs/commons").valueToString;
  3. var deepEqual = require("./deep-equal").use(match); // eslint-disable-line no-use-before-define
  4. var getClass = require("./get-class");
  5. var isDate = require("./is-date");
  6. var isSet = require("./is-set");
  7. var isSubset = require("./is-subset");
  8. var createMatcher = require("./matcher");
  9. function arrayContains(array, subset, compare) {
  10. if (subset.length === 0) {
  11. return true;
  12. }
  13. var i, l, j, k;
  14. for (i = 0, l = array.length; i < l; ++i) {
  15. if (compare(array[i], subset[0])) {
  16. for (j = 0, k = subset.length; j < k; ++j) {
  17. if (i + j >= l) {
  18. return false;
  19. }
  20. if (!compare(array[i + j], subset[j])) {
  21. return false;
  22. }
  23. }
  24. return true;
  25. }
  26. }
  27. return false;
  28. }
  29. /**
  30. * @name samsam.match
  31. * @param Object object
  32. * @param Object matcher
  33. *
  34. * Compare arbitrary value ``object`` with matcher.
  35. */
  36. function match(object, matcher) {
  37. if (matcher && typeof matcher.test === "function") {
  38. return matcher.test(object);
  39. }
  40. if (typeof matcher === "function") {
  41. return matcher(object) === true;
  42. }
  43. if (typeof matcher === "string") {
  44. matcher = matcher.toLowerCase();
  45. var notNull = typeof object === "string" || !!object;
  46. return (
  47. notNull &&
  48. valueToString(object)
  49. .toLowerCase()
  50. .indexOf(matcher) >= 0
  51. );
  52. }
  53. if (typeof matcher === "number") {
  54. return matcher === object;
  55. }
  56. if (typeof matcher === "boolean") {
  57. return matcher === object;
  58. }
  59. if (typeof matcher === "undefined") {
  60. return typeof object === "undefined";
  61. }
  62. if (matcher === null) {
  63. return object === null;
  64. }
  65. if (object === null) {
  66. return false;
  67. }
  68. if (isSet(object)) {
  69. return isSubset(matcher, object, match);
  70. }
  71. if (getClass(object) === "Array" && getClass(matcher) === "Array") {
  72. return arrayContains(object, matcher, match);
  73. }
  74. if (isDate(matcher)) {
  75. return isDate(object) && object.getTime() === matcher.getTime();
  76. }
  77. if (matcher && typeof matcher === "object") {
  78. if (matcher === object) {
  79. return true;
  80. }
  81. if (typeof object !== "object") {
  82. return false;
  83. }
  84. var prop;
  85. // eslint-disable-next-line guard-for-in
  86. for (prop in matcher) {
  87. var value = object[prop];
  88. if (
  89. typeof value === "undefined" &&
  90. typeof object.getAttribute === "function"
  91. ) {
  92. value = object.getAttribute(prop);
  93. }
  94. if (
  95. matcher[prop] === null ||
  96. typeof matcher[prop] === "undefined"
  97. ) {
  98. if (value !== matcher[prop]) {
  99. return false;
  100. }
  101. } else if (
  102. typeof value === "undefined" ||
  103. !deepEqual(value, matcher[prop])
  104. ) {
  105. return false;
  106. }
  107. }
  108. return true;
  109. }
  110. throw new Error(
  111. "Matcher was not a string, a number, a " +
  112. "function, a boolean or an object"
  113. );
  114. }
  115. Object.keys(createMatcher).forEach(function(key) {
  116. match[key] = createMatcher[key];
  117. });
  118. module.exports = match;