From ec5db592d7756826c31e710b1c759d7e9406b153 Mon Sep 17 00:00:00 2001 From: Antoine Raoul Date: Mon, 9 Oct 2023 21:50:41 +1100 Subject: [PATCH 1/6] Add es2023 array methods to observablearray --- .changeset/great-trainers-beg.md | 5 +++ packages/mobx/__tests__/v4/base/array.js | 50 ++++++++++++++++++++++ packages/mobx/__tests__/v5/base/array.js | 50 ++++++++++++++++++++++ packages/mobx/src/types/observablearray.ts | 6 +++ 4 files changed, 111 insertions(+) create mode 100644 .changeset/great-trainers-beg.md diff --git a/.changeset/great-trainers-beg.md b/.changeset/great-trainers-beg.md new file mode 100644 index 000000000..0dd18d20e --- /dev/null +++ b/.changeset/great-trainers-beg.md @@ -0,0 +1,5 @@ +--- +"mobx": minor +--- + +Added es2023 array methods support to observablearray. diff --git a/packages/mobx/__tests__/v4/base/array.js b/packages/mobx/__tests__/v4/base/array.js index 42d60683e..3acf53294 100644 --- a/packages/mobx/__tests__/v4/base/array.js +++ b/packages/mobx/__tests__/v4/base/array.js @@ -144,6 +144,34 @@ test("find(findIndex) and remove", function () { expect(a.remove(20)).toBe(false) }) +test("findLast(findLastIndex) and remove", function () { + const a = mobx.observable([10, 20, 20]) + let idx = -1 + function predicate(item, index) { + if (item === 20) { + idx = index + return true + } + return false + } + ;[].findLastIndex; + expect(a.findLast(predicate)).toBe(20) + expect(a.findLastIndex(predicate)).toBe(2) + expect(a.findLast(predicate)).toBe(20) + + expect(a.remove(20)).toBe(true) + expect(a.find(predicate)).toBe(20) + expect(idx).toBe(1) + expect(a.findIndex(predicate)).toBe(1) + idx = -1 + expect(a.remove(20)).toBe(true) + expect(a.findLast(predicate)).toBe(undefined) + expect(idx).toBe(-1) + expect(a.findLastIndex(predicate)).toBe(-1) + + expect(a.remove(20)).toBe(false) +}) + test("concat should automatically slice observable arrays, #260", () => { const a1 = mobx.observable([1, 2]) const a2 = mobx.observable([3, 4]) @@ -577,6 +605,8 @@ test("correct array should be passed to callbacks #2326", () => { "filter", "find", "findIndex", + "findLast", + "findLastIndex", "flatMap", "forEach", "map", @@ -756,6 +786,26 @@ describe("dehances", () => { expect([...array.values()]).toEqual([...dehanced.values()]) }) + test("toReversed", () => { + expect(array.toReversed()).toEqual(dehanced.toReversed()) + }) + + test("toSorted", () => { + expect(array.toSorted()).toEqual(dehanced.toSorted()) + }) + + test("toSorted with args", () => { + expect(array.toSorted((a, b) => a - b)).toEqual(dehanced.toSorted((a, b) => a - b)) + }) + + test("toSpliced", () => { + expect(array.toSpliced(1, 2)).toEqual(dehanced.toSpliced(1, 2)) + }) + + test("with", () => { + expect(array.with(1, 5)).toEqual(dehanced.with(1, 5)) + }) + test("flat/flatMap", () => { // not supported in V4 }) diff --git a/packages/mobx/__tests__/v5/base/array.js b/packages/mobx/__tests__/v5/base/array.js index 8b9cc576c..e083ac878 100644 --- a/packages/mobx/__tests__/v5/base/array.js +++ b/packages/mobx/__tests__/v5/base/array.js @@ -178,6 +178,34 @@ test("find(findIndex) and remove", function () { expect(a.remove(20)).toBe(false) }) +test("findLast(findLastIndex) and remove", function () { + const a = mobx.observable([10, 20, 20]) + let idx = -1 + function predicate(item, index) { + if (item === 20) { + idx = index + return true + } + return false + } + ;[].findLastIndex; + expect(a.findLast(predicate)).toBe(20) + expect(a.findLastIndex(predicate)).toBe(2) + expect(a.findLast(predicate)).toBe(20) + + expect(a.remove(20)).toBe(true) + expect(a.find(predicate)).toBe(20) + expect(idx).toBe(1) + expect(a.findIndex(predicate)).toBe(1) + idx = -1 + expect(a.remove(20)).toBe(true) + expect(a.findLast(predicate)).toBe(undefined) + expect(idx).toBe(-1) + expect(a.findLastIndex(predicate)).toBe(-1) + + expect(a.remove(20)).toBe(false) +}) + test("concat should automatically slice observable arrays, #260", () => { const a1 = mobx.observable([1, 2]) const a2 = mobx.observable([3, 4]) @@ -630,6 +658,8 @@ test("correct array should be passed to callbacks #2326", () => { "filter", "find", "findIndex", + "findLast", + "findLastIndex", "flatMap", "forEach", "map", @@ -807,6 +837,26 @@ describe("dehances", () => { expect([...array.values()]).toEqual([...dehanced.values()]) }) + test("toReversed", () => { + expect(array.toReversed()).toEqual(dehanced.toReversed()) + }) + + test("toSorted", () => { + expect(array.toSorted()).toEqual(dehanced.toSorted()) + }) + + test("toSorted with args", () => { + expect(array.toSorted((a, b) => a - b)).toEqual(dehanced.toSorted((a, b) => a - b)) + }) + + test("toSpliced", () => { + expect(array.toSpliced(1, 2)).toEqual(dehanced.toSpliced(1, 2)) + }) + + test("with", () => { + expect(array.with(1, 5)).toEqual(dehanced.with(1, 5)) + }) + test("flat/flatMap", () => { const nestedArray = [{ value: 1 }, [{ value: 2 }, [{ value: 3 }]]] const dehancedNestedArray = nestedArray.map(dehancer) diff --git a/packages/mobx/src/types/observablearray.ts b/packages/mobx/src/types/observablearray.ts index 6c3859b3f..a16cdc039 100644 --- a/packages/mobx/src/types/observablearray.ts +++ b/packages/mobx/src/types/observablearray.ts @@ -527,15 +527,21 @@ addArrayExtension("lastIndexOf", simpleFunc) addArrayExtension("slice", simpleFunc) addArrayExtension("toString", simpleFunc) addArrayExtension("toLocaleString", simpleFunc) +addArrayExtension("toSorted", simpleFunc) +addArrayExtension("toSpliced", simpleFunc) +addArrayExtension("with", simpleFunc) // map addArrayExtension("every", mapLikeFunc) addArrayExtension("filter", mapLikeFunc) addArrayExtension("find", mapLikeFunc) addArrayExtension("findIndex", mapLikeFunc) +addArrayExtension("findLast", mapLikeFunc) +addArrayExtension("findLastIndex", mapLikeFunc) addArrayExtension("flatMap", mapLikeFunc) addArrayExtension("forEach", mapLikeFunc) addArrayExtension("map", mapLikeFunc) addArrayExtension("some", mapLikeFunc) +addArrayExtension("toReversed", mapLikeFunc) // reduce addArrayExtension("reduce", reduceLikeFunc) addArrayExtension("reduceRight", reduceLikeFunc) From 209acea87431c38374e9054d42dab75cba5732de Mon Sep 17 00:00:00 2001 From: Antoine Raoul Date: Sat, 11 Nov 2023 15:49:32 +1100 Subject: [PATCH 2/6] add performance for lastIndexCase --- packages/mobx/__tests__/perf/perf.js | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/mobx/__tests__/perf/perf.js b/packages/mobx/__tests__/perf/perf.js index 4bdcbc635..b8b0a95df 100644 --- a/packages/mobx/__tests__/perf/perf.js +++ b/packages/mobx/__tests__/perf/perf.js @@ -196,6 +196,41 @@ results of this test: t.end() }) + test(`${version} - array.es2023 findLastIndex methods`, function (t) { + gc() + let aCalc = 0 + let bCalc = 0 + const ar = observable([0]) + const findLastIndexOfZero = computed(function () { + aCalc++ + return ar.findLastIndex(x => x === 0); + }) + const lastIndexOfZero = computed(function () { + bCalc++ + return ar.lastIndexOf(0); + }) + mobx.observe(findLastIndexOfZero, voidObserver, true) + mobx.observe(lastIndexOfZero, voidObserver, true) + + const start = now() + + t.equal(1, aCalc) + t.equal(1, bCalc) + for (let i = 1; i < 10000; i++) ar.push(i) + + t.equal(0, lastIndexOfZero.get()) + t.equal(0, findLastIndexOfZero.get()) + t.equal(10000, aCalc) + t.equal(10000, bCalc) + + const end = now() + + log( + "Array findLastIndex loop - Updated in " + (end - start) + " ms." + ) + t.end() + }) + test(`${version} - array reduce`, function (t) { gc() let aCalc = 0 From 3fc271eed9fc526ac49d6e6b07114d126950683c Mon Sep 17 00:00:00 2001 From: Antoine Raoul Date: Sat, 11 Nov 2023 15:53:13 +1100 Subject: [PATCH 3/6] addExtension es2022.arrays at method --- packages/mobx/__tests__/v4/base/array.js | 5 +++++ packages/mobx/__tests__/v5/base/array.js | 5 +++++ packages/mobx/src/types/observablearray.ts | 1 + 3 files changed, 11 insertions(+) diff --git a/packages/mobx/__tests__/v4/base/array.js b/packages/mobx/__tests__/v4/base/array.js index 3acf53294..03ea71113 100644 --- a/packages/mobx/__tests__/v4/base/array.js +++ b/packages/mobx/__tests__/v4/base/array.js @@ -806,6 +806,11 @@ describe("dehances", () => { expect(array.with(1, 5)).toEqual(dehanced.with(1, 5)) }) + test("at", () => { + expect(array.at(1)).toEqual(dehanced.at(1)) + expect(array.at(-1)).toEqual(dehanced.at(-1)) + }) + test("flat/flatMap", () => { // not supported in V4 }) diff --git a/packages/mobx/__tests__/v5/base/array.js b/packages/mobx/__tests__/v5/base/array.js index e083ac878..5b0751398 100644 --- a/packages/mobx/__tests__/v5/base/array.js +++ b/packages/mobx/__tests__/v5/base/array.js @@ -857,6 +857,11 @@ describe("dehances", () => { expect(array.with(1, 5)).toEqual(dehanced.with(1, 5)) }) + test("at", () => { + expect(array.at(1)).toEqual(dehanced.at(1)) + expect(array.at(-1)).toEqual(dehanced.at(-1)) + }) + test("flat/flatMap", () => { const nestedArray = [{ value: 1 }, [{ value: 2 }, [{ value: 3 }]]] const dehancedNestedArray = nestedArray.map(dehancer) diff --git a/packages/mobx/src/types/observablearray.ts b/packages/mobx/src/types/observablearray.ts index a16cdc039..3a57b3eab 100644 --- a/packages/mobx/src/types/observablearray.ts +++ b/packages/mobx/src/types/observablearray.ts @@ -518,6 +518,7 @@ export var arrayExtensions = { * Without this, everything works as well, but this works * faster as everything works on unproxied values */ +addArrayExtension("at", simpleFunc) addArrayExtension("concat", simpleFunc) addArrayExtension("flat", simpleFunc) addArrayExtension("includes", simpleFunc) From d5f53f411fa4066f79779863e9a5e8f5498a5f80 Mon Sep 17 00:00:00 2001 From: Antoine Raoul Date: Sat, 11 Nov 2023 16:05:05 +1100 Subject: [PATCH 4/6] Update changeset message to be more versbose --- .changeset/great-trainers-beg.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/great-trainers-beg.md b/.changeset/great-trainers-beg.md index 0dd18d20e..6dbcd896e 100644 --- a/.changeset/great-trainers-beg.md +++ b/.changeset/great-trainers-beg.md @@ -2,4 +2,4 @@ "mobx": minor --- -Added es2023 array methods support to observablearray. +Improve observablearray proxy pefromance for es2023.array and es2022.array methods \ No newline at end of file From 71d0c3c17f660ce68606964e4e46920eb939b4bd Mon Sep 17 00:00:00 2001 From: Antoine Raoul Date: Sat, 11 Nov 2023 16:14:29 +1100 Subject: [PATCH 5/6] Update node version within CI --- .github/workflows/build_and_test.yml | 4 ++-- .github/workflows/coveralls.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index ef5866b6a..37cbe0e02 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -14,10 +14,10 @@ jobs: - name: Checkout Repo uses: actions/checkout@master - - name: Setup Node.js 14.x + - name: Setup Node.js 18.x uses: actions/setup-node@master with: - node-version: 14.x + node-version: 18.x - name: Install Dependencies run: yarn --frozen-lockfile --ignore-scripts diff --git a/.github/workflows/coveralls.yml b/.github/workflows/coveralls.yml index d190ac589..93e8f90f2 100644 --- a/.github/workflows/coveralls.yml +++ b/.github/workflows/coveralls.yml @@ -13,10 +13,10 @@ jobs: # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 - - name: Setup Node.js 14.x + - name: Setup Node.js 18.x uses: actions/setup-node@master with: - node-version: 14.x + node-version: 18.x - name: Install Dependencies run: yarn --frozen-lockfile --ignore-scripts From 227290d2ffed2aedea178631a3166cab442d48c3 Mon Sep 17 00:00:00 2001 From: Antoine Raoul Date: Sun, 12 Nov 2023 02:10:19 +1100 Subject: [PATCH 6/6] Update CI to node 20 --- .github/workflows/build_and_test.yml | 4 ++-- .github/workflows/coveralls.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 37cbe0e02..0be7f1291 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -14,10 +14,10 @@ jobs: - name: Checkout Repo uses: actions/checkout@master - - name: Setup Node.js 18.x + - name: Setup Node.js 20.x uses: actions/setup-node@master with: - node-version: 18.x + node-version: 20.x - name: Install Dependencies run: yarn --frozen-lockfile --ignore-scripts diff --git a/.github/workflows/coveralls.yml b/.github/workflows/coveralls.yml index 93e8f90f2..0eb13139d 100644 --- a/.github/workflows/coveralls.yml +++ b/.github/workflows/coveralls.yml @@ -13,10 +13,10 @@ jobs: # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 - - name: Setup Node.js 18.x + - name: Setup Node.js 20.x uses: actions/setup-node@master with: - node-version: 18.x + node-version: 20.x - name: Install Dependencies run: yarn --frozen-lockfile --ignore-scripts