Dieses Repository beinhaltet HTML- und Javascript Code zur einer NotizenWebApp auf Basis von Web Storage. Zudem sind Mocha/Chai Tests im Browser enthalten. https://meinenotizen.netlify.app/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.js 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. 'use strict';
  2. /* globals Symbol: false, Uint8Array: false, WeakMap: false */
  3. /*!
  4. * deep-eql
  5. * Copyright(c) 2013 Jake Luer <jake@alogicalparadox.com>
  6. * MIT Licensed
  7. */
  8. var type = require('type-detect');
  9. function FakeMap() {
  10. this._key = 'chai/deep-eql__' + Math.random() + Date.now();
  11. }
  12. FakeMap.prototype = {
  13. get: function getMap(key) {
  14. return key[this._key];
  15. },
  16. set: function setMap(key, value) {
  17. if (Object.isExtensible(key)) {
  18. Object.defineProperty(key, this._key, {
  19. value: value,
  20. configurable: true,
  21. });
  22. }
  23. },
  24. };
  25. var MemoizeMap = typeof WeakMap === 'function' ? WeakMap : FakeMap;
  26. /*!
  27. * Check to see if the MemoizeMap has recorded a result of the two operands
  28. *
  29. * @param {Mixed} leftHandOperand
  30. * @param {Mixed} rightHandOperand
  31. * @param {MemoizeMap} memoizeMap
  32. * @returns {Boolean|null} result
  33. */
  34. function memoizeCompare(leftHandOperand, rightHandOperand, memoizeMap) {
  35. // Technically, WeakMap keys can *only* be objects, not primitives.
  36. if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {
  37. return null;
  38. }
  39. var leftHandMap = memoizeMap.get(leftHandOperand);
  40. if (leftHandMap) {
  41. var result = leftHandMap.get(rightHandOperand);
  42. if (typeof result === 'boolean') {
  43. return result;
  44. }
  45. }
  46. return null;
  47. }
  48. /*!
  49. * Set the result of the equality into the MemoizeMap
  50. *
  51. * @param {Mixed} leftHandOperand
  52. * @param {Mixed} rightHandOperand
  53. * @param {MemoizeMap} memoizeMap
  54. * @param {Boolean} result
  55. */
  56. function memoizeSet(leftHandOperand, rightHandOperand, memoizeMap, result) {
  57. // Technically, WeakMap keys can *only* be objects, not primitives.
  58. if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {
  59. return;
  60. }
  61. var leftHandMap = memoizeMap.get(leftHandOperand);
  62. if (leftHandMap) {
  63. leftHandMap.set(rightHandOperand, result);
  64. } else {
  65. leftHandMap = new MemoizeMap();
  66. leftHandMap.set(rightHandOperand, result);
  67. memoizeMap.set(leftHandOperand, leftHandMap);
  68. }
  69. }
  70. /*!
  71. * Primary Export
  72. */
  73. module.exports = deepEqual;
  74. module.exports.MemoizeMap = MemoizeMap;
  75. /**
  76. * Assert deeply nested sameValue equality between two objects of any type.
  77. *
  78. * @param {Mixed} leftHandOperand
  79. * @param {Mixed} rightHandOperand
  80. * @param {Object} [options] (optional) Additional options
  81. * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality.
  82. * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of
  83. complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular
  84. references to blow the stack.
  85. * @return {Boolean} equal match
  86. */
  87. function deepEqual(leftHandOperand, rightHandOperand, options) {
  88. // If we have a comparator, we can't assume anything; so bail to its check first.
  89. if (options && options.comparator) {
  90. return extensiveDeepEqual(leftHandOperand, rightHandOperand, options);
  91. }
  92. var simpleResult = simpleEqual(leftHandOperand, rightHandOperand);
  93. if (simpleResult !== null) {
  94. return simpleResult;
  95. }
  96. // Deeper comparisons are pushed through to a larger function
  97. return extensiveDeepEqual(leftHandOperand, rightHandOperand, options);
  98. }
  99. /**
  100. * Many comparisons can be canceled out early via simple equality or primitive checks.
  101. * @param {Mixed} leftHandOperand
  102. * @param {Mixed} rightHandOperand
  103. * @return {Boolean|null} equal match
  104. */
  105. function simpleEqual(leftHandOperand, rightHandOperand) {
  106. // Equal references (except for Numbers) can be returned early
  107. if (leftHandOperand === rightHandOperand) {
  108. // Handle +-0 cases
  109. return leftHandOperand !== 0 || 1 / leftHandOperand === 1 / rightHandOperand;
  110. }
  111. // handle NaN cases
  112. if (
  113. leftHandOperand !== leftHandOperand && // eslint-disable-line no-self-compare
  114. rightHandOperand !== rightHandOperand // eslint-disable-line no-self-compare
  115. ) {
  116. return true;
  117. }
  118. // Anything that is not an 'object', i.e. symbols, functions, booleans, numbers,
  119. // strings, and undefined, can be compared by reference.
  120. if (isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {
  121. // Easy out b/c it would have passed the first equality check
  122. return false;
  123. }
  124. return null;
  125. }
  126. /*!
  127. * The main logic of the `deepEqual` function.
  128. *
  129. * @param {Mixed} leftHandOperand
  130. * @param {Mixed} rightHandOperand
  131. * @param {Object} [options] (optional) Additional options
  132. * @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality.
  133. * @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of
  134. complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular
  135. references to blow the stack.
  136. * @return {Boolean} equal match
  137. */
  138. function extensiveDeepEqual(leftHandOperand, rightHandOperand, options) {
  139. options = options || {};
  140. options.memoize = options.memoize === false ? false : options.memoize || new MemoizeMap();
  141. var comparator = options && options.comparator;
  142. // Check if a memoized result exists.
  143. var memoizeResultLeft = memoizeCompare(leftHandOperand, rightHandOperand, options.memoize);
  144. if (memoizeResultLeft !== null) {
  145. return memoizeResultLeft;
  146. }
  147. var memoizeResultRight = memoizeCompare(rightHandOperand, leftHandOperand, options.memoize);
  148. if (memoizeResultRight !== null) {
  149. return memoizeResultRight;
  150. }
  151. // If a comparator is present, use it.
  152. if (comparator) {
  153. var comparatorResult = comparator(leftHandOperand, rightHandOperand);
  154. // Comparators may return null, in which case we want to go back to default behavior.
  155. if (comparatorResult === false || comparatorResult === true) {
  156. memoizeSet(leftHandOperand, rightHandOperand, options.memoize, comparatorResult);
  157. return comparatorResult;
  158. }
  159. // To allow comparators to override *any* behavior, we ran them first. Since it didn't decide
  160. // what to do, we need to make sure to return the basic tests first before we move on.
  161. var simpleResult = simpleEqual(leftHandOperand, rightHandOperand);
  162. if (simpleResult !== null) {
  163. // Don't memoize this, it takes longer to set/retrieve than to just compare.
  164. return simpleResult;
  165. }
  166. }
  167. var leftHandType = type(leftHandOperand);
  168. if (leftHandType !== type(rightHandOperand)) {
  169. memoizeSet(leftHandOperand, rightHandOperand, options.memoize, false);
  170. return false;
  171. }
  172. // Temporarily set the operands in the memoize object to prevent blowing the stack
  173. memoizeSet(leftHandOperand, rightHandOperand, options.memoize, true);
  174. var result = extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options);
  175. memoizeSet(leftHandOperand, rightHandOperand, options.memoize, result);
  176. return result;
  177. }
  178. function extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options) {
  179. switch (leftHandType) {
  180. case 'String':
  181. case 'Number':
  182. case 'Boolean':
  183. case 'Date':
  184. // If these types are their instance types (e.g. `new Number`) then re-deepEqual against their values
  185. return deepEqual(leftHandOperand.valueOf(), rightHandOperand.valueOf());
  186. case 'Promise':
  187. case 'Symbol':
  188. case 'function':
  189. case 'WeakMap':
  190. case 'WeakSet':
  191. case 'Error':
  192. return leftHandOperand === rightHandOperand;
  193. case 'Arguments':
  194. case 'Int8Array':
  195. case 'Uint8Array':
  196. case 'Uint8ClampedArray':
  197. case 'Int16Array':
  198. case 'Uint16Array':
  199. case 'Int32Array':
  200. case 'Uint32Array':
  201. case 'Float32Array':
  202. case 'Float64Array':
  203. case 'Array':
  204. return iterableEqual(leftHandOperand, rightHandOperand, options);
  205. case 'RegExp':
  206. return regexpEqual(leftHandOperand, rightHandOperand);
  207. case 'Generator':
  208. return generatorEqual(leftHandOperand, rightHandOperand, options);
  209. case 'DataView':
  210. return iterableEqual(new Uint8Array(leftHandOperand.buffer), new Uint8Array(rightHandOperand.buffer), options);
  211. case 'ArrayBuffer':
  212. return iterableEqual(new Uint8Array(leftHandOperand), new Uint8Array(rightHandOperand), options);
  213. case 'Set':
  214. return entriesEqual(leftHandOperand, rightHandOperand, options);
  215. case 'Map':
  216. return entriesEqual(leftHandOperand, rightHandOperand, options);
  217. default:
  218. return objectEqual(leftHandOperand, rightHandOperand, options);
  219. }
  220. }
  221. /*!
  222. * Compare two Regular Expressions for equality.
  223. *
  224. * @param {RegExp} leftHandOperand
  225. * @param {RegExp} rightHandOperand
  226. * @return {Boolean} result
  227. */
  228. function regexpEqual(leftHandOperand, rightHandOperand) {
  229. return leftHandOperand.toString() === rightHandOperand.toString();
  230. }
  231. /*!
  232. * Compare two Sets/Maps for equality. Faster than other equality functions.
  233. *
  234. * @param {Set} leftHandOperand
  235. * @param {Set} rightHandOperand
  236. * @param {Object} [options] (Optional)
  237. * @return {Boolean} result
  238. */
  239. function entriesEqual(leftHandOperand, rightHandOperand, options) {
  240. // IE11 doesn't support Set#entries or Set#@@iterator, so we need manually populate using Set#forEach
  241. if (leftHandOperand.size !== rightHandOperand.size) {
  242. return false;
  243. }
  244. if (leftHandOperand.size === 0) {
  245. return true;
  246. }
  247. var leftHandItems = [];
  248. var rightHandItems = [];
  249. leftHandOperand.forEach(function gatherEntries(key, value) {
  250. leftHandItems.push([ key, value ]);
  251. });
  252. rightHandOperand.forEach(function gatherEntries(key, value) {
  253. rightHandItems.push([ key, value ]);
  254. });
  255. return iterableEqual(leftHandItems.sort(), rightHandItems.sort(), options);
  256. }
  257. /*!
  258. * Simple equality for flat iterable objects such as Arrays, TypedArrays or Node.js buffers.
  259. *
  260. * @param {Iterable} leftHandOperand
  261. * @param {Iterable} rightHandOperand
  262. * @param {Object} [options] (Optional)
  263. * @return {Boolean} result
  264. */
  265. function iterableEqual(leftHandOperand, rightHandOperand, options) {
  266. var length = leftHandOperand.length;
  267. if (length !== rightHandOperand.length) {
  268. return false;
  269. }
  270. if (length === 0) {
  271. return true;
  272. }
  273. var index = -1;
  274. while (++index < length) {
  275. if (deepEqual(leftHandOperand[index], rightHandOperand[index], options) === false) {
  276. return false;
  277. }
  278. }
  279. return true;
  280. }
  281. /*!
  282. * Simple equality for generator objects such as those returned by generator functions.
  283. *
  284. * @param {Iterable} leftHandOperand
  285. * @param {Iterable} rightHandOperand
  286. * @param {Object} [options] (Optional)
  287. * @return {Boolean} result
  288. */
  289. function generatorEqual(leftHandOperand, rightHandOperand, options) {
  290. return iterableEqual(getGeneratorEntries(leftHandOperand), getGeneratorEntries(rightHandOperand), options);
  291. }
  292. /*!
  293. * Determine if the given object has an @@iterator function.
  294. *
  295. * @param {Object} target
  296. * @return {Boolean} `true` if the object has an @@iterator function.
  297. */
  298. function hasIteratorFunction(target) {
  299. return typeof Symbol !== 'undefined' &&
  300. typeof target === 'object' &&
  301. typeof Symbol.iterator !== 'undefined' &&
  302. typeof target[Symbol.iterator] === 'function';
  303. }
  304. /*!
  305. * Gets all iterator entries from the given Object. If the Object has no @@iterator function, returns an empty array.
  306. * This will consume the iterator - which could have side effects depending on the @@iterator implementation.
  307. *
  308. * @param {Object} target
  309. * @returns {Array} an array of entries from the @@iterator function
  310. */
  311. function getIteratorEntries(target) {
  312. if (hasIteratorFunction(target)) {
  313. try {
  314. return getGeneratorEntries(target[Symbol.iterator]());
  315. } catch (iteratorError) {
  316. return [];
  317. }
  318. }
  319. return [];
  320. }
  321. /*!
  322. * Gets all entries from a Generator. This will consume the generator - which could have side effects.
  323. *
  324. * @param {Generator} target
  325. * @returns {Array} an array of entries from the Generator.
  326. */
  327. function getGeneratorEntries(generator) {
  328. var generatorResult = generator.next();
  329. var accumulator = [ generatorResult.value ];
  330. while (generatorResult.done === false) {
  331. generatorResult = generator.next();
  332. accumulator.push(generatorResult.value);
  333. }
  334. return accumulator;
  335. }
  336. /*!
  337. * Gets all own and inherited enumerable keys from a target.
  338. *
  339. * @param {Object} target
  340. * @returns {Array} an array of own and inherited enumerable keys from the target.
  341. */
  342. function getEnumerableKeys(target) {
  343. var keys = [];
  344. for (var key in target) {
  345. keys.push(key);
  346. }
  347. return keys;
  348. }
  349. /*!
  350. * Determines if two objects have matching values, given a set of keys. Defers to deepEqual for the equality check of
  351. * each key. If any value of the given key is not equal, the function will return false (early).
  352. *
  353. * @param {Mixed} leftHandOperand
  354. * @param {Mixed} rightHandOperand
  355. * @param {Array} keys An array of keys to compare the values of leftHandOperand and rightHandOperand against
  356. * @param {Object} [options] (Optional)
  357. * @return {Boolean} result
  358. */
  359. function keysEqual(leftHandOperand, rightHandOperand, keys, options) {
  360. var length = keys.length;
  361. if (length === 0) {
  362. return true;
  363. }
  364. for (var i = 0; i < length; i += 1) {
  365. if (deepEqual(leftHandOperand[keys[i]], rightHandOperand[keys[i]], options) === false) {
  366. return false;
  367. }
  368. }
  369. return true;
  370. }
  371. /*!
  372. * Recursively check the equality of two Objects. Once basic sameness has been established it will defer to `deepEqual`
  373. * for each enumerable key in the object.
  374. *
  375. * @param {Mixed} leftHandOperand
  376. * @param {Mixed} rightHandOperand
  377. * @param {Object} [options] (Optional)
  378. * @return {Boolean} result
  379. */
  380. function objectEqual(leftHandOperand, rightHandOperand, options) {
  381. var leftHandKeys = getEnumerableKeys(leftHandOperand);
  382. var rightHandKeys = getEnumerableKeys(rightHandOperand);
  383. if (leftHandKeys.length && leftHandKeys.length === rightHandKeys.length) {
  384. leftHandKeys.sort();
  385. rightHandKeys.sort();
  386. if (iterableEqual(leftHandKeys, rightHandKeys) === false) {
  387. return false;
  388. }
  389. return keysEqual(leftHandOperand, rightHandOperand, leftHandKeys, options);
  390. }
  391. var leftHandEntries = getIteratorEntries(leftHandOperand);
  392. var rightHandEntries = getIteratorEntries(rightHandOperand);
  393. if (leftHandEntries.length && leftHandEntries.length === rightHandEntries.length) {
  394. leftHandEntries.sort();
  395. rightHandEntries.sort();
  396. return iterableEqual(leftHandEntries, rightHandEntries, options);
  397. }
  398. if (leftHandKeys.length === 0 &&
  399. leftHandEntries.length === 0 &&
  400. rightHandKeys.length === 0 &&
  401. rightHandEntries.length === 0) {
  402. return true;
  403. }
  404. return false;
  405. }
  406. /*!
  407. * Returns true if the argument is a primitive.
  408. *
  409. * This intentionally returns true for all objects that can be compared by reference,
  410. * including functions and symbols.
  411. *
  412. * @param {Mixed} value
  413. * @return {Boolean} result
  414. */
  415. function isPrimitive(value) {
  416. return value === null || typeof value !== 'object';
  417. }