From dc17a715240ee34ed4aaac6c68f3571c5db70aeb Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Thu, 2 May 2019 16:30:41 -0700 Subject: [PATCH 1/5] Added @microstates/lens as a dependency --- package.json | 1 + rollup.config.js | 3 +- src/cached-property.js | 13 ------- src/lens.js | 83 ------------------------------------------ src/meta.js | 2 +- src/microstates.js | 3 +- src/pathmap.js | 3 +- src/storage.js | 2 +- src/tree.js | 27 -------------- src/types/array.js | 3 +- src/types/object.js | 2 +- tests/lens.test.js | 25 ------------- yarn.lock | 9 ++++- 13 files changed, 17 insertions(+), 159 deletions(-) delete mode 100644 src/cached-property.js delete mode 100644 src/lens.js delete mode 100644 src/tree.js delete mode 100644 tests/lens.test.js diff --git a/package.json b/package.json index 13b58eee..1ed258c3 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "rxjs": "^6.2.1" }, "dependencies": { + "@microstates/lens": "1.0.0-beta.1", "funcadelic": "^0.5.0", "symbol-observable": "^1.2.0" }, diff --git a/rollup.config.js b/rollup.config.js index 23dced82..419c63a7 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,7 +7,8 @@ const replace = require('rollup-plugin-replace'); const external = [ "funcadelic", - "symbol-observable" + "symbol-observable", + "@microstates/lens" ]; const babelPlugin = babel({ diff --git a/src/cached-property.js b/src/cached-property.js deleted file mode 100644 index 711c32a4..00000000 --- a/src/cached-property.js +++ /dev/null @@ -1,13 +0,0 @@ -export default function CachedProperty(key, reify) { - let enumerable = true; - let configurable = true; - return { - enumerable, - configurable, - get() { - let value = reify(this); - Object.defineProperty(this, key, { enumerable, value }); - return value; - } - }; -} diff --git a/src/lens.js b/src/lens.js deleted file mode 100644 index e75e8afe..00000000 --- a/src/lens.js +++ /dev/null @@ -1,83 +0,0 @@ -import { Functor, map, Semigroup } from 'funcadelic'; - -import { childAt } from './tree'; - -class Box { - static get of() { - return (...args) => new this(...args); - } - - static unwrap(box) { - return box.value; - } - - constructor(value) { - this.value = value; - } -} - -const { unwrap } = Box; - -class Id extends Box {} - -class Const extends Box {} - -Functor.instance(Id, { - map(fn, id) { - return Id.of(fn(id.value)); - } -}); - -Functor.instance(Const, { - map(fn, constant) { - return constant; - } -}); - -export function compose(f, g) { - return (...x) => f(g(...x)); -} - -export function view(lens, context) { - let get = compose(unwrap, lens(Const.of)); - return get(context); -} - -export function over(lens, fn, context) { - let update = compose(unwrap, lens(compose(Id.of, fn))); - return update(context); -} - -export function set(lens, value, context) { - return over(lens, () => value, context); -} - -export function Lens(get, set) { - return f => context => { - return map(value => set(value, context), f(get(context))); - }; -} - -export const transparent = Lens(x => x, y => y); - -export function At(property, container) { - let get = context => context != null ? childAt(property, context) : undefined; - let set = (part, whole) => { - let context = whole == null ? (Array.isArray(container) ? [] : {}) : whole; - if (part === context[property]) { - return context; - } else if (Array.isArray(context)) { - let clone = context.slice(); - clone[Number(property)] = part; - return clone; - } else { - return Semigroup.for(Object).append(context, {[property]: part}); - } - }; - - return Lens(get, set); -} - -export function Path(path) { - return path.reduce((lens, key) => compose(lens, At(key)), transparent); -} diff --git a/src/meta.js b/src/meta.js index 805d0f50..87f630e9 100644 --- a/src/meta.js +++ b/src/meta.js @@ -1,4 +1,4 @@ -import { At, compose, transparent, over, view } from './lens'; +import { At, compose, transparent, over, view } from '@microstates/lens'; export class Meta { static symbol = Symbol('Meta'); diff --git a/src/microstates.js b/src/microstates.js index 92013f5c..09634ee2 100644 --- a/src/microstates.js +++ b/src/microstates.js @@ -1,10 +1,9 @@ import { append, stable, map } from 'funcadelic'; -import { set } from './lens'; +import { set, CachedProperty } from '@microstates/lens'; import { Meta, mount, metaOf, valueOf, sourceOf } from './meta'; import { methodsOf } from './reflection'; import dsl from './dsl'; import Any from './types/any'; -import CachedProperty from './cached-property'; import Observable from './observable'; export function create(InputType = Any, value) { diff --git a/src/pathmap.js b/src/pathmap.js index 5941c083..191a4056 100644 --- a/src/pathmap.js +++ b/src/pathmap.js @@ -1,8 +1,7 @@ +import { defineChildren, view, Path } from '@microstates/lens'; import { methodsOf } from './reflection'; import { create } from './microstates'; -import { view, Path } from './lens'; import { valueOf, Meta } from './meta'; -import { defineChildren } from './tree'; import { stable } from 'funcadelic'; import Storage from './storage'; diff --git a/src/storage.js b/src/storage.js index 980b152f..19b8b406 100644 --- a/src/storage.js +++ b/src/storage.js @@ -1,4 +1,4 @@ -import { view, set, Path } from './lens'; +import { view, set, Path } from '@microstates/lens'; export default class Storage { constructor(value, observe = x => x) { diff --git a/src/tree.js b/src/tree.js deleted file mode 100644 index 7b630cff..00000000 --- a/src/tree.js +++ /dev/null @@ -1,27 +0,0 @@ -import { type } from 'funcadelic'; - -import CachedProperty from './cached-property'; - -export const Tree = type(class { - static name = 'Tree'; - - childAt(key, parent) { - if (parent[Tree.symbol]) { - return this(parent).childAt(key, parent); - } else { - return parent[key]; - } - } - - defineChildren(fn, parent) { - if (parent[Tree.symbol]) { - return this(parent).defineChildren(fn, parent); - } else { - for (let property of Object.keys(parent)) { - Object.defineProperty(parent, property, CachedProperty(property, () => fn(property, parent))); - } - } - } -}); - -export const { childAt, defineChildren } = Tree.prototype; diff --git a/src/types/array.js b/src/types/array.js index f31fbfb9..857a4c5c 100644 --- a/src/types/array.js +++ b/src/types/array.js @@ -1,8 +1,7 @@ -import { At, set } from '../lens'; +import { At, set, Tree, childAt } from '@microstates/lens'; import { mount, valueOf } from '../meta'; import { create } from '../microstates'; import parameterized from '../parameterized'; -import { Tree, childAt } from '../tree'; export default parameterized(T => class ArrayType { static T = T; diff --git a/src/types/object.js b/src/types/object.js index f7518c00..d4a58265 100644 --- a/src/types/object.js +++ b/src/types/object.js @@ -1,9 +1,9 @@ import { append, filter, map } from 'funcadelic'; +import { Tree, childAt } from '@microstates/lens'; import { reduce, query } from '../query'; import parameterized from '../parameterized'; import { valueOf, mount } from '../meta'; import { create } from '../microstates'; -import { Tree, childAt } from '../tree'; export default parameterized(T => class ObjectType { diff --git a/tests/lens.test.js b/tests/lens.test.js deleted file mode 100644 index eddfee2a..00000000 --- a/tests/lens.test.js +++ /dev/null @@ -1,25 +0,0 @@ -/* global describe, it, beforeEach */ -import expect from 'expect'; -import { compose, view, set, At } from '../src/lens'; - -describe('At', function() { - let lens; - beforeEach(function() { - lens = compose(At(0, []), At("hello")); - }); - - it('instantiates objects of the correct type at each path', function() { - expect(set(lens, "world", undefined)).toEqual([{hello: 'world'}]); - }); - - it('set-get: view retrievs what set put in', function() { - let cookie = {}; - let object = set(lens, cookie, undefined); - expect(view(lens, object)).toBe(cookie); - }); - - it('get-set: If you set focus to the same value it has, the whole does not change', function() { - let object = set(lens, "world", undefined); - expect(set(lens, "world", object)).toBe(object); - }); -}); diff --git a/yarn.lock b/yarn.lock index 23d552be..fbc679fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -662,6 +662,13 @@ "@types/istanbul-lib-coverage" "^1.1.0" "@types/yargs" "^12.0.9" +"@microstates/lens@1.0.0-beta.1": + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/@microstates/lens/-/lens-1.0.0-beta.1.tgz#a94c2d7d0ac409840b70184a8372f9c9c6142655" + integrity sha512-qavPeVVnnvqoi6fdWZ7bIfL2eS3+sKAP0qMr/8/tqdYA2Pws6eF2+W9rChYWJa6NUh43tGx/kIAbYFBn3Ztm8A== + dependencies: + funcadelic "^0.5.7" + "@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" @@ -1814,7 +1821,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -funcadelic@^0.5.0: +funcadelic@^0.5.0, funcadelic@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/funcadelic/-/funcadelic-0.5.7.tgz#e76f6a9028985531924c1159dc1c930f5b00acb2" integrity sha512-kwKSJVAd2FNFmBgku81FC6VJCQdgcT/gtwG9z7H7FxL4NlDKsbdGqLwtjbDlYgR77t+NuT8phBLkmLSKsg1J5w== From 3992b692882d723ceab0ddb6561407628409bcb4 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Sat, 11 May 2019 09:06:33 -0400 Subject: [PATCH 2/5] Revert "Added @microstates/lens as a dependency" This reverts commit dc17a715240ee34ed4aaac6c68f3571c5db70aeb. --- package.json | 1 - rollup.config.js | 3 +- src/cached-property.js | 13 +++++++ src/lens.js | 83 ++++++++++++++++++++++++++++++++++++++++++ src/meta.js | 2 +- src/microstates.js | 3 +- src/pathmap.js | 3 +- src/storage.js | 2 +- src/tree.js | 27 ++++++++++++++ src/types/array.js | 3 +- src/types/object.js | 2 +- tests/lens.test.js | 25 +++++++++++++ yarn.lock | 9 +---- 13 files changed, 159 insertions(+), 17 deletions(-) create mode 100644 src/cached-property.js create mode 100644 src/lens.js create mode 100644 src/tree.js create mode 100644 tests/lens.test.js diff --git a/package.json b/package.json index 1ed258c3..13b58eee 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "rxjs": "^6.2.1" }, "dependencies": { - "@microstates/lens": "1.0.0-beta.1", "funcadelic": "^0.5.0", "symbol-observable": "^1.2.0" }, diff --git a/rollup.config.js b/rollup.config.js index 419c63a7..23dced82 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,8 +7,7 @@ const replace = require('rollup-plugin-replace'); const external = [ "funcadelic", - "symbol-observable", - "@microstates/lens" + "symbol-observable" ]; const babelPlugin = babel({ diff --git a/src/cached-property.js b/src/cached-property.js new file mode 100644 index 00000000..711c32a4 --- /dev/null +++ b/src/cached-property.js @@ -0,0 +1,13 @@ +export default function CachedProperty(key, reify) { + let enumerable = true; + let configurable = true; + return { + enumerable, + configurable, + get() { + let value = reify(this); + Object.defineProperty(this, key, { enumerable, value }); + return value; + } + }; +} diff --git a/src/lens.js b/src/lens.js new file mode 100644 index 00000000..e75e8afe --- /dev/null +++ b/src/lens.js @@ -0,0 +1,83 @@ +import { Functor, map, Semigroup } from 'funcadelic'; + +import { childAt } from './tree'; + +class Box { + static get of() { + return (...args) => new this(...args); + } + + static unwrap(box) { + return box.value; + } + + constructor(value) { + this.value = value; + } +} + +const { unwrap } = Box; + +class Id extends Box {} + +class Const extends Box {} + +Functor.instance(Id, { + map(fn, id) { + return Id.of(fn(id.value)); + } +}); + +Functor.instance(Const, { + map(fn, constant) { + return constant; + } +}); + +export function compose(f, g) { + return (...x) => f(g(...x)); +} + +export function view(lens, context) { + let get = compose(unwrap, lens(Const.of)); + return get(context); +} + +export function over(lens, fn, context) { + let update = compose(unwrap, lens(compose(Id.of, fn))); + return update(context); +} + +export function set(lens, value, context) { + return over(lens, () => value, context); +} + +export function Lens(get, set) { + return f => context => { + return map(value => set(value, context), f(get(context))); + }; +} + +export const transparent = Lens(x => x, y => y); + +export function At(property, container) { + let get = context => context != null ? childAt(property, context) : undefined; + let set = (part, whole) => { + let context = whole == null ? (Array.isArray(container) ? [] : {}) : whole; + if (part === context[property]) { + return context; + } else if (Array.isArray(context)) { + let clone = context.slice(); + clone[Number(property)] = part; + return clone; + } else { + return Semigroup.for(Object).append(context, {[property]: part}); + } + }; + + return Lens(get, set); +} + +export function Path(path) { + return path.reduce((lens, key) => compose(lens, At(key)), transparent); +} diff --git a/src/meta.js b/src/meta.js index 87f630e9..805d0f50 100644 --- a/src/meta.js +++ b/src/meta.js @@ -1,4 +1,4 @@ -import { At, compose, transparent, over, view } from '@microstates/lens'; +import { At, compose, transparent, over, view } from './lens'; export class Meta { static symbol = Symbol('Meta'); diff --git a/src/microstates.js b/src/microstates.js index 09634ee2..92013f5c 100644 --- a/src/microstates.js +++ b/src/microstates.js @@ -1,9 +1,10 @@ import { append, stable, map } from 'funcadelic'; -import { set, CachedProperty } from '@microstates/lens'; +import { set } from './lens'; import { Meta, mount, metaOf, valueOf, sourceOf } from './meta'; import { methodsOf } from './reflection'; import dsl from './dsl'; import Any from './types/any'; +import CachedProperty from './cached-property'; import Observable from './observable'; export function create(InputType = Any, value) { diff --git a/src/pathmap.js b/src/pathmap.js index 191a4056..5941c083 100644 --- a/src/pathmap.js +++ b/src/pathmap.js @@ -1,7 +1,8 @@ -import { defineChildren, view, Path } from '@microstates/lens'; import { methodsOf } from './reflection'; import { create } from './microstates'; +import { view, Path } from './lens'; import { valueOf, Meta } from './meta'; +import { defineChildren } from './tree'; import { stable } from 'funcadelic'; import Storage from './storage'; diff --git a/src/storage.js b/src/storage.js index 19b8b406..980b152f 100644 --- a/src/storage.js +++ b/src/storage.js @@ -1,4 +1,4 @@ -import { view, set, Path } from '@microstates/lens'; +import { view, set, Path } from './lens'; export default class Storage { constructor(value, observe = x => x) { diff --git a/src/tree.js b/src/tree.js new file mode 100644 index 00000000..7b630cff --- /dev/null +++ b/src/tree.js @@ -0,0 +1,27 @@ +import { type } from 'funcadelic'; + +import CachedProperty from './cached-property'; + +export const Tree = type(class { + static name = 'Tree'; + + childAt(key, parent) { + if (parent[Tree.symbol]) { + return this(parent).childAt(key, parent); + } else { + return parent[key]; + } + } + + defineChildren(fn, parent) { + if (parent[Tree.symbol]) { + return this(parent).defineChildren(fn, parent); + } else { + for (let property of Object.keys(parent)) { + Object.defineProperty(parent, property, CachedProperty(property, () => fn(property, parent))); + } + } + } +}); + +export const { childAt, defineChildren } = Tree.prototype; diff --git a/src/types/array.js b/src/types/array.js index 857a4c5c..f31fbfb9 100644 --- a/src/types/array.js +++ b/src/types/array.js @@ -1,7 +1,8 @@ -import { At, set, Tree, childAt } from '@microstates/lens'; +import { At, set } from '../lens'; import { mount, valueOf } from '../meta'; import { create } from '../microstates'; import parameterized from '../parameterized'; +import { Tree, childAt } from '../tree'; export default parameterized(T => class ArrayType { static T = T; diff --git a/src/types/object.js b/src/types/object.js index d4a58265..f7518c00 100644 --- a/src/types/object.js +++ b/src/types/object.js @@ -1,9 +1,9 @@ import { append, filter, map } from 'funcadelic'; -import { Tree, childAt } from '@microstates/lens'; import { reduce, query } from '../query'; import parameterized from '../parameterized'; import { valueOf, mount } from '../meta'; import { create } from '../microstates'; +import { Tree, childAt } from '../tree'; export default parameterized(T => class ObjectType { diff --git a/tests/lens.test.js b/tests/lens.test.js new file mode 100644 index 00000000..eddfee2a --- /dev/null +++ b/tests/lens.test.js @@ -0,0 +1,25 @@ +/* global describe, it, beforeEach */ +import expect from 'expect'; +import { compose, view, set, At } from '../src/lens'; + +describe('At', function() { + let lens; + beforeEach(function() { + lens = compose(At(0, []), At("hello")); + }); + + it('instantiates objects of the correct type at each path', function() { + expect(set(lens, "world", undefined)).toEqual([{hello: 'world'}]); + }); + + it('set-get: view retrievs what set put in', function() { + let cookie = {}; + let object = set(lens, cookie, undefined); + expect(view(lens, object)).toBe(cookie); + }); + + it('get-set: If you set focus to the same value it has, the whole does not change', function() { + let object = set(lens, "world", undefined); + expect(set(lens, "world", object)).toBe(object); + }); +}); diff --git a/yarn.lock b/yarn.lock index fbc679fd..23d552be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -662,13 +662,6 @@ "@types/istanbul-lib-coverage" "^1.1.0" "@types/yargs" "^12.0.9" -"@microstates/lens@1.0.0-beta.1": - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/@microstates/lens/-/lens-1.0.0-beta.1.tgz#a94c2d7d0ac409840b70184a8372f9c9c6142655" - integrity sha512-qavPeVVnnvqoi6fdWZ7bIfL2eS3+sKAP0qMr/8/tqdYA2Pws6eF2+W9rChYWJa6NUh43tGx/kIAbYFBn3Ztm8A== - dependencies: - funcadelic "^0.5.7" - "@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" @@ -1821,7 +1814,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -funcadelic@^0.5.0, funcadelic@^0.5.7: +funcadelic@^0.5.0: version "0.5.7" resolved "https://registry.yarnpkg.com/funcadelic/-/funcadelic-0.5.7.tgz#e76f6a9028985531924c1159dc1c930f5b00acb2" integrity sha512-kwKSJVAd2FNFmBgku81FC6VJCQdgcT/gtwG9z7H7FxL4NlDKsbdGqLwtjbDlYgR77t+NuT8phBLkmLSKsg1J5w== From a0961da7186c817684ff82bf0556a0b9950caed0 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Sat, 11 May 2019 09:08:19 -0400 Subject: [PATCH 3/5] Add @microstates/lens@1.0.0-beta.2 --- package.json | 1 + yarn.lock | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 13b58eee..8f826ec0 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "rxjs": "^6.2.1" }, "dependencies": { + "@microstates/lens": "1.0.0-beta.2", "funcadelic": "^0.5.0", "symbol-observable": "^1.2.0" }, diff --git a/yarn.lock b/yarn.lock index 23d552be..f0896c14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -662,6 +662,13 @@ "@types/istanbul-lib-coverage" "^1.1.0" "@types/yargs" "^12.0.9" +"@microstates/lens@1.0.0-beta.2": + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@microstates/lens/-/lens-1.0.0-beta.2.tgz#b43badbe038a90f95f13f4ae57a34fddd380c356" + integrity sha512-WrPBgPut3h8c7/Yl1tIaA8Fw4TV80mx3EXJGvumBhx15GE+z31HB+31loz9+I4dbGq6xC4Xi7rhMXdiBqRK6Ug== + dependencies: + funcadelic "^0.5.7" + "@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" @@ -1814,7 +1821,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -funcadelic@^0.5.0: +funcadelic@^0.5.0, funcadelic@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/funcadelic/-/funcadelic-0.5.7.tgz#e76f6a9028985531924c1159dc1c930f5b00acb2" integrity sha512-kwKSJVAd2FNFmBgku81FC6VJCQdgcT/gtwG9z7H7FxL4NlDKsbdGqLwtjbDlYgR77t+NuT8phBLkmLSKsg1J5w== From 44d1c9ac6e29b7416bcfb7dacef931473c39c2f0 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Sat, 11 May 2019 09:19:23 -0400 Subject: [PATCH 4/5] Refactor to use lens from @microstates/lens --- rollup.config.js | 3 +- src/lens.js | 83 --------------------------------------------- src/meta.js | 2 +- src/microstates.js | 2 +- src/pathmap.js | 2 +- src/storage.js | 2 +- src/tree.js | 10 +----- src/types/array.js | 14 ++++---- src/types/object.js | 16 +++++---- tests/lens.test.js | 25 -------------- 10 files changed, 25 insertions(+), 134 deletions(-) delete mode 100644 src/lens.js delete mode 100644 tests/lens.test.js diff --git a/rollup.config.js b/rollup.config.js index 23dced82..419c63a7 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,7 +7,8 @@ const replace = require('rollup-plugin-replace'); const external = [ "funcadelic", - "symbol-observable" + "symbol-observable", + "@microstates/lens" ]; const babelPlugin = babel({ diff --git a/src/lens.js b/src/lens.js deleted file mode 100644 index e75e8afe..00000000 --- a/src/lens.js +++ /dev/null @@ -1,83 +0,0 @@ -import { Functor, map, Semigroup } from 'funcadelic'; - -import { childAt } from './tree'; - -class Box { - static get of() { - return (...args) => new this(...args); - } - - static unwrap(box) { - return box.value; - } - - constructor(value) { - this.value = value; - } -} - -const { unwrap } = Box; - -class Id extends Box {} - -class Const extends Box {} - -Functor.instance(Id, { - map(fn, id) { - return Id.of(fn(id.value)); - } -}); - -Functor.instance(Const, { - map(fn, constant) { - return constant; - } -}); - -export function compose(f, g) { - return (...x) => f(g(...x)); -} - -export function view(lens, context) { - let get = compose(unwrap, lens(Const.of)); - return get(context); -} - -export function over(lens, fn, context) { - let update = compose(unwrap, lens(compose(Id.of, fn))); - return update(context); -} - -export function set(lens, value, context) { - return over(lens, () => value, context); -} - -export function Lens(get, set) { - return f => context => { - return map(value => set(value, context), f(get(context))); - }; -} - -export const transparent = Lens(x => x, y => y); - -export function At(property, container) { - let get = context => context != null ? childAt(property, context) : undefined; - let set = (part, whole) => { - let context = whole == null ? (Array.isArray(container) ? [] : {}) : whole; - if (part === context[property]) { - return context; - } else if (Array.isArray(context)) { - let clone = context.slice(); - clone[Number(property)] = part; - return clone; - } else { - return Semigroup.for(Object).append(context, {[property]: part}); - } - }; - - return Lens(get, set); -} - -export function Path(path) { - return path.reduce((lens, key) => compose(lens, At(key)), transparent); -} diff --git a/src/meta.js b/src/meta.js index 805d0f50..87f630e9 100644 --- a/src/meta.js +++ b/src/meta.js @@ -1,4 +1,4 @@ -import { At, compose, transparent, over, view } from './lens'; +import { At, compose, transparent, over, view } from '@microstates/lens'; export class Meta { static symbol = Symbol('Meta'); diff --git a/src/microstates.js b/src/microstates.js index 92013f5c..dd2e310a 100644 --- a/src/microstates.js +++ b/src/microstates.js @@ -1,5 +1,5 @@ import { append, stable, map } from 'funcadelic'; -import { set } from './lens'; +import { set } from '@microstates/lens'; import { Meta, mount, metaOf, valueOf, sourceOf } from './meta'; import { methodsOf } from './reflection'; import dsl from './dsl'; diff --git a/src/pathmap.js b/src/pathmap.js index 5941c083..dc54e98f 100644 --- a/src/pathmap.js +++ b/src/pathmap.js @@ -1,6 +1,6 @@ +import { view, Path } from '@microstates/lens'; import { methodsOf } from './reflection'; import { create } from './microstates'; -import { view, Path } from './lens'; import { valueOf, Meta } from './meta'; import { defineChildren } from './tree'; import { stable } from 'funcadelic'; diff --git a/src/storage.js b/src/storage.js index 980b152f..19b8b406 100644 --- a/src/storage.js +++ b/src/storage.js @@ -1,4 +1,4 @@ -import { view, set, Path } from './lens'; +import { view, set, Path } from '@microstates/lens'; export default class Storage { constructor(value, observe = x => x) { diff --git a/src/tree.js b/src/tree.js index 7b630cff..e3126fa9 100644 --- a/src/tree.js +++ b/src/tree.js @@ -5,14 +5,6 @@ import CachedProperty from './cached-property'; export const Tree = type(class { static name = 'Tree'; - childAt(key, parent) { - if (parent[Tree.symbol]) { - return this(parent).childAt(key, parent); - } else { - return parent[key]; - } - } - defineChildren(fn, parent) { if (parent[Tree.symbol]) { return this(parent).defineChildren(fn, parent); @@ -24,4 +16,4 @@ export const Tree = type(class { } }); -export const { childAt, defineChildren } = Tree.prototype; +export const { defineChildren } = Tree.prototype; diff --git a/src/types/array.js b/src/types/array.js index f31fbfb9..0d5415af 100644 --- a/src/types/array.js +++ b/src/types/array.js @@ -1,8 +1,8 @@ -import { At, set } from '../lens'; +import { at, At, set, Context } from '@microstates/lens' import { mount, valueOf } from '../meta'; import { create } from '../microstates'; import parameterized from '../parameterized'; -import { Tree, childAt } from '../tree'; +import { Tree } from '../tree'; export default parameterized(T => class ArrayType { static T = T; @@ -88,7 +88,7 @@ export default parameterized(T => class ArrayType { get done() { return next.done; }, get value() { if (!next.done) { - return childAt(index, array); + return at(index, array); } else { return undefined; } @@ -100,16 +100,18 @@ export default parameterized(T => class ArrayType { static initialize() { - Tree.instance(this, { - childAt(key, array) { + Context.instance(this, { + at(key, array) { if (typeof key === 'number') { let value = valueOf(array)[key]; return mount(array, create(T, value), key); } else { return array[key]; } - }, + } + }) + Tree.instance(this, { defineChildren(fn, array) { let generate = array[Symbol.iterator]; return Object.defineProperty(array, Symbol.iterator, { diff --git a/src/types/object.js b/src/types/object.js index f7518c00..f51f9ded 100644 --- a/src/types/object.js +++ b/src/types/object.js @@ -1,10 +1,10 @@ import { append, filter, map } from 'funcadelic'; +import { at, Context } from '@microstates/lens'; import { reduce, query } from '../query'; import parameterized from '../parameterized'; import { valueOf, mount } from '../meta'; import { create } from '../microstates'; -import { Tree, childAt } from '../tree'; - +import { Tree } from '../tree'; export default parameterized(T => class ObjectType { static T = T; @@ -59,7 +59,7 @@ export default parameterized(T => class ObjectType { get done() { return next.done; }, get value() { if (!next.done) { - return new Entry(next.value, childAt(next.value, object)); + return new Entry(next.value, at(next.value, object)); } else { return undefined; } @@ -70,15 +70,19 @@ export default parameterized(T => class ObjectType { } static initialize() { - Tree.instance(this, { - childAt(key, object) { + + Context.instance(this, { + at(key, object) { if (typeof key !== 'string') { return object[key]; } else { let value = valueOf(object)[key]; return mount(object, create(T, value), key); } - }, + } + }) + + Tree.instance(this, { defineChildren(fn, object) { let generate = object[Symbol.iterator]; return Object.defineProperty(object, Symbol.iterator, { diff --git a/tests/lens.test.js b/tests/lens.test.js deleted file mode 100644 index eddfee2a..00000000 --- a/tests/lens.test.js +++ /dev/null @@ -1,25 +0,0 @@ -/* global describe, it, beforeEach */ -import expect from 'expect'; -import { compose, view, set, At } from '../src/lens'; - -describe('At', function() { - let lens; - beforeEach(function() { - lens = compose(At(0, []), At("hello")); - }); - - it('instantiates objects of the correct type at each path', function() { - expect(set(lens, "world", undefined)).toEqual([{hello: 'world'}]); - }); - - it('set-get: view retrievs what set put in', function() { - let cookie = {}; - let object = set(lens, cookie, undefined); - expect(view(lens, object)).toBe(cookie); - }); - - it('get-set: If you set focus to the same value it has, the whole does not change', function() { - let object = set(lens, "world", undefined); - expect(set(lens, "world", object)).toBe(object); - }); -}); From 8f70c54f301160177bbe6820815a6fd7ea116773 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Sat, 11 May 2019 09:21:37 -0400 Subject: [PATCH 5/5] Fixed lint errors --- src/types/array.js | 4 ++-- src/types/object.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/types/array.js b/src/types/array.js index 0d5415af..ad368d05 100644 --- a/src/types/array.js +++ b/src/types/array.js @@ -1,4 +1,4 @@ -import { at, At, set, Context } from '@microstates/lens' +import { at, At, set, Context } from '@microstates/lens'; import { mount, valueOf } from '../meta'; import { create } from '../microstates'; import parameterized from '../parameterized'; @@ -109,7 +109,7 @@ export default parameterized(T => class ArrayType { return array[key]; } } - }) + }); Tree.instance(this, { defineChildren(fn, array) { diff --git a/src/types/object.js b/src/types/object.js index f51f9ded..9e2df766 100644 --- a/src/types/object.js +++ b/src/types/object.js @@ -80,7 +80,7 @@ export default parameterized(T => class ObjectType { return mount(object, create(T, value), key); } } - }) + }); Tree.instance(this, { defineChildren(fn, object) {