From 3e967a891381f145b36b94cd5448b8a77ca29c97 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sat, 7 Aug 2021 08:58:17 +0200 Subject: [PATCH 01/15] Try simplifying a few things. Attributes almost working again. --- dev.hxml | 4 +- haxe_libraries/coconut.data.hxml | 7 +- haxe_libraries/coconut.react-core.hxml | 6 +- haxe_libraries/coconut.react-dom.hxml | 9 ++- haxe_libraries/coconut.vdom.hxml | 8 +-- haxe_libraries/tink_core.hxml | 6 +- haxe_libraries/tink_hxx.hxml | 4 +- haxe_libraries/tink_state.hxml | 4 +- src/coconut/ui/internal/Attribute.hx | 16 +++++ src/coconut/ui/internal/Slot.hx | 89 -------------------------- src/coconut/ui/macros/ViewBuilder.hx | 11 ++-- tests/Tests.hx | 65 ++++++------------- tests/import.hx | 4 +- 13 files changed, 66 insertions(+), 167 deletions(-) create mode 100644 src/coconut/ui/internal/Attribute.hx delete mode 100644 src/coconut/ui/internal/Slot.hx diff --git a/dev.hxml b/dev.hxml index 9fbf666..9ad6062 100644 --- a/dev.hxml +++ b/dev.hxml @@ -1,6 +1,6 @@ tests.hxml --lib coconut.vdom -# with-react.hxml +# -lib coconut.vdom +with-react.hxml -lib travix -D no-deprecation-warnings -js bin/js/tests.js \ No newline at end of file diff --git a/haxe_libraries/coconut.data.hxml b/haxe_libraries/coconut.data.hxml index 4cd16f2..27a45cb 100644 --- a/haxe_libraries/coconut.data.hxml +++ b/haxe_libraries/coconut.data.hxml @@ -1,8 +1,7 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.data#587d2c2dbc57cc24ecb52303c5e22eb97fed12cd" into coconut.data/0.12.1/github/587d2c2dbc57cc24ecb52303c5e22eb97fed12cd +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.data#ca17dc7efb408b8032116493fb2e02f362382956" into coconut.data/0.12.1/github/ca17dc7efb408b8032116493fb2e02f362382956 -lib tink_anon -lib tink_priority -lib tink_pure -lib tink_state --cp ${HAXE_LIBCACHE}/coconut.data/0.12.1/github/587d2c2dbc57cc24ecb52303c5e22eb97fed12cd/src --D coconut.data=0.12.1 ---macro coconut.data.macros.Setup.run() \ No newline at end of file +-cp ${HAXE_LIBCACHE}/coconut.data/0.12.1/github/ca17dc7efb408b8032116493fb2e02f362382956/src +-D coconut.data=0.12.1 \ No newline at end of file diff --git a/haxe_libraries/coconut.react-core.hxml b/haxe_libraries/coconut.react-core.hxml index 30d01c6..47f6224 100644 --- a/haxe_libraries/coconut.react-core.hxml +++ b/haxe_libraries/coconut.react-core.hxml @@ -1,8 +1,8 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-core#e2d2eab146d79940dfd253700efb94ad033504ca" into coconut.react-core/0.2.2/github/e2d2eab146d79940dfd253700efb94ad033504ca +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-core#84f0f5b150699de2e27ce2e19c9063d1a1ba3732" into coconut.react-core/0.3.0/github/84f0f5b150699de2e27ce2e19c9063d1a1ba3732 -lib coconut.ui -lib react-next -lib tink_priority --cp ${HAXE_LIBCACHE}/coconut.react-core/0.2.2/github/e2d2eab146d79940dfd253700efb94ad033504ca/src --D coconut.react-core=0.2.2 +-cp ${HAXE_LIBCACHE}/coconut.react-core/0.3.0/github/84f0f5b150699de2e27ce2e19c9063d1a1ba3732/src +-D coconut.react-core=0.3.0 --macro coconut.react.macros.Setup.all() -D coconut_react_core \ No newline at end of file diff --git a/haxe_libraries/coconut.react-dom.hxml b/haxe_libraries/coconut.react-dom.hxml index fb6ddca..f3fb75b 100644 --- a/haxe_libraries/coconut.react-dom.hxml +++ b/haxe_libraries/coconut.react-dom.hxml @@ -1,6 +1,5 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-dom#23744776318ac391d8613d521649660253e11964" into coconut.react-dom/0.1.0/github/23744776318ac391d8613d521649660253e11964 +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-dom#a3ecd744ff58b0532e23017978cc8bebcfd61eec" into coconut.react-dom/0.3.0/github/a3ecd744ff58b0532e23017978cc8bebcfd61eec -lib coconut.react-core --lib xDOM --cp ${HAXE_LIBCACHE}/coconut.react-dom/0.1.0/github/23744776318ac391d8613d521649660253e11964/src --D coconut.react-dom=0.1.0 ---macro coconut.react.macros.Html.registerTags() \ No newline at end of file +-lib tink_domspec +-cp ${HAXE_LIBCACHE}/coconut.react-dom/0.3.0/github/a3ecd744ff58b0532e23017978cc8bebcfd61eec/src +-D coconut.react-dom=0.3.0 \ No newline at end of file diff --git a/haxe_libraries/coconut.vdom.hxml b/haxe_libraries/coconut.vdom.hxml index 2c8611b..63549fd 100644 --- a/haxe_libraries/coconut.vdom.hxml +++ b/haxe_libraries/coconut.vdom.hxml @@ -1,5 +1,5 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.vdom#98cb1bf86b63312f3e0507f3b6e7bd79835861e6" into coconut.vdom/0.8.1/github/98cb1bf86b63312f3e0507f3b6e7bd79835861e6 --lib coconut.diffing -lib xDOM --cp ${HAXE_LIBCACHE}/coconut.vdom/0.8.1/github/98cb1bf86b63312f3e0507f3b6e7bd79835861e6/src --D coconut.vdom=0.8.1 \ No newline at end of file +-lib coconut.diffing +-cp ${SCOPE_DIR}/../coconut.vdom/src +-D coconut.vdom=0.10.0 +--macro Sys.println("haxe_libraries/coconut.vdom.hxml:4: [Warning] Using dev version of library coconut.vdom") \ No newline at end of file diff --git a/haxe_libraries/tink_core.hxml b/haxe_libraries/tink_core.hxml index 13d5bed..f97bc45 100644 --- a/haxe_libraries/tink_core.hxml +++ b/haxe_libraries/tink_core.hxml @@ -1,3 +1,3 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_core#83032eb4327a73d8dd90a36d720d0d30154bb300" into tink_core/2.0.1/github/83032eb4327a73d8dd90a36d720d0d30154bb300 --cp ${HAXE_LIBCACHE}/tink_core/2.0.1/github/83032eb4327a73d8dd90a36d720d0d30154bb300/src --D tink_core=2.0.1 \ No newline at end of file +# @install: lix --silent download "gh://github.com/haxetink/tink_core#33a5b72257d421c0b278973d58805c9ecefea259" into tink_core/2.0.2/github/33a5b72257d421c0b278973d58805c9ecefea259 +-cp ${HAXE_LIBCACHE}/tink_core/2.0.2/github/33a5b72257d421c0b278973d58805c9ecefea259/src +-D tink_core=2.0.2 \ No newline at end of file diff --git a/haxe_libraries/tink_hxx.hxml b/haxe_libraries/tink_hxx.hxml index 2739de7..d29acdf 100644 --- a/haxe_libraries/tink_hxx.hxml +++ b/haxe_libraries/tink_hxx.hxml @@ -1,6 +1,6 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_hxx#0d6cda883d5ef4c1186dbad476e016b98aad68b8" into tink_hxx/0.25.0/github/0d6cda883d5ef4c1186dbad476e016b98aad68b8 +# @install: lix --silent download "gh://github.com/haxetink/tink_hxx#acfc06d7fa373aec051762a2096c0e742bbbf900" into tink_hxx/0.25.0/github/acfc06d7fa373aec051762a2096c0e742bbbf900 -lib html-entities -lib tink_anon -lib tink_parse --cp ${HAXE_LIBCACHE}/tink_hxx/0.25.0/github/0d6cda883d5ef4c1186dbad476e016b98aad68b8/src +-cp ${HAXE_LIBCACHE}/tink_hxx/0.25.0/github/acfc06d7fa373aec051762a2096c0e742bbbf900/src -D tink_hxx=0.25.0 \ No newline at end of file diff --git a/haxe_libraries/tink_state.hxml b/haxe_libraries/tink_state.hxml index 58a8f3d..bf53358 100644 --- a/haxe_libraries/tink_state.hxml +++ b/haxe_libraries/tink_state.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_state#b01eb8bd47f7264420604b5f8816dde69e5dec55" into tink_state/1.0.0-beta.3/github/b01eb8bd47f7264420604b5f8816dde69e5dec55 +# @install: lix --silent download "gh://github.com/haxetink/tink_state#7048c7869a0d2d9f2e26e0d186269ebd7006ca77" into tink_state/1.0.0-beta.3/github/7048c7869a0d2d9f2e26e0d186269ebd7006ca77 -lib tink_core --cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/b01eb8bd47f7264420604b5f8816dde69e5dec55/src +-cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/7048c7869a0d2d9f2e26e0d186269ebd7006ca77/src -D tink_state=1.0.0-beta.3 \ No newline at end of file diff --git a/src/coconut/ui/internal/Attribute.hx b/src/coconut/ui/internal/Attribute.hx new file mode 100644 index 0000000..b41ec01 --- /dev/null +++ b/src/coconut/ui/internal/Attribute.hx @@ -0,0 +1,16 @@ +package coconut.ui.internal; + +import tink.state.internal.*; + +abstract Attribute(AutoObservable) { + + public var value(get, never):T; + inline function get_value() + return AutoObservable.track(this); + + public inline function new(compute, ?comparator) + this = new AutoObservable(compute, comparator); + + public inline function assign(compute) + this.swapComputation(compute); +} \ No newline at end of file diff --git a/src/coconut/ui/internal/Slot.hx b/src/coconut/ui/internal/Slot.hx deleted file mode 100644 index 1dd5d74..0000000 --- a/src/coconut/ui/internal/Slot.hx +++ /dev/null @@ -1,89 +0,0 @@ -package coconut.ui.internal; - -import tink.state.*; -import tink.state.internal.*; - -using tink.CoreApi; - -class Slot> - extends Invalidatable.Invalidator implements Invalidatable implements ObservableObject { - - var data:Container; - var link:CallbackLink; - - final defaultData:Container;//TODO: this should be lazy - #if tink_state.debug - final owner:{}; - #end - final comparator:Comparator; - - public var value(get, never):T; - inline function get_value() - return observe().value; - - public function new(owner:{}, ?comparator, ?defaultData, ?toString) { - super(toString); - #if tink_state.debug - this.owner = owner; - #end - this.comparator = comparator; - this.data = this.defaultData = defaultData; - list.ondrain = () -> link.cancel(); - list.onfill = () -> heatup(); - } - - function heatup() - if (data != null) link = data.onInvalidate(this); - - public inline function observe():Observable - return this; - - public function invalidate() - fire(); - - public function getComparator():Comparator - return comparator; - - override public function getRevision() { - var ret = revision; - if (data != null) ret *= data.getRevision(); - if (defaultData != null) ret *= defaultData.getRevision(); - return ret; - } - - public function getValue() - return switch [data, defaultData] { - case [null, null]: null; - case [v, null] | [null, v]: v.getValue(); - case [_.getValue() => ret, v]: - if (ret == null) v.getValue(); - else ret; - } - - public function isValid() - return this.data == null || this.data.isValid(); - - public function setData(data:Container) { - if (data == null) - data = defaultData; - if (data == this.data) return; - - this.data = data; - if (list.length > 0) { - link.cancel(); - heatup(); - } - fire(); - } - - #if tink_state.debug - public function getDependencies() { - var ret = new Array>(); - if (data != null) - ret.push(cast data); - if (defaultData != data && defaultData != null) - ret.push(cast defaultData); - return ret.iterator(); - } - #end -} \ No newline at end of file diff --git a/src/coconut/ui/macros/ViewBuilder.hx b/src/coconut/ui/macros/ViewBuilder.hx index eb2529e..6c3e4de 100644 --- a/src/coconut/ui/macros/ViewBuilder.hx +++ b/src/coconut/ui/macros/ViewBuilder.hx @@ -186,15 +186,15 @@ class ViewBuilder { slotName = slotName(a.name); if (!display) { - initSlots.push(macro @:pos(a.pos) this.$slotName.setData($data)); + initSlots.push(macro @:pos(a.pos) this.$slotName.assign($data)); if (expr == null) expr = macro @:pos(a.pos) null; add(macro class { - @:noCompletion private final $slotName:coconut.ui.internal.Slot<$type, $publicType>; + @:noCompletion private final $slotName:coconut.ui.internal.Attribute<$type>; }); - initField(slotName, macro new coconut.ui.internal.Slot<$type, $publicType>(this, ${comparator}, $expr #if tink_state.debug , (_) -> $v{c.target.name} + '#' + this.viewId + '.' + $v{a.name} #end)); + initField(slotName, macro new coconut.ui.internal.Attribute<$type>($expr, ${comparator} #if tink_state.debug , (_) -> $v{c.target.name} + '#' + this.viewId + '.' + $v{a.name} #end)); } switch a.pos.getOutcome(type.toType()).reduce() { @@ -230,10 +230,10 @@ class ViewBuilder { var slotName = slotName(name); - if (optional && expr == null) + if (expr == null) expr = macro @:pos(a.pos) null; - addAttribute(attr.pos, a, expr, type, macro : coconut.data.Value<$type>, optional, + addAttribute(attr.pos, a, macro @:pos(expr.pos) function ():$type return $expr, type, macro : tink.hxx.Expression<$type>, optional, attr.meta.comparator, a.metaNamed(':children') .concat(a.metaNamed(':child')) @@ -337,6 +337,7 @@ class ViewBuilder { for (c in scrape('controlled', noArgs)) switch c.member.kind { case FVar(t, e): + c.pos.error('currently not implemented yet'); if (t == null) t = guessType(e, c.pos); var optional = switch e { diff --git a/tests/Tests.hx b/tests/Tests.hx index 8302a9c..3499f6f 100644 --- a/tests/Tests.hx +++ b/tests/Tests.hx @@ -54,35 +54,6 @@ class Tests extends haxe.unit.TestCase { assertEquals(beforeInner + 1, Example4.redraws); } - function testSlot() { - var s = new coconut.ui.internal.Slot(this, Observable.const(123)), - s1 = new State(0), - s2 = new State(1000); - var log = []; - s.observe().bind(log.push); - s.setData(Observable.const(42)); - assertEquals('123', log.join(',')); - Renderer.updateAll(); - assertEquals('123,42', log.join(',')); - s.setData(Observable.const(0)); - Renderer.updateAll(); - assertEquals('123,42,0', log.join(',')); - s.setData(s1); - Renderer.updateAll(); - assertEquals('123,42,0', log.join(',')); - s1.set(1000); - Renderer.updateAll(); - assertEquals('123,42,0,1000', log.join(',')); - s.setData(s2); - Renderer.updateAll(); - assertEquals('123,42,0,1000', log.join(',')); - - s1.set(1001); - s2.set(1002); - Renderer.updateAll(); - assertEquals('123,42,0,1000,1002', log.join(',')); - } - function testCustom() { var s = new State(4); @@ -146,23 +117,23 @@ class Tests extends haxe.unit.TestCase { } - function testControlled() { - mount(hxx('')); - assertEquals('0', q('#counter1').innerHTML); - click('#counter1'); - assertEquals('1', q('#counter1').innerHTML); - var f = new Foo({ foo: 42 }); - - mount(hxx('')); - assertEquals('42', q('#counter2').innerHTML); - click('#counter2'); - assertEquals('43', q('#counter2').innerHTML); - - mount(hxx('')); - assertEquals(null, q('button.selected[data-value="1"]')); - click('button[data-value="1"]'); - assertEquals('1', q('button.selected[data-value="1"]').innerHTML); - } + // function testControlled() { + // mount(hxx('')); + // assertEquals('0', q('#counter1').innerHTML); + // click('#counter1'); + // assertEquals('1', q('#counter1').innerHTML); + // var f = new Foo({ foo: 42 }); + + // mount(hxx('')); + // assertEquals('42', q('#counter2').innerHTML); + // click('#counter2'); + // assertEquals('43', q('#counter2').innerHTML); + + // mount(hxx('')); + // assertEquals(null, q('button.selected[data-value="1"]')); + // click('button[data-value="1"]'); + // assertEquals('1', q('button.selected[data-value="1"]').innerHTML); + // } static function click(selector) { q(selector).click(); @@ -435,7 +406,7 @@ class Tests extends haxe.unit.TestCase { static function main() { Runner.run( TestBatch.make([ - new Implicits(), + // new Implicits(), new issues.Issue48(), new issues.Issue63(), new issues.Issue80(), diff --git a/tests/import.hx b/tests/import.hx index ff7fc1a..09bf4a7 100644 --- a/tests/import.hx +++ b/tests/import.hx @@ -1,9 +1,11 @@ import js.Browser.*; import coconut.Ui.hxx; +using tink.hxx.FunctionSugar; using tink.CoreApi; import tink.state.*; import coconut.ui.*; import coconut.data.*; import views.*; -import models.*; \ No newline at end of file +import models.*; +import coconut.ui.Html.*; \ No newline at end of file From 9d78fc3d47c20be5ff1900984346bd2a15258141 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sat, 7 Aug 2021 17:24:09 +0200 Subject: [PATCH 02/15] Tests compile for react \o/ --- haxe_libraries/coconut.react-dom.hxml | 7 ++--- haxe_libraries/tink_anon.hxml | 4 +-- haxe_libraries/tink_hxx.hxml | 4 +-- haxe_libraries/tink_state.hxml | 4 +-- src/coconut/ui/internal/Attribute.hx | 5 +--- src/coconut/ui/internal/ImplicitContext.hx | 26 +++++++------------ .../ui/internal/ImplicitContext.macro.hx | 17 ++++++++++++ src/coconut/ui/macros/ViewBuilder.hx | 6 ++--- tests/Tests.hx | 2 +- 9 files changed, 41 insertions(+), 34 deletions(-) create mode 100644 src/coconut/ui/internal/ImplicitContext.macro.hx diff --git a/haxe_libraries/coconut.react-dom.hxml b/haxe_libraries/coconut.react-dom.hxml index f3fb75b..ff8ae07 100644 --- a/haxe_libraries/coconut.react-dom.hxml +++ b/haxe_libraries/coconut.react-dom.hxml @@ -1,5 +1,6 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-dom#a3ecd744ff58b0532e23017978cc8bebcfd61eec" into coconut.react-dom/0.3.0/github/a3ecd744ff58b0532e23017978cc8bebcfd61eec +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-dom#f569d03939e1b6035d7453723ef66e97deb410b1" into coconut.react-dom/0.3.0/github/f569d03939e1b6035d7453723ef66e97deb410b1 -lib coconut.react-core -lib tink_domspec --cp ${HAXE_LIBCACHE}/coconut.react-dom/0.3.0/github/a3ecd744ff58b0532e23017978cc8bebcfd61eec/src --D coconut.react-dom=0.3.0 \ No newline at end of file +-cp ${HAXE_LIBCACHE}/coconut.react-dom/0.3.0/github/f569d03939e1b6035d7453723ef66e97deb410b1/src +-D coconut.react-dom=0.3.0 +--macro coconut.react.Html.init() \ No newline at end of file diff --git a/haxe_libraries/tink_anon.hxml b/haxe_libraries/tink_anon.hxml index 58a2b3d..6046e27 100644 --- a/haxe_libraries/tink_anon.hxml +++ b/haxe_libraries/tink_anon.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_anon#a44bdda9caa41d461f9b0a43366ea9c320260963" into tink_anon/0.7.0/github/a44bdda9caa41d461f9b0a43366ea9c320260963 +# @install: lix --silent download "gh://github.com/haxetink/tink_anon#0277e6e3f97a7878f1aa9aeeccc4b7be0e9c82bc" into tink_anon/0.7.0/github/0277e6e3f97a7878f1aa9aeeccc4b7be0e9c82bc -lib tink_macro --cp ${HAXE_LIBCACHE}/tink_anon/0.7.0/github/a44bdda9caa41d461f9b0a43366ea9c320260963/src +-cp ${HAXE_LIBCACHE}/tink_anon/0.7.0/github/0277e6e3f97a7878f1aa9aeeccc4b7be0e9c82bc/src -D tink_anon=0.7.0 \ No newline at end of file diff --git a/haxe_libraries/tink_hxx.hxml b/haxe_libraries/tink_hxx.hxml index d29acdf..97169f4 100644 --- a/haxe_libraries/tink_hxx.hxml +++ b/haxe_libraries/tink_hxx.hxml @@ -1,6 +1,6 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_hxx#acfc06d7fa373aec051762a2096c0e742bbbf900" into tink_hxx/0.25.0/github/acfc06d7fa373aec051762a2096c0e742bbbf900 +# @install: lix --silent download "gh://github.com/haxetink/tink_hxx#07cada55ff0b550b47f6e1ffb888be62d1e969c4" into tink_hxx/0.25.0/github/07cada55ff0b550b47f6e1ffb888be62d1e969c4 -lib html-entities -lib tink_anon -lib tink_parse --cp ${HAXE_LIBCACHE}/tink_hxx/0.25.0/github/acfc06d7fa373aec051762a2096c0e742bbbf900/src +-cp ${HAXE_LIBCACHE}/tink_hxx/0.25.0/github/07cada55ff0b550b47f6e1ffb888be62d1e969c4/src -D tink_hxx=0.25.0 \ No newline at end of file diff --git a/haxe_libraries/tink_state.hxml b/haxe_libraries/tink_state.hxml index bf53358..7134ddc 100644 --- a/haxe_libraries/tink_state.hxml +++ b/haxe_libraries/tink_state.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_state#7048c7869a0d2d9f2e26e0d186269ebd7006ca77" into tink_state/1.0.0-beta.3/github/7048c7869a0d2d9f2e26e0d186269ebd7006ca77 +# @install: lix --silent download "gh://github.com/haxetink/tink_state#85515e36666e91db1281d574c3c31ecc9ae2e450" into tink_state/1.0.0-beta.3/github/85515e36666e91db1281d574c3c31ecc9ae2e450 -lib tink_core --cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/7048c7869a0d2d9f2e26e0d186269ebd7006ca77/src +-cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/85515e36666e91db1281d574c3c31ecc9ae2e450/src -D tink_state=1.0.0-beta.3 \ No newline at end of file diff --git a/src/coconut/ui/internal/Attribute.hx b/src/coconut/ui/internal/Attribute.hx index b41ec01..50dbf91 100644 --- a/src/coconut/ui/internal/Attribute.hx +++ b/src/coconut/ui/internal/Attribute.hx @@ -2,12 +2,9 @@ package coconut.ui.internal; import tink.state.internal.*; +@:forward(value) abstract Attribute(AutoObservable) { - public var value(get, never):T; - inline function get_value() - return AutoObservable.track(this); - public inline function new(compute, ?comparator) this = new AutoObservable(compute, comparator); diff --git a/src/coconut/ui/internal/ImplicitContext.hx b/src/coconut/ui/internal/ImplicitContext.hx index cb91426..1d355f0 100644 --- a/src/coconut/ui/internal/ImplicitContext.hx +++ b/src/coconut/ui/internal/ImplicitContext.hx @@ -1,7 +1,7 @@ package coconut.ui.internal; import tink.state.*; -import coconut.data.Value; +import tink.state.internal.*; using tink.CoreApi; #if macro using tink.MacroApi; @@ -10,7 +10,7 @@ using tink.CoreApi; class ImplicitContext { final parent:Lazy>; - final slots = new Map, Slot>>(); + final slots = new Map, AutoObservable>(); public function new(?parent) { this.parent = switch parent { @@ -31,28 +31,20 @@ class ImplicitContext { function getSlot(key) return switch slots[key] { - case null: slots[key] = new Slot(this);// in theory, creating slots and never destroying them leaks ... in practice, the key set for every context should always be small and well-bound, and typically constant + case null: slots[key] = new AutoObservable(() -> Noise);// in theory, creating slots and never destroying them leaks ... in practice, the key set for every context should always be small and well-bound, and typically constant case v: v; } public function update(values:ImplicitValues) { for (k => slot in slots) - if (!values.exists(k)) slot.setData(null); + if (!values.exists(k)) slot.swapComputation(null); for (k => v in values) - getSlot(k).setData(v); + getSlot(k).swapComputation(v); } - static public macro function with(e) { - var exprs = switch e.expr { case EArrayDecl(a): a; default: [e]; }; - var entries = [for (e in exprs) switch e { - case macro $k => $v: - macro @:pos(e.pos) new coconut.ui.internal.ImplicitContext.SingleImplicit($k, $v); - default: e.reject('expected key => value'); - }]; - return macro new coconut.ui.internal.ImplicitContext.ImplicitValues([$a{entries}]); - } + static public macro function with(e); } abstract TypeKey({}) to {} { @@ -67,15 +59,15 @@ abstract TypeKey({}) to {} { @:fromHxx( transform = coconut.ui.internal.ImplicitContext.with(_) ) -abstract ImplicitValues(Map, Value>) { +abstract ImplicitValues(Map, Computation>) { public function new(a:Array) this = [for (o in a) o.key => o.val]; } class SingleImplicit { public final key:TypeKey; - public final val:Value; + public final val:Computation; - public function new(key:TypeKey, val:Value) { + public function new(key:TypeKey, val:tink.hxx.Expression) { this.key = key; this.val = val; } diff --git a/src/coconut/ui/internal/ImplicitContext.macro.hx b/src/coconut/ui/internal/ImplicitContext.macro.hx new file mode 100644 index 0000000..5802d55 --- /dev/null +++ b/src/coconut/ui/internal/ImplicitContext.macro.hx @@ -0,0 +1,17 @@ +package coconut.ui.internal; + +import haxe.macro.Expr; +using tink.MacroApi; + +class ImplicitContext { + + static function with(e:Expr) { + var exprs = switch e.expr { case EArrayDecl(a): a; default: [e]; }; + var entries = [for (e in exprs) switch e { + case macro $k => $v: + macro @:pos(e.pos) new coconut.ui.internal.ImplicitContext.SingleImplicit($k, function () return $v); + default: e.reject('expected key => value'); + }]; + return macro new coconut.ui.internal.ImplicitContext.ImplicitValues([$a{entries}]); + } +} \ No newline at end of file diff --git a/src/coconut/ui/macros/ViewBuilder.hx b/src/coconut/ui/macros/ViewBuilder.hx index 6c3e4de..d299cb8 100644 --- a/src/coconut/ui/macros/ViewBuilder.hx +++ b/src/coconut/ui/macros/ViewBuilder.hx @@ -415,12 +415,12 @@ class ViewBuilder { macro { var fallback = tink.core.Lazy.ofFunc(() -> $fallback); - tink.state.Observable.auto(() -> switch $i{implicits}.get($p{t.toString().split('.')}) { + () -> switch $i{implicits}.get($p{t.toString().split('.')}) { case null: fallback.get(); case v: v; - }); + }; } - }, t, macro : coconut.data.Value<$t>, true, macro null); + }, t, macro : tink.hxx.Expression<$t>, true, macro null); m.publish(); m.kind = FProp('get', 'never', t); diff --git a/tests/Tests.hx b/tests/Tests.hx index 3499f6f..18b1702 100644 --- a/tests/Tests.hx +++ b/tests/Tests.hx @@ -406,7 +406,7 @@ class Tests extends haxe.unit.TestCase { static function main() { Runner.run( TestBatch.make([ - // new Implicits(), + new Implicits(), new issues.Issue48(), new issues.Issue63(), new issues.Issue80(), From 8994863ce9b5bf5b3b11b90ee0d986b5831aa7a6 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Wed, 11 Aug 2021 09:56:58 +0200 Subject: [PATCH 03/15] Delete unused thing. --- src/coconut/ui/internal/ImplicitContext.hx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coconut/ui/internal/ImplicitContext.hx b/src/coconut/ui/internal/ImplicitContext.hx index 1d355f0..c44359d 100644 --- a/src/coconut/ui/internal/ImplicitContext.hx +++ b/src/coconut/ui/internal/ImplicitContext.hx @@ -20,7 +20,6 @@ class ImplicitContext { } static final ORPHAN:Lazy> = (null:ImplicitContext); - static final NONE = Observable.const(new ImplicitValues([])); public function get(key:TypeKey):Null return switch [getSlot(key).value, parent.get()] { From aa083706023b0c070d3f82c86a411c0a1d2412bf Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Fri, 13 Aug 2021 17:03:47 +0200 Subject: [PATCH 04/15] Slowly progressing. --- dev.hxml | 4 +- haxe_libraries/coconut.diffing.hxml | 6 +-- haxe_libraries/tink_state.hxml | 6 +-- src/coconut/ui/internal/Attribute.hx | 46 ++++++++++++++-- src/coconut/ui/internal/Controlled.hx | 52 ++++++++++++++++++ src/coconut/ui/internal/ImplicitContext.hx | 13 +++-- src/coconut/ui/internal/Variable.hx | 14 +++++ src/coconut/ui/internal/Variable.macro.hx | 63 ++++++++++++++++++++++ src/coconut/ui/macros/ViewBuilder.hx | 21 ++++---- tests/Tests.hx | 34 ++++++------ tests/cases/Base.hx | 3 +- tests/views/Wrapper.hx | 16 ++++-- 12 files changed, 225 insertions(+), 53 deletions(-) create mode 100644 src/coconut/ui/internal/Controlled.hx create mode 100644 src/coconut/ui/internal/Variable.hx create mode 100644 src/coconut/ui/internal/Variable.macro.hx diff --git a/dev.hxml b/dev.hxml index 9ad6062..9fbf666 100644 --- a/dev.hxml +++ b/dev.hxml @@ -1,6 +1,6 @@ tests.hxml -# -lib coconut.vdom -with-react.hxml +-lib coconut.vdom +# with-react.hxml -lib travix -D no-deprecation-warnings -js bin/js/tests.js \ No newline at end of file diff --git a/haxe_libraries/coconut.diffing.hxml b/haxe_libraries/coconut.diffing.hxml index 8b2cab8..30ced0d 100644 --- a/haxe_libraries/coconut.diffing.hxml +++ b/haxe_libraries/coconut.diffing.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.diffing#867b48ea374077d1ff15b05de4e07430637217ea" into coconut.diffing/0.2.1/github/867b48ea374077d1ff15b05de4e07430637217ea -lib coconut.ui --cp ${HAXE_LIBCACHE}/coconut.diffing/0.2.1/github/867b48ea374077d1ff15b05de4e07430637217ea/src --D coconut.diffing=0.2.1 \ No newline at end of file +-cp ${SCOPE_DIR}/../coconut.diffing/src +-D coconut.diffing=0.5.0 +--macro Sys.println("haxe_libraries/coconut.diffing.hxml:3: [Warning] Using dev version of library coconut.diffing") \ No newline at end of file diff --git a/haxe_libraries/tink_state.hxml b/haxe_libraries/tink_state.hxml index 7134ddc..d50bd42 100644 --- a/haxe_libraries/tink_state.hxml +++ b/haxe_libraries/tink_state.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_state#85515e36666e91db1281d574c3c31ecc9ae2e450" into tink_state/1.0.0-beta.3/github/85515e36666e91db1281d574c3c31ecc9ae2e450 -lib tink_core --cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/85515e36666e91db1281d574c3c31ecc9ae2e450/src --D tink_state=1.0.0-beta.3 \ No newline at end of file +-cp ${SCOPE_DIR}/../../tink/state/src +-D tink_state=1.0.0-beta.3 +--macro Sys.println("haxe_libraries/tink_state.hxml:3: [Warning] Using dev version of library tink_state") \ No newline at end of file diff --git a/src/coconut/ui/internal/Attribute.hx b/src/coconut/ui/internal/Attribute.hx index 50dbf91..87274b4 100644 --- a/src/coconut/ui/internal/Attribute.hx +++ b/src/coconut/ui/internal/Attribute.hx @@ -1,13 +1,49 @@ package coconut.ui.internal; +import tink.state.*; import tink.state.internal.*; -@:forward(value) -abstract Attribute(AutoObservable) { +@:forward(value, assign) +abstract Attribute(Impl) { public inline function new(compute, ?comparator) - this = new AutoObservable(compute, comparator); + this = new Impl(compute, comparator); +} - public inline function assign(compute) - this.swapComputation(compute); +private class Impl implements ObservableObject extends Dispatcher { + + final dFault:()->T; + var cur:Null<()->T>; + final comparator:Comparator; + + public var value(get, never):T; + inline function get_value():T + return (this:Observable).value; + + public function new(compute:()->T, ?comparator) { + super(); + this.comparator = comparator; + this.dFault = compute; + } + + public function assign(c:Null<()->T>) + if (c != cur) { + cur = c; + fire(this); + } + + public function getValue():T + return switch cur { + case null: dFault(); + case f: switch f() { + case null: dFault(); + case v: v; + } + } + + public function isValid():Bool + return false;//TODO: implement + + public function getComparator():Comparator + return comparator; } \ No newline at end of file diff --git a/src/coconut/ui/internal/Controlled.hx b/src/coconut/ui/internal/Controlled.hx new file mode 100644 index 0000000..063a81e --- /dev/null +++ b/src/coconut/ui/internal/Controlled.hx @@ -0,0 +1,52 @@ +package coconut.ui.internal; + +import tink.state.*; +import tink.state.internal.*; + +@:forward(value, assign) +abstract Controlled(Impl) { + + public inline function new(compute, ?comparator) + this = new Impl(compute, comparator); +} + +private class Impl implements ObservableObject extends Dispatcher { + + final fallback:tink.core.Lazy>; + var cur:Null>; + final comparator:Comparator; + + public var value(get, set):T; + inline function get_value():T + return state().value; + + inline function set_value(param):T + return state().value = param; + + inline function state() + return switch cur { + case null: fallback.get(); + case v: v; + } + + public function new(fallback, ?comparator) { + super(); + this.comparator = comparator; + this.fallback = fallback; + } + + public function assign(c:Null>) + if (c != cur) { + cur = c; + fire(this); + } + + public function getValue():T + return state().value; + + public function isValid():Bool + return false;//TODO: implement + + public function getComparator():Comparator + return comparator; +} \ No newline at end of file diff --git a/src/coconut/ui/internal/ImplicitContext.hx b/src/coconut/ui/internal/ImplicitContext.hx index c44359d..e3f1b6e 100644 --- a/src/coconut/ui/internal/ImplicitContext.hx +++ b/src/coconut/ui/internal/ImplicitContext.hx @@ -1,7 +1,6 @@ package coconut.ui.internal; import tink.state.*; -import tink.state.internal.*; using tink.CoreApi; #if macro using tink.MacroApi; @@ -10,7 +9,7 @@ using tink.CoreApi; class ImplicitContext { final parent:Lazy>; - final slots = new Map, AutoObservable>(); + final slots = new Map, Attribute>(); public function new(?parent) { this.parent = switch parent { @@ -30,17 +29,17 @@ class ImplicitContext { function getSlot(key) return switch slots[key] { - case null: slots[key] = new AutoObservable(() -> Noise);// in theory, creating slots and never destroying them leaks ... in practice, the key set for every context should always be small and well-bound, and typically constant + case null: slots[key] = new Attribute(() -> Noise);// in theory, creating slots and never destroying them leaks ... in practice, the key set for every context should always be small and well-bound, and typically constant case v: v; } public function update(values:ImplicitValues) { for (k => slot in slots) - if (!values.exists(k)) slot.swapComputation(null); + if (!values.exists(k)) slot.assign(null); for (k => v in values) - getSlot(k).swapComputation(v); + getSlot(k).assign(v); } static public macro function with(e); @@ -58,13 +57,13 @@ abstract TypeKey({}) to {} { @:fromHxx( transform = coconut.ui.internal.ImplicitContext.with(_) ) -abstract ImplicitValues(Map, Computation>) { +abstract ImplicitValues(Map, tink.hxx.Expression>) { public function new(a:Array) this = [for (o in a) o.key => o.val]; } class SingleImplicit { public final key:TypeKey; - public final val:Computation; + public final val:tink.hxx.Expression; public function new(key:TypeKey, val:tink.hxx.Expression) { this.key = key; diff --git a/src/coconut/ui/internal/Variable.hx b/src/coconut/ui/internal/Variable.hx new file mode 100644 index 0000000..abc7a35 --- /dev/null +++ b/src/coconut/ui/internal/Variable.hx @@ -0,0 +1,14 @@ +package coconut.ui.internal; + +import tink.state.*; + +@:fromHxx( + transform = coconut.ui.internal.Variable.make(_) +) +@:forward +abstract Variable(State) from State to State { + public inline function new(init) + this = new State(init); + + static public macro function make(e); +} \ No newline at end of file diff --git a/src/coconut/ui/internal/Variable.macro.hx b/src/coconut/ui/internal/Variable.macro.hx new file mode 100644 index 0000000..55e3127 --- /dev/null +++ b/src/coconut/ui/internal/Variable.macro.hx @@ -0,0 +1,63 @@ +package coconut.ui.internal; + +import haxe.macro.Context.*; +import haxe.macro.Expr; + +using haxe.macro.Tools; +using tink.MacroApi; + +abstract Variable(Dynamic) { + static function shouldCheck(e:Expr) + return switch e { + case { expr: ECheckType(e, _)} | macro ($e): shouldCheck(e); + case macro @:skipCheck $_: false; + default: true; + } + + static public function make(e:Expr) + return (switch typeExpr(e) { + case done = followWithAbstracts(_.t) => TInst(_.get() => { module: 'tink.state.State', name: 'StateObject' }, _): + storeTypedExpr(done); + case te: + switch e { + case macro $i{name}: + e = macro @:pos(e.pos) this.$name; + default: + } + switch e { + case macro ${owner}.$name: // TODO: consider checking if the target is valid + + var v = typeExpr(owner); + if (v.hasThis()) + v = typeExpr(macro @:pos(owner.pos) (function () return $owner)()); + + var ret = storeTypedExpr(v); + + if (shouldCheck(e)) { + var ownerT = v.t, + pos = e.pos; + + coconut.data.macros.Models.afterChecking(function () { + switch coconut.data.macros.Models.check(ownerT) { + case []: + case v: + pos.error('Target not observable: ${v[0]}'); + } + }); + } + + typeof(macro @:pos(e.pos) $ret.$name = cast null); + + macro @:pos(e.pos) { + var target = tink.state.Observable.auto(function () return $ret); + @:pos(e.pos) tink.state.State.compound( + tink.state.Observable.auto(function () return target.value.$name), // consider using .map here + function (value) target.value.$name = value + ); + } + + default: + e.reject('expression should be a field or of type State (found ${te.t.toString()})'); + } + }); +} \ No newline at end of file diff --git a/src/coconut/ui/macros/ViewBuilder.hx b/src/coconut/ui/macros/ViewBuilder.hx index d299cb8..a2baa6a 100644 --- a/src/coconut/ui/macros/ViewBuilder.hx +++ b/src/coconut/ui/macros/ViewBuilder.hx @@ -180,7 +180,9 @@ class ViewBuilder { function slotName(name) return '__coco_$name'; - function addAttribute(pos, a, expr:Expr, type:ComplexType, publicType:ComplexType, optional:Bool, comparator, ?meta) { + function addAttribute(pos, a, expr:Expr, type:ComplexType, publicType:ComplexType, optional:Bool, comparator, ?meta, ?container = 'Attribute') { + var container = 'coconut.ui.internal.$container'.asTypePath([TPType(type)]); + var name = a.name; var data = macro @:pos(a.pos) attributes.$name, slotName = slotName(a.name); @@ -191,10 +193,11 @@ class ViewBuilder { if (expr == null) expr = macro @:pos(a.pos) null; + initField(slotName, macro new $container($expr, ${comparator} #if tink_state.debug , (_) -> $v{c.target.name} + '#' + this.viewId + '.' + $v{a.name} #end)); + var container = TPath(container); add(macro class { - @:noCompletion private final $slotName:coconut.ui.internal.Attribute<$type>; + @:noCompletion private final $slotName:$container; }); - initField(slotName, macro new coconut.ui.internal.Attribute<$type>($expr, ${comparator} #if tink_state.debug , (_) -> $v{c.target.name} + '#' + this.viewId + '.' + $v{a.name} #end)); } switch a.pos.getOutcome(type.toType()).reduce() { @@ -337,7 +340,6 @@ class ViewBuilder { for (c in scrape('controlled', noArgs)) switch c.member.kind { case FVar(t, e): - c.pos.error('currently not implemented yet'); if (t == null) t = guessType(e, c.pos); var optional = switch e { @@ -352,7 +354,7 @@ class ViewBuilder { true; } - addAttribute(c.pos, c.member, e, t, macro : coconut.data.Variable<$t>, optional, macro @:pos(c.pos) null); + addAttribute(c.pos, c.member, e, t, macro : coconut.ui.internal.Variable<$t>, optional, macro @:pos(c.pos) null, 'Controlled'); c.member.kind = FProp('get', 'set', t); @@ -365,13 +367,8 @@ class ViewBuilder { add(macro class { inline function $getter():$t return this.$slotName.value; - function $setter(param:$t):$t { - switch @:privateAccess this.$slotName.data {//TODO: this is quite hideous - case null: //should probably never happen - case v: v.set(param); - } - return param; - } + inline function $setter(param:$t):$t + return this.$slotName.value = param; }); case _.match(FFun(_)) => isFunc: c.pos.error('controlled attributes cannot be ${if (isFunc) 'functions' else 'properties'}'); diff --git a/tests/Tests.hx b/tests/Tests.hx index 18b1702..b40b2aa 100644 --- a/tests/Tests.hx +++ b/tests/Tests.hx @@ -117,23 +117,23 @@ class Tests extends haxe.unit.TestCase { } - // function testControlled() { - // mount(hxx('')); - // assertEquals('0', q('#counter1').innerHTML); - // click('#counter1'); - // assertEquals('1', q('#counter1').innerHTML); - // var f = new Foo({ foo: 42 }); - - // mount(hxx('')); - // assertEquals('42', q('#counter2').innerHTML); - // click('#counter2'); - // assertEquals('43', q('#counter2').innerHTML); - - // mount(hxx('')); - // assertEquals(null, q('button.selected[data-value="1"]')); - // click('button[data-value="1"]'); - // assertEquals('1', q('button.selected[data-value="1"]').innerHTML); - // } + function testControlled() { + mount(hxx('')); + assertEquals('0', q('#counter1').innerHTML); + click('#counter1'); + assertEquals('1', q('#counter1').innerHTML); + var f = new Foo({ foo: 42 }); + + mount(hxx('')); + assertEquals('42', q('#counter2').innerHTML); + click('#counter2'); + assertEquals('43', q('#counter2').innerHTML); + + mount(hxx('')); + assertEquals(null, q('button.selected[data-value="1"]')); + click('button[data-value="1"]'); + assertEquals('1', q('button.selected[data-value="1"]').innerHTML); + } static function click(selector) { q(selector).click(); diff --git a/tests/cases/Base.hx b/tests/cases/Base.hx index 5ca19fe..4961f51 100644 --- a/tests/cases/Base.hx +++ b/tests/cases/Base.hx @@ -8,7 +8,8 @@ class Base { Wrapper.mount(o); } - @:after function teardown() { + @:after public function teardown() { Wrapper.clear(); + return Promise.NOISE; } } \ No newline at end of file diff --git a/tests/views/Wrapper.hx b/tests/views/Wrapper.hx index 2859f11..6608539 100644 --- a/tests/views/Wrapper.hx +++ b/tests/views/Wrapper.hx @@ -6,9 +6,19 @@ class Wrapper { document.body.appendChild(e); e; } - static public function clear() - mount(null); - static public function mount(o) + static public function clear() { + container.remove(); + container = { + var e = document.createElement('wrapper-element'); + document.body.appendChild(e); + e; + } + // trace('yo!'); + // mount(null); + } + + static public function mount(o) { coconut.ui.Renderer.mount(container, o); + } } \ No newline at end of file From 08d710a4a62cc2fa744d16d8ff6b4cf7a08de230 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Fri, 13 Aug 2021 17:26:04 +0200 Subject: [PATCH 05/15] React almost working. --- dev.hxml | 4 ++-- haxe_libraries/tink_state.hxml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev.hxml b/dev.hxml index 9fbf666..9ad6062 100644 --- a/dev.hxml +++ b/dev.hxml @@ -1,6 +1,6 @@ tests.hxml --lib coconut.vdom -# with-react.hxml +# -lib coconut.vdom +with-react.hxml -lib travix -D no-deprecation-warnings -js bin/js/tests.js \ No newline at end of file diff --git a/haxe_libraries/tink_state.hxml b/haxe_libraries/tink_state.hxml index d50bd42..52a96f3 100644 --- a/haxe_libraries/tink_state.hxml +++ b/haxe_libraries/tink_state.hxml @@ -1,4 +1,4 @@ +# @install: lix --silent download "gh://github.com/haxetink/tink_state#15396fec1d56001325b8f68209cf3bedd01e3847" into tink_state/1.0.0-beta.3/github/15396fec1d56001325b8f68209cf3bedd01e3847 -lib tink_core --cp ${SCOPE_DIR}/../../tink/state/src --D tink_state=1.0.0-beta.3 ---macro Sys.println("haxe_libraries/tink_state.hxml:3: [Warning] Using dev version of library tink_state") \ No newline at end of file +-cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/15396fec1d56001325b8f68209cf3bedd01e3847/src +-D tink_state=1.0.0-beta.3 \ No newline at end of file From 0be4e69654856a2a057369e9be1a83a47631b6cb Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Tue, 30 Nov 2021 08:34:06 +0100 Subject: [PATCH 06/15] Bump dependencies. --- dev.hxml | 4 ++-- haxe_libraries/coconut.diffing.hxml | 6 +++--- haxe_libraries/coconut.vdom.hxml | 8 ++++---- haxe_libraries/tink_state.hxml | 4 ++-- haxe_libraries/travix.hxml | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dev.hxml b/dev.hxml index 9ad6062..9fbf666 100644 --- a/dev.hxml +++ b/dev.hxml @@ -1,6 +1,6 @@ tests.hxml -# -lib coconut.vdom -with-react.hxml +-lib coconut.vdom +# with-react.hxml -lib travix -D no-deprecation-warnings -js bin/js/tests.js \ No newline at end of file diff --git a/haxe_libraries/coconut.diffing.hxml b/haxe_libraries/coconut.diffing.hxml index 30ced0d..de58808 100644 --- a/haxe_libraries/coconut.diffing.hxml +++ b/haxe_libraries/coconut.diffing.hxml @@ -1,4 +1,4 @@ +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.diffing#499d62647c2ff68ad1336a311005f9f9d8cdf332" into coconut.diffing/0.5.0/github/499d62647c2ff68ad1336a311005f9f9d8cdf332 -lib coconut.ui --cp ${SCOPE_DIR}/../coconut.diffing/src --D coconut.diffing=0.5.0 ---macro Sys.println("haxe_libraries/coconut.diffing.hxml:3: [Warning] Using dev version of library coconut.diffing") \ No newline at end of file +-cp ${HAXE_LIBCACHE}/coconut.diffing/0.5.0/github/499d62647c2ff68ad1336a311005f9f9d8cdf332/src +-D coconut.diffing=0.5.0 \ No newline at end of file diff --git a/haxe_libraries/coconut.vdom.hxml b/haxe_libraries/coconut.vdom.hxml index 63549fd..1280eeb 100644 --- a/haxe_libraries/coconut.vdom.hxml +++ b/haxe_libraries/coconut.vdom.hxml @@ -1,5 +1,5 @@ --lib xDOM +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.vdom#710301040bf6da83530a182e25e24af4d4c31884" into coconut.vdom/0.10.0/github/710301040bf6da83530a182e25e24af4d4c31884 -lib coconut.diffing --cp ${SCOPE_DIR}/../coconut.vdom/src --D coconut.vdom=0.10.0 ---macro Sys.println("haxe_libraries/coconut.vdom.hxml:4: [Warning] Using dev version of library coconut.vdom") \ No newline at end of file +-lib xDOM +-cp ${HAXE_LIBCACHE}/coconut.vdom/0.10.0/github/710301040bf6da83530a182e25e24af4d4c31884/src +-D coconut.vdom=0.10.0 \ No newline at end of file diff --git a/haxe_libraries/tink_state.hxml b/haxe_libraries/tink_state.hxml index 52a96f3..5a1702b 100644 --- a/haxe_libraries/tink_state.hxml +++ b/haxe_libraries/tink_state.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_state#15396fec1d56001325b8f68209cf3bedd01e3847" into tink_state/1.0.0-beta.3/github/15396fec1d56001325b8f68209cf3bedd01e3847 +# @install: lix --silent download "gh://github.com/haxetink/tink_state#9fda3b07ea27e299e7f53720d6e349787477268e" into tink_state/1.0.0-beta.3/github/9fda3b07ea27e299e7f53720d6e349787477268e -lib tink_core --cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/15396fec1d56001325b8f68209cf3bedd01e3847/src +-cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/9fda3b07ea27e299e7f53720d6e349787477268e/src -D tink_state=1.0.0-beta.3 \ No newline at end of file diff --git a/haxe_libraries/travix.hxml b/haxe_libraries/travix.hxml index 29c0d68..0870b65 100644 --- a/haxe_libraries/travix.hxml +++ b/haxe_libraries/travix.hxml @@ -1,7 +1,7 @@ -# @install: lix --silent download "gh://github.com/back2dos/travix#63b230b854c6f02cf2ac04bb758c09751f28b8e8" into travix/0.15.0/github/63b230b854c6f02cf2ac04bb758c09751f28b8e8 -# @post-install: cd ${HAXE_LIBCACHE}/travix/0.15.0/github/63b230b854c6f02cf2ac04bb758c09751f28b8e8 && haxe -cp src --run travix.PostDownload -# @run: haxelib run-dir travix ${HAXE_LIBCACHE}/travix/0.15.0/github/63b230b854c6f02cf2ac04bb758c09751f28b8e8 +# @install: lix --silent download "haxelib:/travix#0.15.0" into travix/0.15.0/haxelib +# @post-install: cd ${HAXE_LIBCACHE}/travix/0.15.0/haxelib && haxe -cp src --run travix.PostDownload +# @run: haxelib run-dir travix ${HAXE_LIBCACHE}/travix/0.15.0/haxelib -lib tink_cli --cp ${HAXE_LIBCACHE}/travix/0.15.0/github/63b230b854c6f02cf2ac04bb758c09751f28b8e8/src +-cp ${HAXE_LIBCACHE}/travix/0.15.0/haxelib/src -D travix=0.15.0 --macro travix.Macro.setup() \ No newline at end of file From d36f5780ae53ba9d5c81f811440b160cdef855e2 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sat, 11 Dec 2021 20:06:00 +0100 Subject: [PATCH 07/15] Don't query parent implicit context if current has value. --- src/coconut/ui/internal/ImplicitContext.hx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/coconut/ui/internal/ImplicitContext.hx b/src/coconut/ui/internal/ImplicitContext.hx index e3f1b6e..de51927 100644 --- a/src/coconut/ui/internal/ImplicitContext.hx +++ b/src/coconut/ui/internal/ImplicitContext.hx @@ -21,10 +21,13 @@ class ImplicitContext { static final ORPHAN:Lazy> = (null:ImplicitContext); public function get(key:TypeKey):Null - return switch [getSlot(key).value, parent.get()] { - case [null, null]: null; - case [null, p]: p.get(key); - case [v, _]: v; + return switch getSlot(key).value { + case null: + switch parent.get() { + case null: null; + case ctx: ctx.get(key); + } + case v: v; } function getSlot(key) From bde0b278b82cdf78ef27dd2512fa981215aefe23 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sat, 11 Dec 2021 22:34:07 +0100 Subject: [PATCH 08/15] Fix @:controlled attributes. --- src/coconut/ui/internal/Variable.macro.hx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/coconut/ui/internal/Variable.macro.hx b/src/coconut/ui/internal/Variable.macro.hx index 55e3127..d7ff8e5 100644 --- a/src/coconut/ui/internal/Variable.macro.hx +++ b/src/coconut/ui/internal/Variable.macro.hx @@ -19,13 +19,18 @@ abstract Variable(Dynamic) { case done = followWithAbstracts(_.t) => TInst(_.get() => { module: 'tink.state.State', name: 'StateObject' }, _): storeTypedExpr(done); case te: + while (true) + switch e { + case macro (${v}): e = v; + default: break; + } switch e { case macro $i{name}: e = macro @:pos(e.pos) this.$name; default: } switch e { - case macro ${owner}.$name: // TODO: consider checking if the target is valid + case macro ${owner}.$name: var v = typeExpr(owner); if (v.hasThis()) From 26ebd79578d84a24dba74b80918b39636b7200d3 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sun, 12 Dec 2021 09:44:27 +0100 Subject: [PATCH 09/15] Minor. --- src/coconut/ui/internal/Attribute.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coconut/ui/internal/Attribute.hx b/src/coconut/ui/internal/Attribute.hx index 87274b4..49e1e4b 100644 --- a/src/coconut/ui/internal/Attribute.hx +++ b/src/coconut/ui/internal/Attribute.hx @@ -6,7 +6,7 @@ import tink.state.internal.*; @:forward(value, assign) abstract Attribute(Impl) { - public inline function new(compute, ?comparator) + public inline function new(compute, ?comparator #if tink_state.debug , toString #end) this = new Impl(compute, comparator); } From 255e2f24343f5083d69aab1ffc855d3ca1afe2e1 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sun, 12 Dec 2021 09:44:35 +0100 Subject: [PATCH 10/15] Don't generate nulls for optional args. --- src/coconut/ui/macros/ViewBuilder.hx | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/coconut/ui/macros/ViewBuilder.hx b/src/coconut/ui/macros/ViewBuilder.hx index a2baa6a..10a98cc 100644 --- a/src/coconut/ui/macros/ViewBuilder.hx +++ b/src/coconut/ui/macros/ViewBuilder.hx @@ -193,7 +193,20 @@ class ViewBuilder { if (expr == null) expr = macro @:pos(a.pos) null; - initField(slotName, macro new $container($expr, ${comparator} #if tink_state.debug , (_) -> $v{c.target.name} + '#' + this.viewId + '.' + $v{a.name} #end)); + var args = [ + expr, + comparator, + #if tink_state.debug (_) -> $v{c.target.name} + '#' + this.viewId + '.' + $v{a.name} #end + ]; + + #if !tink.state.debug + switch comparator { + case macro null: args.pop(); + default: + } + #end + + initField(slotName, macro new $container($a{args})); var container = TPath(container); add(macro class { @:noCompletion private final $slotName:$container; @@ -522,7 +535,12 @@ class ViewBuilder { } }); - initField(internal, macro new tink.state.State<$t>(${v.expr}, ${state.meta.comparator})); + var args = [v.expr]; + switch state.meta.comparator { + case macro null: + case v: args.push(v); + } + initField(internal, macro new tink.state.State<$t>($a{args})); s.kind = FProp('get', 'set', t, null); } From 3023d91540da8470dabf12791ca5383bf5c19343 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sun, 13 Mar 2022 11:51:51 +0100 Subject: [PATCH 11/15] Unwrap parens for implicit context. --- src/coconut/ui/internal/ImplicitContext.macro.hx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coconut/ui/internal/ImplicitContext.macro.hx b/src/coconut/ui/internal/ImplicitContext.macro.hx index 5802d55..5f925b1 100644 --- a/src/coconut/ui/internal/ImplicitContext.macro.hx +++ b/src/coconut/ui/internal/ImplicitContext.macro.hx @@ -6,11 +6,15 @@ using tink.MacroApi; class ImplicitContext { static function with(e:Expr) { + switch e { + case macro ($v): e = v; + default: + } var exprs = switch e.expr { case EArrayDecl(a): a; default: [e]; }; var entries = [for (e in exprs) switch e { case macro $k => $v: macro @:pos(e.pos) new coconut.ui.internal.ImplicitContext.SingleImplicit($k, function () return $v); - default: e.reject('expected key => value'); + default: e.reject('expected key => value, but got ${e.toString()}'); }]; return macro new coconut.ui.internal.ImplicitContext.ImplicitValues([$a{entries}]); } From ea4675142ac7cf036142b5a6a9fa8c3a8d53e22e Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sun, 13 Mar 2022 15:55:22 +0100 Subject: [PATCH 12/15] Use ObjectMap from tink_state. --- src/coconut/ui/internal/ImplicitContext.hx | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/coconut/ui/internal/ImplicitContext.hx b/src/coconut/ui/internal/ImplicitContext.hx index de51927..2e2a937 100644 --- a/src/coconut/ui/internal/ImplicitContext.hx +++ b/src/coconut/ui/internal/ImplicitContext.hx @@ -5,11 +5,10 @@ using tink.CoreApi; #if macro using tink.MacroApi; #end - class ImplicitContext { final parent:Lazy>; - final slots = new Map, Attribute>(); + final slots = new Mapping>(); public function new(?parent) { this.parent = switch parent { @@ -37,17 +36,14 @@ class ImplicitContext { } public function update(values:ImplicitValues) { - - for (k => slot in slots) - if (!values.exists(k)) slot.assign(null); - - for (k => v in values) - getSlot(k).assign(v); + slots.forEach((slot, k, _) -> if (!values.exists(k)) slot.assign(null)); + values.forEach((v, k, _) -> getSlot(k).assign(v)); } static public macro function with(e); } +private typedef Mapping = tink.state.internal.ObjectMap, T>; abstract TypeKey({}) to {} { @:from static function ofClass(t:Class):TypeKey return cast t; @@ -56,12 +52,15 @@ abstract TypeKey({}) to {} { } @:pure -@:forward(exists, get, keyValueIterator) +@:forward(exists, get, forEach) @:fromHxx( transform = coconut.ui.internal.ImplicitContext.with(_) ) -abstract ImplicitValues(Map, tink.hxx.Expression>) { - public function new(a:Array) this = [for (o in a) o.key => o.val]; +abstract ImplicitValues(Mapping>) { + public function new(a:Array) { + this = new Mapping(); + for (o in a) this[o.key] = o.val; + } } class SingleImplicit { From a74c4cd59ce6a0940199731ecda679c52c5ad0da Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sat, 2 Apr 2022 20:09:26 +0200 Subject: [PATCH 13/15] Slightly better Attribute implementation. --- src/coconut/ui/internal/Attribute.hx | 34 +++++++--------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/coconut/ui/internal/Attribute.hx b/src/coconut/ui/internal/Attribute.hx index 49e1e4b..6fc278f 100644 --- a/src/coconut/ui/internal/Attribute.hx +++ b/src/coconut/ui/internal/Attribute.hx @@ -10,40 +10,22 @@ abstract Attribute(Impl) { this = new Impl(compute, comparator); } -private class Impl implements ObservableObject extends Dispatcher { - +private class Impl extends AutoObservable { final dFault:()->T; - var cur:Null<()->T>; - final comparator:Comparator; - - public var value(get, never):T; - inline function get_value():T - return (this:Observable).value; + final state:State<()->T>; public function new(compute:()->T, ?comparator) { - super(); - this.comparator = comparator; - this.dFault = compute; - } - - public function assign(c:Null<()->T>) - if (c != cur) { - cur = c; - fire(this); - } - - public function getValue():T - return switch cur { + this.state = new State(this.dFault = compute); + super(() -> switch state.value { case null: dFault(); case f: switch f() { case null: dFault(); case v: v; } - } + }, comparator); + } - public function isValid():Bool - return false;//TODO: implement + public function assign(c:Null<()->T>) + state.set(c); - public function getComparator():Comparator - return comparator; } \ No newline at end of file From 0f05ac79990506165767edc2d8623d454ef37a89 Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Sun, 1 May 2022 09:29:18 +0200 Subject: [PATCH 14/15] Add key value iterator to Children. --- src/coconut/ui/internal/Children.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/coconut/ui/internal/Children.hx b/src/coconut/ui/internal/Children.hx index 11b08b1..2071df3 100644 --- a/src/coconut/ui/internal/Children.hx +++ b/src/coconut/ui/internal/Children.hx @@ -32,4 +32,9 @@ abstract Children(Array) from Array { } @:from macro static function ofOther(e:haxe.macro.Expr); + + static final EMPTY = new Array(); + + public inline function keyValueIterator() + return (if (this != null) this else EMPTY).keyValueIterator(); } From 98a1c9d1a07ab54d9d0636f84a12c1969c345e2a Mon Sep 17 00:00:00 2001 From: Juraj Kirchheim Date: Wed, 22 Feb 2023 20:09:36 +0100 Subject: [PATCH 15/15] Catch up with tink_hxx. --- haxe_libraries/tink_core.hxml | 4 ++-- haxe_libraries/tink_hxx.hxml | 4 ++-- src/coconut/ui/macros/Helpers.hx | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/haxe_libraries/tink_core.hxml b/haxe_libraries/tink_core.hxml index f97bc45..37d612f 100644 --- a/haxe_libraries/tink_core.hxml +++ b/haxe_libraries/tink_core.hxml @@ -1,3 +1,3 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_core#33a5b72257d421c0b278973d58805c9ecefea259" into tink_core/2.0.2/github/33a5b72257d421c0b278973d58805c9ecefea259 --cp ${HAXE_LIBCACHE}/tink_core/2.0.2/github/33a5b72257d421c0b278973d58805c9ecefea259/src +# @install: lix --silent download "gh://github.com/haxetink/tink_core#f500203b657859bfde36c49e54f95a0b1fc2b165" into tink_core/2.0.2/github/f500203b657859bfde36c49e54f95a0b1fc2b165 +-cp ${HAXE_LIBCACHE}/tink_core/2.0.2/github/f500203b657859bfde36c49e54f95a0b1fc2b165/src -D tink_core=2.0.2 \ No newline at end of file diff --git a/haxe_libraries/tink_hxx.hxml b/haxe_libraries/tink_hxx.hxml index 97169f4..9a6edb0 100644 --- a/haxe_libraries/tink_hxx.hxml +++ b/haxe_libraries/tink_hxx.hxml @@ -1,6 +1,6 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_hxx#07cada55ff0b550b47f6e1ffb888be62d1e969c4" into tink_hxx/0.25.0/github/07cada55ff0b550b47f6e1ffb888be62d1e969c4 +# @install: lix --silent download "gh://github.com/haxetink/tink_hxx#783a4606516582567d9f6f12505740ba48334c39" into tink_hxx/0.25.0/github/783a4606516582567d9f6f12505740ba48334c39 -lib html-entities -lib tink_anon -lib tink_parse --cp ${HAXE_LIBCACHE}/tink_hxx/0.25.0/github/07cada55ff0b550b47f6e1ffb888be62d1e969c4/src +-cp ${HAXE_LIBCACHE}/tink_hxx/0.25.0/github/783a4606516582567d9f6f12505740ba48334c39/src -D tink_hxx=0.25.0 \ No newline at end of file diff --git a/src/coconut/ui/macros/Helpers.hx b/src/coconut/ui/macros/Helpers.hx index ac9802e..7407e80 100644 --- a/src/coconut/ui/macros/Helpers.hx +++ b/src/coconut/ui/macros/Helpers.hx @@ -27,7 +27,6 @@ class Helpers { defaultExtension: 'hxx', noControlStructures: false, defaultSwitchTarget: macro __data__, - isVoid: ctx.isVoid, fragment: fragment, treatNested: function (children) return ctx.generateRoot.bind(children).bounce(), })