diff --git a/README.md b/README.md index 5356224..8a304f9 100644 --- a/README.md +++ b/README.md @@ -32,4 +32,8 @@ NodeJS or open `test/run.html` in a browser. To run the tests in your browser, simply use `npm run test:jasmine`. To run the tests using Karma use `npm run test:karma` and for continious tests run with file changes detection `npm run test:karma-dev`. Finally to open a remote debug console on karma use `npm run test:karma-debug`. +======= +## Design principles + +- extends core types (e.g extends `Array.prototype` with additional non-enumerable properties like `.set`) diff --git a/deque.js b/deque.js index 3f004c4..7c37028 100644 --- a/deque.js +++ b/deque.js @@ -346,8 +346,25 @@ Deque.prototype.lastIndexOf = function (value, index) { return -1; } -// TODO rename findValue -Deque.prototype.find = function (value, equals, index) { +var deprecatedWarnNonce = {}; +function deprecatedWarn(msg, notOnce) { + if ( + typeof console !== 'undefined' && + typeof console.warn === 'function' && + (notOnce !== true && deprecatedWarnNonce.hasOwnProperty(msg) === false) + ) { + console.warn(msg); + deprecatedWarnNonce[msg]++; + } +} + +// TODO remove in v6 (not present in v2) +Deque.prototype.find = function () { + deprecatedWarn('Deque#find function is deprecated please use Deque#findValue instead.'); + return this.findValue.apply(this, arguments); +}; + +Deque.prototype.findValue = function (value, equals, index) { equals = equals || Object.equals; // Default start index at beginning if (index == null) { @@ -368,8 +385,13 @@ Deque.prototype.find = function (value, equals, index) { return -1; }; -// TODO rename findLastValue -Deque.prototype.findLast = function (value, equals, index) { +// TODO remove in v6 (not present in v2) +Deque.prototype.findLast = function () { + deprecatedWarn('Deque#findLast function is deprecated please use Deque#findLastValue instead.'); + return this.findLastValue.apply(this, arguments); +}; + +Deque.prototype.findLastValue = function (value, equals, index) { equals = equals || Object.equals; // Default start position at the end if (index == null) { diff --git a/shim-array.js b/shim-array.js index 1aed113..a6d74c7 100644 --- a/shim-array.js +++ b/shim-array.js @@ -86,13 +86,13 @@ define("constructClone", function (values) { }); define("has", function (value, equals) { - return this.find(value, equals) !== -1; + return this.findValue(value, equals) !== -1; }); define("get", function (index, defaultValue) { - if (+index !== index) + if (+index !== index) { throw new Error("Indicies must be numbers"); - if (!index in this) { + } else if (!index in this) { return defaultValue; } else { return this[index]; @@ -110,7 +110,7 @@ define("add", function (value) { }); define("delete", function (value, equals) { - var index = this.find(value, equals); + var index = this.findValue(value, equals); if (index !== -1) { this.spliceOne(index); return true; @@ -132,7 +132,81 @@ define("deleteAll", function (value, equals) { return count; }); -define("find", function (value, equals) { +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find +// https://tc39.github.io/ecma262/#sec-array.prototype.find +if (!Array.prototype.find) { + Object.defineProperty(Array.prototype, 'find', { + value: function(predicate) { + // 1. Let O be ? ToObject(this value). + if (this == null) { + throw new TypeError('"this" is null or not defined'); + } + + var o = Object(this); + + // 2. Let len be ? ToLength(? Get(O, "length")). + var len = o.length >>> 0; + + // 3. If IsCallable(predicate) is false, throw a TypeError exception. + if (typeof predicate !== 'function') { + throw new TypeError('predicate must be a function'); + } + + // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. + var thisArg = arguments[1]; + + // 5. Let k be 0. + var k = 0; + + // 6. Repeat, while k < len + while (k < len) { + // a. Let Pk be ! ToString(k). + // b. Let kValue be ? Get(O, Pk). + // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). + // d. If testResult is true, return kValue. + var kValue = o[k]; + if (predicate.call(thisArg, kValue, k, o)) { + return kValue; + } + // e. Increase k by 1. + k++; + } + } + }); +} + +// TODO remove in v6 (not present in v2) +var deprecatedWarnNonce = {}; +function deprecatedWarn(msg, notOnce) { + if ( + typeof console !== 'undefined' && + typeof console.warn === 'function' && + (notOnce !== true && deprecatedWarnNonce.hasOwnProperty(msg) === false) + ) { + console.warn(msg); + deprecatedWarnNonce[msg]++; + } +} + +// Save Array.prototype.find in order to support legacy and display warning. +// TODO remove in v6 (not present in v2) +var ArrayFindPrototype = Object.getOwnPropertyDescriptor(Array.prototype, 'find').value; +define("find", function (value, equals, index) { + if ( + typeof arguments[0] === 'function' && + this instanceof Array + ) { + return ArrayFindPrototype.apply(this, arguments); + } else { + deprecatedWarn('Array#find usage is deprecated please use Array#findValue'); + return this.findValue.apply(this, arguments); + } +}); + +define("findValue", function (value, equals, index) { + if (index) { + throw new Error("Array#findValue does not support third argument: index"); + } equals = equals || this.contentEquals || Object.equals; for (var index = 0; index < this.length; index++) { if (index in this && equals(value, this[index])) { @@ -142,7 +216,13 @@ define("find", function (value, equals) { return -1; }); +// TODO remove in v6 (not present in v2) define("findLast", function (value, equals) { + deprecatedWarn('Array#findLast function is deprecated please use Array#findLastValue instead.'); + return this.findLastValue.apply(this, arguments); +}); + +define("findLastValue", function (value, equals) { equals = equals || this.contentEquals || Object.equals; var index = this.length; do { @@ -358,7 +438,8 @@ function ArrayIterator(array, start, end) { this.array = array; this.start = start == null ? 0 : start; this.end = end; -}; +} + ArrayIterator.prototype.__iterationObject = null; Object.defineProperty(ArrayIterator.prototype,"_iterationObject", { get: function() { diff --git a/sorted-array.js b/sorted-array.js index 2913a52..416ba2b 100644 --- a/sorted-array.js +++ b/sorted-array.js @@ -198,24 +198,48 @@ SortedArray.prototype.lastIndexOf = function (value) { return searchLast(this.array, value, this.contentCompare, this.contentEquals); }; +var deprecatedWarnNonce = {}; +function deprecatedWarn(msg, notOnce) { + if ( + typeof console !== 'undefined' && + typeof console.warn === 'function' && + (notOnce !== true && deprecatedWarnNonce.hasOwnProperty(msg) === false) + ) { + console.warn(msg); + deprecatedWarnNonce[msg]++; + } +} + +// TODO remove in v6 (not present in v2) SortedArray.prototype.find = function (value, equals, index) { + deprecatedWarn('This SortedArray#find usage is deprecated please use SortedArray#findValue'); + return this.findValue.apply(this, arguments); +}; + +SortedArray.prototype.findValue = function (value, equals, index) { // TODO throw error if provided a start index if (equals) { - throw new Error("SortedArray#find does not support second argument: equals"); + throw new Error("SortedArray#findValue does not support second argument: equals"); } if (index) { - throw new Error("SortedArray#find does not support third argument: index"); + throw new Error("SortedArray#findValue does not support third argument: index"); } // TODO support initial partition index return searchFirst(this.array, value, this.contentCompare, this.contentEquals); }; +// TODO remove in v6 (not present in v2) SortedArray.prototype.findLast = function (value, equals, index) { + deprecatedWarn('This SortedArray#findLast usage is deprecated please use SortedArray#findLastValue'); + return this.findLastValue.apply(this, arguments); +}; + +SortedArray.prototype.findLastValue = function (value, equals, index) { if (equals) { - throw new Error("SortedArray#findLast does not support second argument: equals"); + throw new Error("SortedArray#findLastValue does not support second argument: equals"); } if (index) { - throw new Error("SortedArray#findLast does not support third argument: index"); + throw new Error("SortedArray#findLastValue does not support third argument: index"); } // TODO support initial partition index return searchLast(this.array, value, this.contentCompare, this.contentEquals); diff --git a/test/spec/array-spec.js b/test/spec/array-spec.js index 68eb8c9..a1d6f44 100644 --- a/test/spec/array-spec.js +++ b/test/spec/array-spec.js @@ -75,17 +75,45 @@ describe("Array-spec", function () { describe("find", function () { + it("should find an object in an array by one of its properties", function () { + var inventory = [ + {name: 'apples', quantity: 2}, + {name: 'bananas', quantity: 0}, + {name: 'cherries', quantity: 5} + ]; + + function isCherries(fruit) { + return fruit.name === 'cherries'; + } + + expect(inventory.find(isCherries)).toEqual(inventory[2]); + }); + + describe("find (deprecated support)", function () { + + it("should find equivalent objects", function () { + expect([{a:10}].find({a:10})).toEqual(0); + }); + + it("should allow equality comparison override", function () { + expect([{a:10}].find({a:10}, Object.is)).toEqual(-1); + }); + }); + + }); + + describe("findValue", function () { + it("should find equivalent objects", function () { - expect([{a:10}].find({a:10})).toEqual(0); + expect([{a:10}].findValue({a:10})).toEqual(0); }); it("should allow equality comparison override", function () { - expect([{a:10}].find({a:10}, Object.is)).toEqual(-1); + expect([{a:10}].findValue({a:10}, Object.is)).toEqual(-1); }); - }); - describe("findLast", function () { + describe("findLast (deprecated support)", function () { it("should find equivalent objects", function () { expect([{a:10}].findLast({a:10})).toEqual(0); @@ -102,6 +130,23 @@ describe("Array-spec", function () { }); + describe("findLastValue", function () { + + it("should find equivalent objects", function () { + expect([{a:10}].findLastValue({a:10})).toEqual(0); + }); + + it("should allow equality comparison override", function () { + expect([{a:10}].findLastValue({a:10}, Object.is)).toEqual(-1); + }); + + it("should find the last of equivalent objects", function () { + var object = {a: 10}; + expect([object, {a: 10}].findLastValue(object)).toEqual(1); + }); + + }); + describe("has", function () { it("should find equivalent objects", function () { diff --git a/test/spec/order.js b/test/spec/order.js index d657002..09db4f1 100644 --- a/test/spec/order.js +++ b/test/spec/order.js @@ -147,7 +147,7 @@ function describeOrder(Collection) { }); - describe("find", function () { + describe("find (deprecated support)", function () { it("finds equivalent values", function () { expect(Collection([10, 10, 10]).find(10)).toEqual(0); @@ -159,11 +159,30 @@ function describeOrder(Collection) { }); - describe("findLast", function () { + describe("findValue", function () { + + it("finds equivalent values", function () { + expect(Collection([10, 10, 10]).findValue(10)).toEqual(0); + }); + + it("finds equivalent values", function () { + expect(Collection([10, 10, 10]).findValue(10)).toEqual(0); + }); + + }); + + describe("findLast (deprecated support)", function () { it("finds equivalent values", function () { expect(Collection([10, 10, 10]).findLast(10)).toEqual(2); }); + }); + + describe("findLastValue", function () { + + it("finds equivalent values", function () { + expect(Collection([10, 10, 10]).findLastValue(10)).toEqual(2); + }); });