From 1d07280a3827ff223ecf0abe6a628caa6af7a423 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Tue, 29 May 2018 10:28:02 +0200
Subject: [PATCH 01/15] :construction: PoC nav
---
packages/immutadot/src/nav/consts.js | 1 +
packages/immutadot/src/nav/nav.js | 18 +++++++++++++
packages/immutadot/src/nav/nav.spec.js | 37 ++++++++++++++++++++++++++
packages/immutadot/src/nav/prop.js | 13 +++++++++
4 files changed, 69 insertions(+)
create mode 100644 packages/immutadot/src/nav/consts.js
create mode 100644 packages/immutadot/src/nav/nav.js
create mode 100644 packages/immutadot/src/nav/nav.spec.js
create mode 100644 packages/immutadot/src/nav/prop.js
diff --git a/packages/immutadot/src/nav/consts.js b/packages/immutadot/src/nav/consts.js
new file mode 100644
index 00000000..2aa4aea7
--- /dev/null
+++ b/packages/immutadot/src/nav/consts.js
@@ -0,0 +1 @@
+export const NONE = Symbol()
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
new file mode 100644
index 00000000..cf3cc9b0
--- /dev/null
+++ b/packages/immutadot/src/nav/nav.js
@@ -0,0 +1,18 @@
+import * as types from '@immutadot/parser/consts'
+import { NONE } from './consts'
+import { prop } from './prop'
+
+export function nav(path) {
+ return path.map(toNav).reduceRight((next, nav) => nav(next), finalNav)
+}
+
+function toNav([type, value]) {
+ switch (type) {
+ case types.prop: return prop(value)
+ default: throw TypeError(type)
+ }
+}
+
+function finalNav(value) {
+ return (updater = NONE) => updater === NONE ? value : updater(value)
+}
diff --git a/packages/immutadot/src/nav/nav.spec.js b/packages/immutadot/src/nav/nav.spec.js
new file mode 100644
index 00000000..2679e470
--- /dev/null
+++ b/packages/immutadot/src/nav/nav.spec.js
@@ -0,0 +1,37 @@
+/* eslint-env jest */
+import { immutaTest } from 'test.utils'
+import { nav } from './nav'
+import { toPath } from '@immutadot/parser'
+
+describe('nav.nav', () => {
+ const obj = { nested: { prop: 'foo' } }
+ const path = 'nested.prop'
+
+ it('should allow to get a nested prop', () => {
+ expect(nav(toPath(path))(obj)()).toBe('foo')
+ })
+
+ it('should allow to set a nested prop', () => {
+ immutaTest(
+ obj,
+ [path],
+ input => {
+ const output = nav(toPath(path))(input)(() => 'bar')
+ expect(output).toEqual({ nested: { prop: 'bar' } })
+ return output
+ },
+ )
+ })
+
+ it('should allow to update a nested prop', () => {
+ immutaTest(
+ obj,
+ [path],
+ input => {
+ const output = nav(toPath(path))(input)(value => value.toUpperCase())
+ expect(output).toEqual({ nested: { prop: 'FOO' } })
+ return output
+ },
+ )
+ })
+})
diff --git a/packages/immutadot/src/nav/prop.js b/packages/immutadot/src/nav/prop.js
new file mode 100644
index 00000000..520ac5ca
--- /dev/null
+++ b/packages/immutadot/src/nav/prop.js
@@ -0,0 +1,13 @@
+import { NONE } from './consts'
+import { isNil } from 'util/lang'
+
+export function prop(key) {
+ return next => obj => (updater = NONE) => {
+ const nextValue = isNil(obj) ? next(undefined) : next(obj[key])
+
+ if (updater === NONE) return nextValue()
+
+ const copy = isNil(obj) ? {} : { ...obj }
+ return Object.assign(copy, { [key]: nextValue(updater) })
+ }
+}
From 6203a823772f6207340be8df00af1d0912380ff9 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Tue, 29 May 2018 11:59:47 +0200
Subject: [PATCH 02/15] :construction: Add index navigator
---
packages/immutadot/src/nav/_index.js | 19 +++++++++++++++++++
packages/immutadot/src/nav/nav.js | 2 ++
packages/immutadot/src/nav/nav.spec.js | 12 ++++++++++++
3 files changed, 33 insertions(+)
create mode 100644 packages/immutadot/src/nav/_index.js
diff --git a/packages/immutadot/src/nav/_index.js b/packages/immutadot/src/nav/_index.js
new file mode 100644
index 00000000..c1291946
--- /dev/null
+++ b/packages/immutadot/src/nav/_index.js
@@ -0,0 +1,19 @@
+import { NONE } from './consts'
+import { isNil } from 'util/lang'
+
+function makeCopy(obj) {
+ if (isNil(obj)) return []
+ return Array.isArray()
+}
+
+export function index(key) {
+ return next => obj => (updater = NONE) => {
+ const nextValue = isNil(obj) ? next(undefined) : next(obj[key])
+
+ if (updater === NONE) return nextValue()
+
+ const copy = makeCopy(obj)
+ copy[key] = nextValue(updater)
+ return copy
+ }
+}
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index cf3cc9b0..0bddf51f 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -1,5 +1,6 @@
import * as types from '@immutadot/parser/consts'
import { NONE } from './consts'
+import { index } from './_index'
import { prop } from './prop'
export function nav(path) {
@@ -9,6 +10,7 @@ export function nav(path) {
function toNav([type, value]) {
switch (type) {
case types.prop: return prop(value)
+ case types.index: return index(value)
default: throw TypeError(type)
}
}
diff --git a/packages/immutadot/src/nav/nav.spec.js b/packages/immutadot/src/nav/nav.spec.js
index 2679e470..8724a394 100644
--- a/packages/immutadot/src/nav/nav.spec.js
+++ b/packages/immutadot/src/nav/nav.spec.js
@@ -34,4 +34,16 @@ describe('nav.nav', () => {
},
)
})
+
+ it('should create unknown path', () => {
+ immutaTest(
+ {},
+ ['nested.prop.0', 'nested.prop.1'],
+ input => {
+ const output = nav(toPath('nested.prop[1]'))(input)(() => 'foo')
+ expect(output).toEqual({ nested: { prop: [undefined, 'foo'] } })
+ return output
+ },
+ )
+ })
})
From 9592a003ac30de8deb6696cd838554e0293e04c3 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Tue, 29 May 2018 15:04:48 +0200
Subject: [PATCH 03/15] :construction: Add slice navigator
---
packages/immutadot/src/nav/_index.js | 14 +++---
packages/immutadot/src/nav/nav.js | 2 +
packages/immutadot/src/nav/nav.spec.js | 60 ++++++++++++++++++++------
packages/immutadot/src/nav/prop.js | 10 +++--
packages/immutadot/src/nav/slice.js | 49 +++++++++++++++++++++
5 files changed, 112 insertions(+), 23 deletions(-)
create mode 100644 packages/immutadot/src/nav/slice.js
diff --git a/packages/immutadot/src/nav/_index.js b/packages/immutadot/src/nav/_index.js
index c1291946..ea1b596a 100644
--- a/packages/immutadot/src/nav/_index.js
+++ b/packages/immutadot/src/nav/_index.js
@@ -3,17 +3,19 @@ import { isNil } from 'util/lang'
function makeCopy(obj) {
if (isNil(obj)) return []
- return Array.isArray()
+ return Array.isArray(obj) ? [...obj] : { ...obj }
}
export function index(key) {
- return next => obj => (updater = NONE) => {
+ return next => obj => {
const nextValue = isNil(obj) ? next(undefined) : next(obj[key])
- if (updater === NONE) return nextValue()
+ return (updater = NONE) => {
+ if (updater === NONE) return nextValue()
- const copy = makeCopy(obj)
- copy[key] = nextValue(updater)
- return copy
+ const copy = makeCopy(obj)
+ copy[key] = nextValue(updater)
+ return copy
+ }
}
}
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index 0bddf51f..47eed426 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -2,6 +2,7 @@ import * as types from '@immutadot/parser/consts'
import { NONE } from './consts'
import { index } from './_index'
import { prop } from './prop'
+import { slice } from './slice'
export function nav(path) {
return path.map(toNav).reduceRight((next, nav) => nav(next), finalNav)
@@ -11,6 +12,7 @@ function toNav([type, value]) {
switch (type) {
case types.prop: return prop(value)
case types.index: return index(value)
+ case types.slice: return slice(value)
default: throw TypeError(type)
}
}
diff --git a/packages/immutadot/src/nav/nav.spec.js b/packages/immutadot/src/nav/nav.spec.js
index 8724a394..1518f41a 100644
--- a/packages/immutadot/src/nav/nav.spec.js
+++ b/packages/immutadot/src/nav/nav.spec.js
@@ -4,18 +4,15 @@ import { nav } from './nav'
import { toPath } from '@immutadot/parser'
describe('nav.nav', () => {
- const obj = { nested: { prop: 'foo' } }
- const path = 'nested.prop'
-
- it('should allow to get a nested prop', () => {
- expect(nav(toPath(path))(obj)()).toBe('foo')
+ it('should get a nested prop', () => {
+ expect(nav(toPath('nested.prop'))({ nested: { prop: 'foo' } })()).toBe('foo')
})
- it('should allow to set a nested prop', () => {
+ it('should set a nested prop', () => {
immutaTest(
- obj,
- [path],
- input => {
+ { nested: { prop: 'foo' } },
+ ['nested.prop'],
+ (input, [path]) => {
const output = nav(toPath(path))(input)(() => 'bar')
expect(output).toEqual({ nested: { prop: 'bar' } })
return output
@@ -23,11 +20,11 @@ describe('nav.nav', () => {
)
})
- it('should allow to update a nested prop', () => {
+ it('should update a nested prop', () => {
immutaTest(
- obj,
- [path],
- input => {
+ { nested: { prop: 'foo' } },
+ ['nested.prop'],
+ (input, [path]) => {
const output = nav(toPath(path))(input)(value => value.toUpperCase())
expect(output).toEqual({ nested: { prop: 'FOO' } })
return output
@@ -46,4 +43,41 @@ describe('nav.nav', () => {
},
)
})
+
+ it('should get a slice', () => {
+ expect(nav(toPath('nested.prop[:].val'))({
+ nested: {
+ prop: [
+ { val: 'foo' },
+ { val: 'bar' },
+ ],
+ },
+ })()).toEqual(['foo', 'bar'])
+ })
+
+ it('should update a slice', () => immutaTest(
+ {
+ nested: {
+ prop: [
+ { val: 'foo' },
+ { val: 'bar' },
+ { val: 'baz' },
+ ],
+ },
+ },
+ ['nested.prop.1.val', 'nested.prop.2.val'],
+ input => {
+ const output = nav(toPath('nested.prop[-2:].val'))(input)(value => value.toUpperCase())
+ expect(output).toEqual({
+ nested: {
+ prop: [
+ { val: 'foo' },
+ { val: 'BAR' },
+ { val: 'BAZ' },
+ ],
+ },
+ })
+ return output
+ },
+ ))
})
diff --git a/packages/immutadot/src/nav/prop.js b/packages/immutadot/src/nav/prop.js
index 520ac5ca..24aa7b95 100644
--- a/packages/immutadot/src/nav/prop.js
+++ b/packages/immutadot/src/nav/prop.js
@@ -2,12 +2,14 @@ import { NONE } from './consts'
import { isNil } from 'util/lang'
export function prop(key) {
- return next => obj => (updater = NONE) => {
+ return next => obj => {
const nextValue = isNil(obj) ? next(undefined) : next(obj[key])
- if (updater === NONE) return nextValue()
+ return (updater = NONE) => {
+ if (updater === NONE) return nextValue()
- const copy = isNil(obj) ? {} : { ...obj }
- return Object.assign(copy, { [key]: nextValue(updater) })
+ const copy = isNil(obj) ? {} : { ...obj }
+ return Object.assign(copy, { [key]: nextValue(updater) })
+ }
}
}
diff --git a/packages/immutadot/src/nav/slice.js b/packages/immutadot/src/nav/slice.js
new file mode 100644
index 00000000..a1e0ae6a
--- /dev/null
+++ b/packages/immutadot/src/nav/slice.js
@@ -0,0 +1,49 @@
+import {
+ isNil,
+ length,
+} from 'util/lang'
+import { NONE } from './consts'
+
+function getSliceBound(value, length) {
+ if (value < 0) return Math.max(length + value, 0)
+ return value
+}
+
+function getSliceBounds([start, end], length) {
+ return [
+ getSliceBound(start, length),
+ getSliceBound(end === undefined ? length : end, length),
+ ]
+}
+
+// FIXME mutualize with index (same file array.js ?)
+function makeCopy(obj) {
+ if (isNil(obj)) return []
+ return Array.isArray(obj) ? [...obj] : { ...obj }
+}
+
+export function slice(bounds) {
+ return next => obj => {
+ let nextValue
+
+ if (isNil(obj)) {
+ nextValue = () => []
+ } else {
+ const [start, end] = getSliceBounds(bounds, length(obj))
+
+ const nextValues = Array.from(function* () {
+ for (let i = start; i < end; i++) yield [i, next(obj[i])]
+ }())
+
+ nextValue = updater => nextValues.map(([i, nextIndex]) => [i, nextIndex(updater)])
+ }
+
+ return (updater = NONE) => {
+ if (updater === NONE) return nextValue().map(([, value]) => value)
+
+ const copy = makeCopy(obj)
+ for (const [i, value] of nextValue(updater)) copy[i] = value
+ return copy
+ }
+ }
+}
From 52f80e85d9776288f26fda81b2efa38a2503c002 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Tue, 29 May 2018 15:15:05 +0200
Subject: [PATCH 04/15] :recycle: Reorganize code
---
packages/immutadot/src/nav/_index.js | 21 -------------
.../immutadot/src/nav/{slice.js => array.js} | 30 ++++++++++++-------
packages/immutadot/src/nav/nav.js | 5 ++--
.../immutadot/src/nav/{prop.js => object.js} | 0
4 files changed, 22 insertions(+), 34 deletions(-)
delete mode 100644 packages/immutadot/src/nav/_index.js
rename packages/immutadot/src/nav/{slice.js => array.js} (75%)
rename packages/immutadot/src/nav/{prop.js => object.js} (100%)
diff --git a/packages/immutadot/src/nav/_index.js b/packages/immutadot/src/nav/_index.js
deleted file mode 100644
index ea1b596a..00000000
--- a/packages/immutadot/src/nav/_index.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { NONE } from './consts'
-import { isNil } from 'util/lang'
-
-function makeCopy(obj) {
- if (isNil(obj)) return []
- return Array.isArray(obj) ? [...obj] : { ...obj }
-}
-
-export function index(key) {
- return next => obj => {
- const nextValue = isNil(obj) ? next(undefined) : next(obj[key])
-
- return (updater = NONE) => {
- if (updater === NONE) return nextValue()
-
- const copy = makeCopy(obj)
- copy[key] = nextValue(updater)
- return copy
- }
- }
-}
diff --git a/packages/immutadot/src/nav/slice.js b/packages/immutadot/src/nav/array.js
similarity index 75%
rename from packages/immutadot/src/nav/slice.js
rename to packages/immutadot/src/nav/array.js
index a1e0ae6a..9988afea 100644
--- a/packages/immutadot/src/nav/slice.js
+++ b/packages/immutadot/src/nav/array.js
@@ -1,9 +1,25 @@
-import {
- isNil,
- length,
-} from 'util/lang'
+import { isNil, length } from 'util/lang'
import { NONE } from './consts'
+function makeCopy(obj) {
+ if (isNil(obj)) return []
+ return Array.isArray(obj) ? [...obj] : { ...obj }
+}
+
+export function index(key) {
+ return next => obj => {
+ const nextValue = isNil(obj) ? next(undefined) : next(obj[key])
+
+ return (updater = NONE) => {
+ if (updater === NONE) return nextValue()
+
+ const copy = makeCopy(obj)
+ copy[key] = nextValue(updater)
+ return copy
+ }
+ }
+}
+
function getSliceBound(value, length) {
if (value < 0) return Math.max(length + value, 0)
return value
@@ -16,12 +32,6 @@ function getSliceBounds([start, end], length) {
]
}
-// FIXME mutualize with index (same file array.js ?)
-function makeCopy(obj) {
- if (isNil(obj)) return []
- return Array.isArray(obj) ? [...obj] : { ...obj }
-}
-
export function slice(bounds) {
return next => obj => {
let nextValue
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index 47eed426..ddb4eabe 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -1,8 +1,7 @@
import * as types from '@immutadot/parser/consts'
+import { index, slice } from './array'
import { NONE } from './consts'
-import { index } from './_index'
-import { prop } from './prop'
-import { slice } from './slice'
+import { prop } from './object'
export function nav(path) {
return path.map(toNav).reduceRight((next, nav) => nav(next), finalNav)
diff --git a/packages/immutadot/src/nav/prop.js b/packages/immutadot/src/nav/object.js
similarity index 100%
rename from packages/immutadot/src/nav/prop.js
rename to packages/immutadot/src/nav/object.js
From 2e406869c4bbab772cbfd17ae5973092b1eecc02 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Tue, 29 May 2018 16:25:00 +0200
Subject: [PATCH 05/15] :recycle: Move apart get and update logic and use ES6
classes
---
packages/immutadot/src/nav/array.js | 109 ++++++++++++++++---------
packages/immutadot/src/nav/consts.js | 1 -
packages/immutadot/src/nav/nav.js | 29 +++++--
packages/immutadot/src/nav/nav.spec.js | 12 +--
packages/immutadot/src/nav/object.js | 34 ++++++--
5 files changed, 121 insertions(+), 64 deletions(-)
delete mode 100644 packages/immutadot/src/nav/consts.js
diff --git a/packages/immutadot/src/nav/array.js b/packages/immutadot/src/nav/array.js
index 9988afea..fa0005e8 100644
--- a/packages/immutadot/src/nav/array.js
+++ b/packages/immutadot/src/nav/array.js
@@ -1,59 +1,88 @@
import { isNil, length } from 'util/lang'
-import { NONE } from './consts'
-function makeCopy(obj) {
- if (isNil(obj)) return []
- return Array.isArray(obj) ? [...obj] : { ...obj }
+class ArrayNav {
+ constructor(obj, next) {
+ this.obj = obj
+ this.next = next
+ }
+
+ copy() {
+ if (isNil(this.obj)) return []
+ return Array.isArray(this.obj) ? [...this.obj] : { ...this.obj }
+ }
}
-export function index(key) {
- return next => obj => {
- const nextValue = isNil(obj) ? next(undefined) : next(obj[key])
+class IndexNav extends ArrayNav {
+ constructor(obj, index, next) {
+ super(obj, next)
+ this.index = index
+ }
- return (updater = NONE) => {
- if (updater === NONE) return nextValue()
+ get nextValue() {
+ return isNil(this.obj) ? this.next(undefined) : this.next(this.obj[this.index])
+ }
- const copy = makeCopy(obj)
- copy[key] = nextValue(updater)
- return copy
- }
+ get() {
+ return this.nextValue.get()
}
-}
-function getSliceBound(value, length) {
- if (value < 0) return Math.max(length + value, 0)
- return value
+ update(updater) {
+ const copy = this.copy()
+ copy[this.index] = this.nextValue.update(updater)
+ return copy
+ }
}
-function getSliceBounds([start, end], length) {
- return [
- getSliceBound(start, length),
- getSliceBound(end === undefined ? length : end, length),
- ]
+export function indexNav(index) {
+ return next => obj => new IndexNav(obj, index, next)
}
-export function slice(bounds) {
- return next => obj => {
- let nextValue
+class SliceNav extends ArrayNav {
+ constructor(obj, bounds, next) {
+ super(obj, next)
+ this.bounds = bounds
+ }
- if (isNil(obj)) {
- nextValue = () => []
- } else {
- const [start, end] = getSliceBounds(bounds, length(obj))
+ get length() {
+ if (this._length === undefined) this._length = length(this.obj)
+ return this._length
+ }
- const nextValues = Array.from(function* () {
- for (let i = start; i < end; i++) yield [i, next(obj[i])]
- }())
+ bound(index) {
+ if (index < 0) return Math.max(this.length + index, 0)
+ return index
+ }
- nextValue = updater => nextValues.map(([i, nextIndex]) => [i, nextIndex(updater)])
- }
+ get start() {
+ return this.bound(this.bounds[0])
+ }
- return (updater = NONE) => {
- if (updater === NONE) return nextValue().map(([, value]) => value)
+ get end() {
+ const [, end] = this.bounds
+ return this.bound(end === undefined ? this.length : end)
+ }
- const copy = makeCopy(obj)
- for (const [i, value] of nextValue(updater)) copy[i] = value
- return copy
- }
+ get range() {
+ const { start, end } = this
+ return (function*() {
+ for (let i = start; i < end; i++) yield i
+ }())
}
+
+ get() {
+ if (isNil(this.obj)) return []
+ return Array.from(this.range, index => this.next(this.obj[index]).get())
+ }
+
+ update(updater) {
+ if (isNil(this.obj)) return []
+
+ const copy = this.copy()
+ for (const index of this.range) copy[index] = this.next(this.obj[index]).update(updater)
+ return copy
+ }
+}
+
+export function sliceNav(bounds) {
+ return next => obj => new SliceNav(obj, bounds, next)
}
diff --git a/packages/immutadot/src/nav/consts.js b/packages/immutadot/src/nav/consts.js
deleted file mode 100644
index 2aa4aea7..00000000
--- a/packages/immutadot/src/nav/consts.js
+++ /dev/null
@@ -1 +0,0 @@
-export const NONE = Symbol()
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index ddb4eabe..784f05d6 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -1,7 +1,6 @@
-import * as types from '@immutadot/parser/consts'
-import { index, slice } from './array'
-import { NONE } from './consts'
-import { prop } from './object'
+import { index, prop, slice } from '@immutadot/parser/consts'
+import { indexNav, sliceNav } from './array'
+import { propNav } from './object'
export function nav(path) {
return path.map(toNav).reduceRight((next, nav) => nav(next), finalNav)
@@ -9,13 +8,27 @@ export function nav(path) {
function toNav([type, value]) {
switch (type) {
- case types.prop: return prop(value)
- case types.index: return index(value)
- case types.slice: return slice(value)
+ case prop: return propNav(value)
+ case index: return indexNav(value)
+ case slice: return sliceNav(value)
default: throw TypeError(type)
}
}
+class FinalNav {
+ constructor(value) {
+ this.value = value
+ }
+
+ get() {
+ return this.value
+ }
+
+ update(updater) {
+ return updater(this.value)
+ }
+}
+
function finalNav(value) {
- return (updater = NONE) => updater === NONE ? value : updater(value)
+ return new FinalNav(value)
}
diff --git a/packages/immutadot/src/nav/nav.spec.js b/packages/immutadot/src/nav/nav.spec.js
index 1518f41a..33125f16 100644
--- a/packages/immutadot/src/nav/nav.spec.js
+++ b/packages/immutadot/src/nav/nav.spec.js
@@ -5,7 +5,7 @@ import { toPath } from '@immutadot/parser'
describe('nav.nav', () => {
it('should get a nested prop', () => {
- expect(nav(toPath('nested.prop'))({ nested: { prop: 'foo' } })()).toBe('foo')
+ expect(nav(toPath('nested.prop'))({ nested: { prop: 'foo' } }).get()).toBe('foo')
})
it('should set a nested prop', () => {
@@ -13,7 +13,7 @@ describe('nav.nav', () => {
{ nested: { prop: 'foo' } },
['nested.prop'],
(input, [path]) => {
- const output = nav(toPath(path))(input)(() => 'bar')
+ const output = nav(toPath(path))(input).update(() => 'bar')
expect(output).toEqual({ nested: { prop: 'bar' } })
return output
},
@@ -25,7 +25,7 @@ describe('nav.nav', () => {
{ nested: { prop: 'foo' } },
['nested.prop'],
(input, [path]) => {
- const output = nav(toPath(path))(input)(value => value.toUpperCase())
+ const output = nav(toPath(path))(input).update(value => value.toUpperCase())
expect(output).toEqual({ nested: { prop: 'FOO' } })
return output
},
@@ -37,7 +37,7 @@ describe('nav.nav', () => {
{},
['nested.prop.0', 'nested.prop.1'],
input => {
- const output = nav(toPath('nested.prop[1]'))(input)(() => 'foo')
+ const output = nav(toPath('nested.prop[1]'))(input).update(() => 'foo')
expect(output).toEqual({ nested: { prop: [undefined, 'foo'] } })
return output
},
@@ -52,7 +52,7 @@ describe('nav.nav', () => {
{ val: 'bar' },
],
},
- })()).toEqual(['foo', 'bar'])
+ }).get()).toEqual(['foo', 'bar'])
})
it('should update a slice', () => immutaTest(
@@ -67,7 +67,7 @@ describe('nav.nav', () => {
},
['nested.prop.1.val', 'nested.prop.2.val'],
input => {
- const output = nav(toPath('nested.prop[-2:].val'))(input)(value => value.toUpperCase())
+ const output = nav(toPath('nested.prop[-2:].val'))(input).update(value => value.toUpperCase())
expect(output).toEqual({
nested: {
prop: [
diff --git a/packages/immutadot/src/nav/object.js b/packages/immutadot/src/nav/object.js
index 24aa7b95..ebb1829c 100644
--- a/packages/immutadot/src/nav/object.js
+++ b/packages/immutadot/src/nav/object.js
@@ -1,15 +1,31 @@
-import { NONE } from './consts'
import { isNil } from 'util/lang'
-export function prop(key) {
- return next => obj => {
- const nextValue = isNil(obj) ? next(undefined) : next(obj[key])
+class PropNav {
+ constructor(obj, key, next) {
+ this.obj = obj
+ this.key = key
+ this.next = next
+ }
+
+ get nextValue() {
+ return isNil(this.obj) ? this.next(undefined) : this.next(this.obj[this.key])
+ }
+
+ get() {
+ return this.nextValue.get()
+ }
- return (updater = NONE) => {
- if (updater === NONE) return nextValue()
+ copy() {
+ return isNil(this.obj) ? {} : { ...this.obj }
+ }
- const copy = isNil(obj) ? {} : { ...obj }
- return Object.assign(copy, { [key]: nextValue(updater) })
- }
+ update(updater) {
+ const copy = this.copy()
+ copy[this.key] = this.nextValue.update(updater)
+ return copy
}
}
+
+export function propNav(key) {
+ return next => obj => new PropNav(obj, key, next)
+}
From 0960f54786216ac812efdf107e7426c34a5c7b48 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Tue, 29 May 2018 16:29:36 +0200
Subject: [PATCH 06/15] :fire: Remove unused currification level
---
packages/immutadot/src/nav/array.js | 8 ++++----
packages/immutadot/src/nav/nav.js | 10 +++++-----
packages/immutadot/src/nav/object.js | 4 ++--
3 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/packages/immutadot/src/nav/array.js b/packages/immutadot/src/nav/array.js
index fa0005e8..4f45d25c 100644
--- a/packages/immutadot/src/nav/array.js
+++ b/packages/immutadot/src/nav/array.js
@@ -33,8 +33,8 @@ class IndexNav extends ArrayNav {
}
}
-export function indexNav(index) {
- return next => obj => new IndexNav(obj, index, next)
+export function indexNav(index, next) {
+ return obj => new IndexNav(obj, index, next)
}
class SliceNav extends ArrayNav {
@@ -83,6 +83,6 @@ class SliceNav extends ArrayNav {
}
}
-export function sliceNav(bounds) {
- return next => obj => new SliceNav(obj, bounds, next)
+export function sliceNav(bounds, next) {
+ return obj => new SliceNav(obj, bounds, next)
}
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index 784f05d6..9e3a5588 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -3,14 +3,14 @@ import { indexNav, sliceNav } from './array'
import { propNav } from './object'
export function nav(path) {
- return path.map(toNav).reduceRight((next, nav) => nav(next), finalNav)
+ return path.reduceRight((next, [type, value]) => toNav(type)(value, next), finalNav)
}
-function toNav([type, value]) {
+function toNav(type) {
switch (type) {
- case prop: return propNav(value)
- case index: return indexNav(value)
- case slice: return sliceNav(value)
+ case prop: return propNav
+ case index: return indexNav
+ case slice: return sliceNav
default: throw TypeError(type)
}
}
diff --git a/packages/immutadot/src/nav/object.js b/packages/immutadot/src/nav/object.js
index ebb1829c..e4c968b3 100644
--- a/packages/immutadot/src/nav/object.js
+++ b/packages/immutadot/src/nav/object.js
@@ -26,6 +26,6 @@ class PropNav {
}
}
-export function propNav(key) {
- return next => obj => new PropNav(obj, key, next)
+export function propNav(key, next) {
+ return obj => new PropNav(obj, key, next)
}
From 4a8578aabf7ec96b5e3b72592f4f69ff026df416 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Tue, 29 May 2018 22:19:39 +0200
Subject: [PATCH 07/15] :zap: Use nav in set and validate performance
improvement with benchmark
---
packages/immutadot-benchmark/package.json | 2 +-
.../src/updateTodos.spec.js | 26 +++----------------
packages/immutadot/src/core/set.js | 10 +++----
yarn.lock | 6 -----
4 files changed, 9 insertions(+), 35 deletions(-)
diff --git a/packages/immutadot-benchmark/package.json b/packages/immutadot-benchmark/package.json
index 815c80dc..7956a8f7 100644
--- a/packages/immutadot-benchmark/package.json
+++ b/packages/immutadot-benchmark/package.json
@@ -7,7 +7,7 @@
"cross-env": "~5.1.6",
"immer": "~1.3.1",
"immutable": "~3.8.2",
- "immutadot": "~1.0.0",
+ "immutadot": "~2.0.0",
"jest": "~21.2.1",
"lerna": "~2.11.0",
"qim": "~0.0.52"
diff --git a/packages/immutadot-benchmark/src/updateTodos.spec.js b/packages/immutadot-benchmark/src/updateTodos.spec.js
index ae010cb1..212062d4 100644
--- a/packages/immutadot-benchmark/src/updateTodos.spec.js
+++ b/packages/immutadot-benchmark/src/updateTodos.spec.js
@@ -3,7 +3,7 @@ import { $each, $slice, set as qimSet } from 'qim'
import { List, Record } from 'immutable'
-import immer, { setAutoFreeze, setUseProxies } from 'immer'
+import immer, { setAutoFreeze } from 'immer'
import { createBenchmark } from './benchmark'
@@ -70,7 +70,7 @@ function updateTodosList(title, listSize, modifySize, maxTime, maxOperations) {
})
})
- it('immutable w/o conversion', () => {
+ it('immutable', () => {
benchmark('immutable', 'immutable 3.8.2 (w/o conversion to plain JS objects)', () => {
const [start, end] = randomBounds()
immutableState.withMutations(state => {
@@ -79,15 +79,6 @@ function updateTodosList(title, listSize, modifySize, maxTime, maxOperations) {
})
})
- it('immutable w/ conversion', () => {
- benchmark('immutable-toJS', 'immutable 3.8.2 (w/ conversion to plain JS objects)', () => {
- const [start, end] = randomBounds()
- return immutableState.withMutations(state => {
- for (let i = start; i < end; i++) state.setIn([i, 'done'], true)
- }).toJS()
- })
- })
-
it('immer proxy', () => {
benchmark('immer-proxy', 'immer 1.2.0 (proxy implementation w/o autofreeze)', () => {
const [start, end] = randomBounds()
@@ -97,17 +88,6 @@ function updateTodosList(title, listSize, modifySize, maxTime, maxOperations) {
})
})
- it('immer ES5', () => {
- setUseProxies(false)
- benchmark('immer-es5', 'immer 1.2.0 (ES5 implementation w/o autofreeze)', () => {
- const [start, end] = randomBounds()
- return immer(baseState, draft => {
- for (let i = start; i < end; i++) draft[i].done = true
- })
- })
- setUseProxies(true)
- })
-
it('qim', () => {
benchmark('qim', 'qim 0.0.52', () => {
const [start, end] = randomBounds()
@@ -116,7 +96,7 @@ function updateTodosList(title, listSize, modifySize, maxTime, maxOperations) {
})
it('immutad●t', () => {
- benchmark('immutadot', 'immutad●t 1.0.0', () => {
+ benchmark('immutadot', 'immutad●t 2.0.0', () => {
const [start, end] = randomBounds()
return set(baseState, `[${start}:${end}].done`, true)
})
diff --git a/packages/immutadot/src/core/set.js b/packages/immutadot/src/core/set.js
index f74ef9bc..2a1a0f4c 100644
--- a/packages/immutadot/src/core/set.js
+++ b/packages/immutadot/src/core/set.js
@@ -1,10 +1,8 @@
-import { apply } from 'path/apply'
-
-const setOperation = (obj, prop, _, value) => { obj[prop] = value }
+import { nav } from 'nav/nav'
+import { toPath } from '@immutadot/parser'
/**
* Sets the value at path
of obj
.
- * @function
* @memberof core
* @param {*} obj The object to modify.
* @param {string|Array} path The path of the property to set.
@@ -13,6 +11,8 @@ const setOperation = (obj, prop, _, value) => { obj[prop] = value }
* @example set({ nested: { prop: 'old' } }, 'nested.prop', 'new') // => { nested: { prop: 'new' } }
* @since 1.0.0
*/
-const set = apply(setOperation)
+function set(obj, path, value) {
+ return nav(toPath(path))(obj).update(() => value)
+}
export { set }
diff --git a/yarn.lock b/yarn.lock
index 68f8bb21..028d61d9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2557,12 +2557,6 @@ immutable@~3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
-immutadot@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/immutadot/-/immutadot-1.0.0.tgz#9d99bffde37666755aff0b6f9cb7df8e5a4b4231"
- dependencies:
- babel-runtime "^6.26.0"
-
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
From b8e0c6e90a048468fee16b813a96225acd2ea2e8 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Wed, 30 May 2018 12:17:35 +0200
Subject: [PATCH 08/15] :sparkles: Put back negative array index support
---
packages/immutadot/src/nav/array.js | 22 +++++++++++++++-------
packages/immutadot/src/nav/nav.spec.js | 4 ++++
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/packages/immutadot/src/nav/array.js b/packages/immutadot/src/nav/array.js
index 4f45d25c..3c0a74b3 100644
--- a/packages/immutadot/src/nav/array.js
+++ b/packages/immutadot/src/nav/array.js
@@ -6,6 +6,11 @@ class ArrayNav {
this.next = next
}
+ get length() {
+ if (this._length === undefined) this._length = length(this.obj)
+ return this._length
+ }
+
copy() {
if (isNil(this.obj)) return []
return Array.isArray(this.obj) ? [...this.obj] : { ...this.obj }
@@ -15,11 +20,19 @@ class ArrayNav {
class IndexNav extends ArrayNav {
constructor(obj, index, next) {
super(obj, next)
- this.index = index
+ this._index = index
+ }
+
+ get index() {
+ const { _index, length } = this
+ if (_index >= 0) return _index
+ if (-_index > length) return undefined
+ return Math.max(length + _index, 0)
}
get nextValue() {
- return isNil(this.obj) ? this.next(undefined) : this.next(this.obj[this.index])
+ const { index, obj } = this
+ return (isNil(obj) || index === undefined) ? this.next(undefined) : this.next(obj[index])
}
get() {
@@ -43,11 +56,6 @@ class SliceNav extends ArrayNav {
this.bounds = bounds
}
- get length() {
- if (this._length === undefined) this._length = length(this.obj)
- return this._length
- }
-
bound(index) {
if (index < 0) return Math.max(this.length + index, 0)
return index
diff --git a/packages/immutadot/src/nav/nav.spec.js b/packages/immutadot/src/nav/nav.spec.js
index 33125f16..0530966f 100644
--- a/packages/immutadot/src/nav/nav.spec.js
+++ b/packages/immutadot/src/nav/nav.spec.js
@@ -55,6 +55,10 @@ describe('nav.nav', () => {
}).get()).toEqual(['foo', 'bar'])
})
+ it('should get a negative array index', () => {
+ expect(nav(toPath('nested.prop[-3]'))({ nested: { prop: [0, 1, 2, 3, 4] } }).get()).toBe(2)
+ })
+
it('should update a slice', () => immutaTest(
{
nested: {
From 719fd70d8335ca94cbf30289da92439eea383fce Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Wed, 30 May 2018 12:36:35 +0200
Subject: [PATCH 09/15] :white_check_mark: Report apply tests to nav
---
packages/immutadot/src/nav/nav.spec.js | 340 +++++++++++++++++++++++++
1 file changed, 340 insertions(+)
diff --git a/packages/immutadot/src/nav/nav.spec.js b/packages/immutadot/src/nav/nav.spec.js
index 0530966f..ba65e484 100644
--- a/packages/immutadot/src/nav/nav.spec.js
+++ b/packages/immutadot/src/nav/nav.spec.js
@@ -1,9 +1,349 @@
/* eslint-env jest */
+import { get } from 'core'
import { immutaTest } from 'test.utils'
+import { isString } from 'util/lang'
import { nav } from './nav'
import { toPath } from '@immutadot/parser'
describe('nav.nav', () => {
+ function incV(v, i = 1) {
+ let r = Number(v)
+ if (Number.isNaN(r))
+ r = 0
+ return r + i
+ }
+
+ function uncurriedInc(obj, path, ...args) {
+ return nav(toPath(path))(obj).update(v => incV(v, ...args))
+ }
+
+ function curriedInc(path, ...args) {
+ return function(obj) {
+ return uncurriedInc(obj, path, ...args)
+ }
+ }
+
+ function inc(...args) {
+ const [firstArg, ...argsRest] = args
+ if (isString(firstArg)) return curriedInc(...args)
+ return uncurriedInc(firstArg, ...argsRest)
+ }
+
+ it('should inc element at negative position in array', () => {
+ immutaTest({ nested: { prop: [0, 1, 2, 3] } },
+ ['nested.prop.3'],
+ input => {
+ const output = inc(input, 'nested.prop[-1]', 1)
+ expect(output).toEqual({ nested: { prop: [0, 1, 2, 4] } })
+ return output
+ })
+ })
+
+ it.skip('should do nothing for out of bounds negative array index', () => {
+ immutaTest({ nested: { prop: [0, 1, 2, 3] } },
+ [],
+ input => {
+ const output = inc(input, 'nested.prop[-5]', 1)
+ expect(output).toEqual({ nested: { prop: [0, 1, 2, 3] } })
+ return output
+ })
+ })
+
+ it('should inc in an array slice', () => {
+ immutaTest({
+ nested: {
+ prop: [{
+ val: 4,
+ other: {},
+ },
+ { val: -8 },
+ { val: 'a' },
+ {},
+ ],
+ },
+ }, [
+ 'nested.prop.0.val',
+ 'nested.prop.1.val',
+ 'nested.prop.2.val',
+ 'nested.prop.3.val',
+ ], input => {
+ const output = inc(input, 'nested.prop[:].val', 2)
+ expect(output).toEqual({
+ nested: {
+ prop: [{
+ val: 6,
+ other: {},
+ },
+ { val: -6 },
+ { val: 2 },
+ { val: 2 },
+ ],
+ },
+ })
+ return output
+ })
+ immutaTest({
+ nested: {
+ prop: [{ val: 0 },
+ {
+ val: 1,
+ other: {},
+ },
+ { val: 2 },
+ { val: 3 },
+ ],
+ },
+ other: {},
+ }, [
+ 'nested.prop.1.val',
+ 'nested.prop.2.val',
+ ], input => {
+ const output = inc(input, 'nested.prop[1:3].val')
+ expect(output).toEqual({
+ nested: {
+ prop: [{ val: 0 },
+ {
+ val: 2,
+ other: {},
+ },
+ { val: 3 },
+ { val: 3 },
+ ],
+ },
+ other: {},
+ })
+ return output
+ })
+ immutaTest({
+ nested: {
+ prop: [{ val: 0 },
+ {
+ val: 1,
+ other: {},
+ },
+ { val: 2 },
+ { val: 3 },
+ ],
+ },
+ other: {},
+ }, [
+ 'nested.prop.1.val',
+ 'nested.prop.2.val',
+ ], input => {
+ const output = inc(input, 'nested.prop[-3:-1].val')
+ expect(output).toEqual({
+ nested: {
+ prop: [{ val: 0 },
+ {
+ val: 2,
+ other: {},
+ },
+ { val: 3 },
+ { val: 3 },
+ ],
+ },
+ other: {},
+ })
+ return output
+ })
+ immutaTest({
+ nested: {
+ prop: [{ val: 0 },
+ { val: 1 },
+ ],
+ },
+ other: {},
+ }, [
+ 'nested.prop.2',
+ 'nested.prop.3.val',
+ 'nested.prop.4.val',
+ ], input => {
+ const output = inc(input, 'nested.prop[3:5].val', 6)
+ expect(output).toEqual({
+ nested: {
+ prop: [{ val: 0 },
+ { val: 1 },
+ undefined,
+ { val: 6 },
+ { val: 6 },
+ ],
+ },
+ other: {},
+ })
+ return output
+ })
+ })
+
+ it.skip('should avoid unnecessary copies with slice operator', () => {
+ immutaTest({
+ nested: {
+ prop: [{ val: 0 },
+ { val: 1 },
+ ],
+ },
+ other: {},
+ }, [], input => inc(input, 'nested.prop[0:0].val', 6))
+ immutaTest({
+ nested: {
+ prop: [{
+ arr: [{ val: 0 },
+ { val: 1 },
+ ],
+ },
+ { arr: [{ val: 2 }] },
+ ],
+ },
+ other: {},
+ }, [], input => inc(input, 'nested.prop[:].arr[0:0].val', 6))
+ immutaTest({
+ nested: {
+ prop: [{
+ arr: [{ val: 0 },
+ { val: 1 },
+ ],
+ },
+ { arr: [{ val: 2 }] },
+ ],
+ },
+ other: {},
+ }, ['nested.prop.0.arr.1.val'], input => {
+ const output = inc(input, 'nested.prop[:].arr[1:].val', 6)
+ expect(output).toEqual({
+ nested: {
+ prop: [{
+ arr: [{ val: 0 },
+ { val: 7 },
+ ],
+ },
+ { arr: [{ val: 2 }] },
+ ],
+ },
+ other: {},
+ })
+ return output
+ })
+ })
+
+ it('should inc in a list of props', () => {
+ immutaTest({
+ nested: {
+ 'prop1': { val: 0 },
+ 'prop2': { val: 5 },
+ 'prop{3}': { val: 5 },
+ '"prop4"': { val: 3 },
+ 'prop5': { val: 5 },
+ },
+ other: {},
+ }, [
+ 'nested.prop1.val',
+ 'nested.prop2.val',
+ 'nested.prop{3}.val',
+ 'nested."prop4".val',
+ ], input => {
+ const output = inc(input, 'nested.{prop1,prop2,"prop{3}",\'"prop4"\'}.val')
+ expect(output).toEqual({
+ nested: {
+ 'prop1': { val: 1 },
+ 'prop2': { val: 6 },
+ 'prop{3}': { val: 6 },
+ '"prop4"': { val: 4 },
+ 'prop5': { val: 5 },
+ },
+ other: {},
+ })
+ return output
+ })
+ })
+
+ it('should inc in all props', () => {
+ immutaTest({
+ nested: {
+ 'prop1': { val: 0 },
+ 'prop2': { val: 5 },
+ 'prop{3}': { val: 5 },
+ '"prop4"': { val: 3 },
+ },
+ other: {},
+ }, [
+ 'nested.prop1.val',
+ 'nested.prop2.val',
+ 'nested.prop{3}.val',
+ 'nested."prop4".val',
+ ], input => {
+ const output = inc(input, 'nested.{*}.val')
+ expect(output).toEqual({
+ nested: {
+ 'prop1': { val: 1 },
+ 'prop2': { val: 6 },
+ 'prop{3}': { val: 6 },
+ '"prop4"': { val: 4 },
+ },
+ other: {},
+ })
+ return output
+ })
+ })
+
+ it('should throw an explicit error when en empty path is given as parameter', () => {
+ expect(() => inc({}, '')).toThrowError('path should not be empty')
+ })
+
+ it('should support curried first arg', () => {
+ immutaTest({
+ nested: { prop: 5 },
+ other: {},
+ }, ['nested.prop'], (input, [path]) => {
+ const output = inc(path)(input, { shouldBeDiscarded: true })
+ expect(output).toEqual({
+ nested: { prop: 6 },
+ other: {},
+ })
+ return output
+ })
+ })
+
+ it('should initialize unknown props in a list', () => {
+ immutaTest({
+ nested: { prop1: { val: 5 } },
+ other: {},
+ }, [
+ 'nested.prop1.val',
+ 'nested.prop2.val',
+ ], input => {
+ const output = inc(input, 'nested.{prop1,prop2}.val')
+ expect(output).toEqual({
+ nested: {
+ prop1: { val: 6 },
+ prop2: { val: 1 },
+ },
+ other: {},
+ })
+ return output
+ })
+ })
+
+ it.skip('should support lazy function args', () => {
+ immutaTest({
+ nested: {
+ prop1: { val: 3 },
+ prop2: { val: 4 },
+ },
+ other: {},
+ },
+ ['nested.prop1.val'],
+ input => {
+ const output = inc(input, 'nested.prop1.val', get('nested.prop2.val'))
+ expect(output).toEqual({
+ nested: {
+ prop1: { val: 7 },
+ prop2: { val: 4 },
+ },
+ other: {},
+ })
+ return output
+ })
+ })
+
it('should get a nested prop', () => {
expect(nav(toPath('nested.prop'))({ nested: { prop: 'foo' } }).get()).toBe('foo')
})
From 410cec96f45a45d55c337e09df1ec759fc04280d Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Wed, 30 May 2018 16:07:57 +0200
Subject: [PATCH 10/15] :truck: Move each navigator in its own file as
suggested by @frinyvonnick
---
packages/immutadot/src/nav/array.js | 96 -------------------
packages/immutadot/src/nav/arrayNav.js | 18 ++++
packages/immutadot/src/nav/indexNav.js | 35 +++++++
packages/immutadot/src/nav/nav.js | 5 +-
.../src/nav/{object.js => propNav.js} | 0
packages/immutadot/src/nav/sliceNav.js | 47 +++++++++
6 files changed, 103 insertions(+), 98 deletions(-)
delete mode 100644 packages/immutadot/src/nav/array.js
create mode 100644 packages/immutadot/src/nav/arrayNav.js
create mode 100644 packages/immutadot/src/nav/indexNav.js
rename packages/immutadot/src/nav/{object.js => propNav.js} (100%)
create mode 100644 packages/immutadot/src/nav/sliceNav.js
diff --git a/packages/immutadot/src/nav/array.js b/packages/immutadot/src/nav/array.js
deleted file mode 100644
index 3c0a74b3..00000000
--- a/packages/immutadot/src/nav/array.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import { isNil, length } from 'util/lang'
-
-class ArrayNav {
- constructor(obj, next) {
- this.obj = obj
- this.next = next
- }
-
- get length() {
- if (this._length === undefined) this._length = length(this.obj)
- return this._length
- }
-
- copy() {
- if (isNil(this.obj)) return []
- return Array.isArray(this.obj) ? [...this.obj] : { ...this.obj }
- }
-}
-
-class IndexNav extends ArrayNav {
- constructor(obj, index, next) {
- super(obj, next)
- this._index = index
- }
-
- get index() {
- const { _index, length } = this
- if (_index >= 0) return _index
- if (-_index > length) return undefined
- return Math.max(length + _index, 0)
- }
-
- get nextValue() {
- const { index, obj } = this
- return (isNil(obj) || index === undefined) ? this.next(undefined) : this.next(obj[index])
- }
-
- get() {
- return this.nextValue.get()
- }
-
- update(updater) {
- const copy = this.copy()
- copy[this.index] = this.nextValue.update(updater)
- return copy
- }
-}
-
-export function indexNav(index, next) {
- return obj => new IndexNav(obj, index, next)
-}
-
-class SliceNav extends ArrayNav {
- constructor(obj, bounds, next) {
- super(obj, next)
- this.bounds = bounds
- }
-
- bound(index) {
- if (index < 0) return Math.max(this.length + index, 0)
- return index
- }
-
- get start() {
- return this.bound(this.bounds[0])
- }
-
- get end() {
- const [, end] = this.bounds
- return this.bound(end === undefined ? this.length : end)
- }
-
- get range() {
- const { start, end } = this
- return (function*() {
- for (let i = start; i < end; i++) yield i
- }())
- }
-
- get() {
- if (isNil(this.obj)) return []
- return Array.from(this.range, index => this.next(this.obj[index]).get())
- }
-
- update(updater) {
- if (isNil(this.obj)) return []
-
- const copy = this.copy()
- for (const index of this.range) copy[index] = this.next(this.obj[index]).update(updater)
- return copy
- }
-}
-
-export function sliceNav(bounds, next) {
- return obj => new SliceNav(obj, bounds, next)
-}
diff --git a/packages/immutadot/src/nav/arrayNav.js b/packages/immutadot/src/nav/arrayNav.js
new file mode 100644
index 00000000..d7be147d
--- /dev/null
+++ b/packages/immutadot/src/nav/arrayNav.js
@@ -0,0 +1,18 @@
+import { isNil, length } from 'util/lang'
+
+export class ArrayNav {
+ constructor(obj, next) {
+ this.obj = obj
+ this.next = next
+ }
+
+ get length() {
+ if (this._length === undefined) this._length = length(this.obj)
+ return this._length
+ }
+
+ copy() {
+ if (isNil(this.obj)) return []
+ return Array.isArray(this.obj) ? [...this.obj] : { ...this.obj }
+ }
+}
diff --git a/packages/immutadot/src/nav/indexNav.js b/packages/immutadot/src/nav/indexNav.js
new file mode 100644
index 00000000..eeee2ee7
--- /dev/null
+++ b/packages/immutadot/src/nav/indexNav.js
@@ -0,0 +1,35 @@
+import { ArrayNav } from './arrayNav'
+import { isNil } from 'util/lang'
+
+class IndexNav extends ArrayNav {
+ constructor(obj, index, next) {
+ super(obj, next)
+ this._index = index
+ }
+
+ get index() {
+ const { _index, length } = this
+ if (_index >= 0) return _index
+ if (-_index > length) return undefined
+ return Math.max(length + _index, 0)
+ }
+
+ get nextValue() {
+ const { index, obj } = this
+ return (isNil(obj) || index === undefined) ? this.next(undefined) : this.next(obj[index])
+ }
+
+ get() {
+ return this.nextValue.get()
+ }
+
+ update(updater) {
+ const copy = this.copy()
+ copy[this.index] = this.nextValue.update(updater)
+ return copy
+ }
+}
+
+export function indexNav(index, next) {
+ return obj => new IndexNav(obj, index, next)
+}
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index 9e3a5588..d235350f 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -1,6 +1,7 @@
import { index, prop, slice } from '@immutadot/parser/consts'
-import { indexNav, sliceNav } from './array'
-import { propNav } from './object'
+import { indexNav } from './indexNav'
+import { propNav } from './propNav'
+import { sliceNav } from './sliceNav'
export function nav(path) {
return path.reduceRight((next, [type, value]) => toNav(type)(value, next), finalNav)
diff --git a/packages/immutadot/src/nav/object.js b/packages/immutadot/src/nav/propNav.js
similarity index 100%
rename from packages/immutadot/src/nav/object.js
rename to packages/immutadot/src/nav/propNav.js
diff --git a/packages/immutadot/src/nav/sliceNav.js b/packages/immutadot/src/nav/sliceNav.js
new file mode 100644
index 00000000..cf6aa4c4
--- /dev/null
+++ b/packages/immutadot/src/nav/sliceNav.js
@@ -0,0 +1,47 @@
+import { ArrayNav } from './arrayNav'
+import { isNil } from 'util/lang'
+
+class SliceNav extends ArrayNav {
+ constructor(obj, bounds, next) {
+ super(obj, next)
+ this.bounds = bounds
+ }
+
+ bound(index) {
+ if (index < 0) return Math.max(this.length + index, 0)
+ return index
+ }
+
+ get start() {
+ return this.bound(this.bounds[0])
+ }
+
+ get end() {
+ const [, end] = this.bounds
+ return this.bound(end === undefined ? this.length : end)
+ }
+
+ get range() {
+ const { start, end } = this
+ return (function*() {
+ for (let i = start; i < end; i++) yield i
+ }())
+ }
+
+ get() {
+ if (isNil(this.obj)) return []
+ return Array.from(this.range, index => this.next(this.obj[index]).get())
+ }
+
+ update(updater) {
+ if (isNil(this.obj)) return []
+
+ const copy = this.copy()
+ for (const index of this.range) copy[index] = this.next(this.obj[index]).update(updater)
+ return copy
+ }
+}
+
+export function sliceNav(bounds, next) {
+ return obj => new SliceNav(obj, bounds, next)
+}
From c74587b4955f52ab2fe33c3452468bd9b13849b7 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Wed, 30 May 2018 16:17:35 +0200
Subject: [PATCH 11/15] :refactor: Optional currying on set
---
packages/immutadot/src/core/set.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/packages/immutadot/src/core/set.js b/packages/immutadot/src/core/set.js
index 2a1a0f4c..7c30a35b 100644
--- a/packages/immutadot/src/core/set.js
+++ b/packages/immutadot/src/core/set.js
@@ -1,3 +1,4 @@
+import { isString } from 'util/lang'
import { nav } from 'nav/nav'
import { toPath } from '@immutadot/parser'
@@ -15,4 +16,10 @@ function set(obj, path, value) {
return nav(toPath(path))(obj).update(() => value)
}
-export { set }
+const curried = (path, value) => obj => set(obj, path, value)
+
+function optionallyCurried(...args) {
+ return isString(args[0]) ? curried(...args) : set(...args)
+}
+
+export { optionallyCurried as set }
From 481f3d5ecb9d14d0270802cc9fad09066d16a746 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Wed, 30 May 2018 17:20:21 +0200
Subject: [PATCH 12/15] :sparkles: Add all props navigator
---
packages/immutadot/src/nav/allPropsNav.js | 24 ++++++++++++++
packages/immutadot/src/nav/arrayNav.js | 15 ++++-----
packages/immutadot/src/nav/baseNav.js | 6 ++++
packages/immutadot/src/nav/indexNav.js | 16 +++++-----
packages/immutadot/src/nav/nav.js | 6 ++--
packages/immutadot/src/nav/objectNav.js | 9 ++++++
packages/immutadot/src/nav/propNav.js | 23 ++++++-------
packages/immutadot/src/nav/sliceNav.js | 17 ++++++----
packages/immutadot/src/util/lang.js | 23 -------------
packages/immutadot/src/util/lang.spec.js | 39 +----------------------
10 files changed, 78 insertions(+), 100 deletions(-)
create mode 100644 packages/immutadot/src/nav/allPropsNav.js
create mode 100644 packages/immutadot/src/nav/baseNav.js
create mode 100644 packages/immutadot/src/nav/objectNav.js
diff --git a/packages/immutadot/src/nav/allPropsNav.js b/packages/immutadot/src/nav/allPropsNav.js
new file mode 100644
index 00000000..1f0b552a
--- /dev/null
+++ b/packages/immutadot/src/nav/allPropsNav.js
@@ -0,0 +1,24 @@
+import { ObjectNav } from './objectNav'
+import { isNil } from 'util/lang'
+
+class AllPropsNav extends ObjectNav {
+ get() {
+ const { _next, value } = this
+
+ if (isNil(value)) return []
+
+ return Object.keys(value).map(key => _next(value[key]))
+ }
+
+ update(updater) {
+ const { _next, value } = this
+
+ const copy = this.copy()
+ for (const key of Object.keys(copy)) copy[key] = _next(value[key]).update(updater)
+ return copy
+ }
+}
+
+export function allPropsNav(_, next) {
+ return value => new AllPropsNav(value, next)
+}
diff --git a/packages/immutadot/src/nav/arrayNav.js b/packages/immutadot/src/nav/arrayNav.js
index d7be147d..d79299ae 100644
--- a/packages/immutadot/src/nav/arrayNav.js
+++ b/packages/immutadot/src/nav/arrayNav.js
@@ -1,18 +1,15 @@
import { isNil, length } from 'util/lang'
+import { BaseNav } from './baseNav'
-export class ArrayNav {
- constructor(obj, next) {
- this.obj = obj
- this.next = next
- }
-
+export class ArrayNav extends BaseNav {
get length() {
- if (this._length === undefined) this._length = length(this.obj)
+ if (this._length === undefined) this._length = length(this.value)
return this._length
}
copy() {
- if (isNil(this.obj)) return []
- return Array.isArray(this.obj) ? [...this.obj] : { ...this.obj }
+ const { value } = this
+ if (isNil(value)) return []
+ return Array.isArray(value) ? [...value] : { ...value }
}
}
diff --git a/packages/immutadot/src/nav/baseNav.js b/packages/immutadot/src/nav/baseNav.js
new file mode 100644
index 00000000..01bd297d
--- /dev/null
+++ b/packages/immutadot/src/nav/baseNav.js
@@ -0,0 +1,6 @@
+export class BaseNav {
+ constructor(value, next) {
+ this.value = value
+ this._next = next
+ }
+}
diff --git a/packages/immutadot/src/nav/indexNav.js b/packages/immutadot/src/nav/indexNav.js
index eeee2ee7..576245d3 100644
--- a/packages/immutadot/src/nav/indexNav.js
+++ b/packages/immutadot/src/nav/indexNav.js
@@ -2,8 +2,8 @@ import { ArrayNav } from './arrayNav'
import { isNil } from 'util/lang'
class IndexNav extends ArrayNav {
- constructor(obj, index, next) {
- super(obj, next)
+ constructor(value, index, next) {
+ super(value, next)
this._index = index
}
@@ -14,22 +14,22 @@ class IndexNav extends ArrayNav {
return Math.max(length + _index, 0)
}
- get nextValue() {
- const { index, obj } = this
- return (isNil(obj) || index === undefined) ? this.next(undefined) : this.next(obj[index])
+ get next() {
+ const { _next, index, value } = this
+ return (isNil(value) || index === undefined) ? _next(undefined) : _next(value[index])
}
get() {
- return this.nextValue.get()
+ return this.next.get()
}
update(updater) {
const copy = this.copy()
- copy[this.index] = this.nextValue.update(updater)
+ copy[this.index] = this.next.update(updater)
return copy
}
}
export function indexNav(index, next) {
- return obj => new IndexNav(obj, index, next)
+ return value => new IndexNav(value, index, next)
}
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index d235350f..c9460c55 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -1,4 +1,5 @@
-import { index, prop, slice } from '@immutadot/parser/consts'
+import { allProps, index, prop, slice } from '@immutadot/parser/consts'
+import { allPropsNav } from './allPropsNav'
import { indexNav } from './indexNav'
import { propNav } from './propNav'
import { sliceNav } from './sliceNav'
@@ -9,8 +10,9 @@ export function nav(path) {
function toNav(type) {
switch (type) {
- case prop: return propNav
+ case allProps: return allPropsNav
case index: return indexNav
+ case prop: return propNav
case slice: return sliceNav
default: throw TypeError(type)
}
diff --git a/packages/immutadot/src/nav/objectNav.js b/packages/immutadot/src/nav/objectNav.js
new file mode 100644
index 00000000..c2e7464a
--- /dev/null
+++ b/packages/immutadot/src/nav/objectNav.js
@@ -0,0 +1,9 @@
+import { BaseNav } from './baseNav'
+import { isNil } from 'util/lang'
+
+export class ObjectNav extends BaseNav {
+ copy() {
+ const { value } = this
+ return isNil(value) ? {} : { ...value }
+ }
+}
diff --git a/packages/immutadot/src/nav/propNav.js b/packages/immutadot/src/nav/propNav.js
index e4c968b3..44bd52a7 100644
--- a/packages/immutadot/src/nav/propNav.js
+++ b/packages/immutadot/src/nav/propNav.js
@@ -1,31 +1,28 @@
+import { ObjectNav } from './objectNav'
import { isNil } from 'util/lang'
-class PropNav {
- constructor(obj, key, next) {
- this.obj = obj
+class PropNav extends ObjectNav {
+ constructor(value, key, next) {
+ super(value, next)
this.key = key
- this.next = next
}
- get nextValue() {
- return isNil(this.obj) ? this.next(undefined) : this.next(this.obj[this.key])
+ get next() {
+ const { _next, key, value } = this
+ return isNil(value) ? _next(undefined) : _next(value[key])
}
get() {
- return this.nextValue.get()
- }
-
- copy() {
- return isNil(this.obj) ? {} : { ...this.obj }
+ return this.next.get()
}
update(updater) {
const copy = this.copy()
- copy[this.key] = this.nextValue.update(updater)
+ copy[this.key] = this.next.update(updater)
return copy
}
}
export function propNav(key, next) {
- return obj => new PropNav(obj, key, next)
+ return value => new PropNav(value, key, next)
}
diff --git a/packages/immutadot/src/nav/sliceNav.js b/packages/immutadot/src/nav/sliceNav.js
index cf6aa4c4..3ce7b3a1 100644
--- a/packages/immutadot/src/nav/sliceNav.js
+++ b/packages/immutadot/src/nav/sliceNav.js
@@ -2,8 +2,8 @@ import { ArrayNav } from './arrayNav'
import { isNil } from 'util/lang'
class SliceNav extends ArrayNav {
- constructor(obj, bounds, next) {
- super(obj, next)
+ constructor(value, bounds, next) {
+ super(value, next)
this.bounds = bounds
}
@@ -29,19 +29,22 @@ class SliceNav extends ArrayNav {
}
get() {
- if (isNil(this.obj)) return []
- return Array.from(this.range, index => this.next(this.obj[index]).get())
+ const { _next, value, range } = this
+
+ if (isNil(value)) return []
+
+ return Array.from(range, index => _next(value[index]).get())
}
update(updater) {
- if (isNil(this.obj)) return []
+ const { _next, value, range } = this
const copy = this.copy()
- for (const index of this.range) copy[index] = this.next(this.obj[index]).update(updater)
+ for (const index of range) copy[index] = _next(value[index]).update(updater)
return copy
}
}
export function sliceNav(bounds, next) {
- return obj => new SliceNav(obj, bounds, next)
+ return value => new SliceNav(value, bounds, next)
}
diff --git a/packages/immutadot/src/util/lang.js b/packages/immutadot/src/util/lang.js
index e00993bf..fd08a576 100644
--- a/packages/immutadot/src/util/lang.js
+++ b/packages/immutadot/src/util/lang.js
@@ -42,17 +42,6 @@ const isNil = arg => arg === undefined || arg === null
*/
const isString = arg => typeof arg === 'string'
-/**
- * Tests whether arg
is a Symbol.
- * @param {*} arg The value to test
- * @return {boolean} True if arg
is a Symbol, false otherwise
- * @memberof util
- * @private
- * @since 1.0.0
- * @see {@link https://mdn.io/Symbol|Symbol} for more information.
- */
-const isSymbol = arg => typeof arg === 'symbol'
-
/**
* Returns the length of arg
.
* @function
@@ -77,23 +66,11 @@ const length = arg => {
*/
const toString = arg => typeof arg === 'string' ? arg : `${arg}`
-/**
- * Tests whether arg
is a object.
- * @param {*} arg The value to test
- * @return {boolean} True if arg
is an Object
, false otherwise
- * @memberof util
- * @private
- * @since 1.0.0
- */
-const isObject = arg => arg instanceof Object
-
export {
isFunction,
isNaturalInteger,
isNil,
- isObject,
isString,
- isSymbol,
length,
toString,
}
diff --git a/packages/immutadot/src/util/lang.spec.js b/packages/immutadot/src/util/lang.spec.js
index 4d630340..7b6bd31d 100644
--- a/packages/immutadot/src/util/lang.spec.js
+++ b/packages/immutadot/src/util/lang.spec.js
@@ -3,12 +3,11 @@ import {
isFunction,
isNaturalInteger,
isNil,
- isObject,
isString,
- isSymbol,
length,
toString,
} from './lang'
+
describe('Lang utils', () => {
describe('util.isFunction', () => {
it('should return true for functions', () => {
@@ -77,18 +76,6 @@ describe('Lang utils', () => {
expect(isString(null)).toBe(false)
})
})
- describe('util.isSymbol', () => {
- it('should return true for symbols', () => {
- expect(isSymbol(Symbol())).toBe(true)
- expect(isSymbol(Symbol('\uD83C\uDF7A'))).toBe(true)
- expect(isSymbol(Symbol.for('\uD83C\uDF7A'))).toBe(true)
- })
- it('should return false for non symbols', () => {
- expect(isSymbol('\uD83C\uDF7A')).toBe(false)
- expect(isSymbol(666)).toBe(false)
- expect(isSymbol({})).toBe(false)
- })
- })
describe('util.length', () => {
it('should return length of array', () => {
expect(length(Array(666))).toBe(666)
@@ -114,28 +101,4 @@ describe('Lang utils', () => {
expect(toString(666)).toBe('666')
})
})
- describe('util.isObject', () => {
- it('should return true for object', () => {
- expect(isObject({})).toBe(true)
- })
- it('should return true for array', () => {
- expect(isObject([])).toBe(true)
- })
- it('should return true for function', () => {
- const func = () => 1
- expect(isObject(func)).toBe(true)
- })
- it('should return true for string', () => {
- expect(isObject('')).toBe(false)
- })
- it('should return true for number', () => {
- expect(isObject(1)).toBe(false)
- })
- it('should return true for instance of wrappers', () => {
- /* eslint-disable no-new-wrappers */
- expect(isObject(new Number(1))).toBe(true)
- expect(isObject(new String(''))).toBe(true)
- expect(isObject(new Boolean(true))).toBe(true) /* eslint-enable no-new-wrappers */
- })
- })
})
From 53fc488fd18ef81d9a4ee2538c88dffddb9ee59a Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Wed, 30 May 2018 21:36:21 +0200
Subject: [PATCH 13/15] :sparkles: Prop list navigator
---
packages/immutadot/src/nav/allPropsNav.js | 24 ----------------
packages/immutadot/src/nav/nav.js | 8 ++++--
packages/immutadot/src/nav/propsNav.js | 35 +++++++++++++++++++++++
3 files changed, 40 insertions(+), 27 deletions(-)
delete mode 100644 packages/immutadot/src/nav/allPropsNav.js
create mode 100644 packages/immutadot/src/nav/propsNav.js
diff --git a/packages/immutadot/src/nav/allPropsNav.js b/packages/immutadot/src/nav/allPropsNav.js
deleted file mode 100644
index 1f0b552a..00000000
--- a/packages/immutadot/src/nav/allPropsNav.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { ObjectNav } from './objectNav'
-import { isNil } from 'util/lang'
-
-class AllPropsNav extends ObjectNav {
- get() {
- const { _next, value } = this
-
- if (isNil(value)) return []
-
- return Object.keys(value).map(key => _next(value[key]))
- }
-
- update(updater) {
- const { _next, value } = this
-
- const copy = this.copy()
- for (const key of Object.keys(copy)) copy[key] = _next(value[key]).update(updater)
- return copy
- }
-}
-
-export function allPropsNav(_, next) {
- return value => new AllPropsNav(value, next)
-}
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index c9460c55..6e6e2bae 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -1,7 +1,7 @@
-import { allProps, index, prop, slice } from '@immutadot/parser/consts'
-import { allPropsNav } from './allPropsNav'
+import { allProps, index, list, prop, slice } from '@immutadot/parser/consts'
import { indexNav } from './indexNav'
import { propNav } from './propNav'
+import { propsNav } from './propsNav'
import { sliceNav } from './sliceNav'
export function nav(path) {
@@ -10,7 +10,9 @@ export function nav(path) {
function toNav(type) {
switch (type) {
- case allProps: return allPropsNav
+ case allProps:
+ case list:
+ return propsNav
case index: return indexNav
case prop: return propNav
case slice: return sliceNav
diff --git a/packages/immutadot/src/nav/propsNav.js b/packages/immutadot/src/nav/propsNav.js
new file mode 100644
index 00000000..6272f7bb
--- /dev/null
+++ b/packages/immutadot/src/nav/propsNav.js
@@ -0,0 +1,35 @@
+import { ObjectNav } from './objectNav'
+import { isNil } from 'util/lang'
+
+class PropsNav extends ObjectNav {
+ constructor(value, keys, next) {
+ super(value, next)
+ this._keys = keys
+ }
+
+ get keys() {
+ const { _keys, value } = this
+
+ if (_keys !== undefined) return _keys
+
+ return isNil(value) ? [] : Object.keys(value)
+ }
+
+ get() {
+ const { _next, keys, value } = this
+
+ return keys.map(key => _next(value[key]))
+ }
+
+ update(updater) {
+ const { _next, keys, value } = this
+
+ const copy = this.copy()
+ for (const key of keys) copy[key] = _next(value[key]).update(updater)
+ return copy
+ }
+}
+
+export function propsNav(keys, next) {
+ return value => new PropsNav(value, keys, next)
+}
From 3fa0bd203d8a09722e75fd355b611d27ee72ec85 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Wed, 30 May 2018 22:16:37 +0200
Subject: [PATCH 14/15] :recycle: Put TypeError for empty path in nav
---
packages/immutadot/src/nav/nav.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/immutadot/src/nav/nav.js b/packages/immutadot/src/nav/nav.js
index 6e6e2bae..8bac4154 100644
--- a/packages/immutadot/src/nav/nav.js
+++ b/packages/immutadot/src/nav/nav.js
@@ -5,6 +5,8 @@ import { propsNav } from './propsNav'
import { sliceNav } from './sliceNav'
export function nav(path) {
+ if (path.length === 0) throw new TypeError('path should not be empty')
+
return path.reduceRight((next, [type, value]) => toNav(type)(value, next), finalNav)
}
From 77f98573ff51f046de86c936acab8cca30d15726 Mon Sep 17 00:00:00 2001
From: nlepage <19571875+nlepage@users.noreply.github.com>
Date: Wed, 6 Jun 2018 19:24:38 +0200
Subject: [PATCH 15/15] :ok_hand: @frinyvonnick's review
---
packages/immutadot/src/nav/arrayNav.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/packages/immutadot/src/nav/arrayNav.js b/packages/immutadot/src/nav/arrayNav.js
index d79299ae..2e7d7224 100644
--- a/packages/immutadot/src/nav/arrayNav.js
+++ b/packages/immutadot/src/nav/arrayNav.js
@@ -3,8 +3,7 @@ import { BaseNav } from './baseNav'
export class ArrayNav extends BaseNav {
get length() {
- if (this._length === undefined) this._length = length(this.value)
- return this._length
+ return length(this.value)
}
copy() {