@treenity/react 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/dist/AclEditor.d.ts +11 -0
  2. package/dist/AclEditor.d.ts.map +1 -0
  3. package/dist/AclEditor.js +152 -0
  4. package/dist/AclEditor.js.map +1 -0
  5. package/dist/App.d.ts +2 -0
  6. package/dist/App.d.ts.map +1 -0
  7. package/dist/App.js +521 -0
  8. package/dist/App.js.map +1 -0
  9. package/dist/Inspector.d.ts +12 -0
  10. package/dist/Inspector.d.ts.map +1 -0
  11. package/dist/Inspector.js +360 -0
  12. package/dist/Inspector.js.map +1 -0
  13. package/dist/Tree.d.ts +16 -0
  14. package/dist/Tree.d.ts.map +1 -0
  15. package/dist/Tree.js +100 -0
  16. package/dist/Tree.js.map +1 -0
  17. package/dist/ViewPage.d.ts +5 -0
  18. package/dist/ViewPage.d.ts.map +1 -0
  19. package/dist/ViewPage.js +13 -0
  20. package/dist/ViewPage.js.map +1 -0
  21. package/dist/bind/computed.d.ts +9 -0
  22. package/dist/bind/computed.d.ts.map +1 -0
  23. package/dist/bind/computed.js +61 -0
  24. package/dist/bind/computed.js.map +1 -0
  25. package/dist/bind/engine.d.ts +3 -0
  26. package/dist/bind/engine.d.ts.map +1 -0
  27. package/dist/bind/engine.js +184 -0
  28. package/dist/bind/engine.js.map +1 -0
  29. package/dist/bind/eval.d.ts +13 -0
  30. package/dist/bind/eval.d.ts.map +1 -0
  31. package/dist/bind/eval.js +97 -0
  32. package/dist/bind/eval.js.map +1 -0
  33. package/dist/bind/hook.d.ts +8 -0
  34. package/dist/bind/hook.d.ts.map +1 -0
  35. package/dist/bind/hook.js +99 -0
  36. package/dist/bind/hook.js.map +1 -0
  37. package/dist/bind/parse.d.ts +19 -0
  38. package/dist/bind/parse.d.ts.map +1 -0
  39. package/dist/bind/parse.js +86 -0
  40. package/dist/bind/parse.js.map +1 -0
  41. package/dist/bind/pipes.d.ts +4 -0
  42. package/dist/bind/pipes.d.ts.map +1 -0
  43. package/dist/bind/pipes.js +43 -0
  44. package/dist/bind/pipes.js.map +1 -0
  45. package/dist/cache.d.ts +27 -0
  46. package/dist/cache.d.ts.map +1 -0
  47. package/dist/cache.js +236 -0
  48. package/dist/cache.js.map +1 -0
  49. package/dist/client-tree.d.ts +9 -0
  50. package/dist/client-tree.d.ts.map +1 -0
  51. package/dist/client-tree.js +14 -0
  52. package/dist/client-tree.js.map +1 -0
  53. package/dist/client.d.ts +2 -0
  54. package/dist/client.d.ts.map +1 -0
  55. package/dist/client.js +10 -0
  56. package/dist/client.js.map +1 -0
  57. package/dist/components/ui/accordion.d.ts +8 -0
  58. package/dist/components/ui/accordion.d.ts.map +1 -0
  59. package/dist/components/ui/accordion.js +18 -0
  60. package/dist/components/ui/accordion.js.map +1 -0
  61. package/dist/components/ui/badge.d.ts +10 -0
  62. package/dist/components/ui/badge.d.ts.map +1 -0
  63. package/dist/components/ui/badge.js +19 -0
  64. package/dist/components/ui/badge.js.map +1 -0
  65. package/dist/components/ui/button.d.ts +11 -0
  66. package/dist/components/ui/button.d.ts.map +1 -0
  67. package/dist/components/ui/button.js +31 -0
  68. package/dist/components/ui/button.js.map +1 -0
  69. package/dist/components/ui/checkbox.d.ts +4 -0
  70. package/dist/components/ui/checkbox.d.ts.map +1 -0
  71. package/dist/components/ui/checkbox.js +7 -0
  72. package/dist/components/ui/checkbox.js.map +1 -0
  73. package/dist/components/ui/dialog.d.ts +18 -0
  74. package/dist/components/ui/dialog.d.ts.map +1 -0
  75. package/dist/components/ui/dialog.js +37 -0
  76. package/dist/components/ui/dialog.js.map +1 -0
  77. package/dist/components/ui/drawer.d.ts +14 -0
  78. package/dist/components/ui/drawer.d.ts.map +1 -0
  79. package/dist/components/ui/drawer.js +35 -0
  80. package/dist/components/ui/drawer.js.map +1 -0
  81. package/dist/components/ui/input.d.ts +4 -0
  82. package/dist/components/ui/input.d.ts.map +1 -0
  83. package/dist/components/ui/input.js +7 -0
  84. package/dist/components/ui/input.js.map +1 -0
  85. package/dist/components/ui/label.d.ts +5 -0
  86. package/dist/components/ui/label.d.ts.map +1 -0
  87. package/dist/components/ui/label.js +8 -0
  88. package/dist/components/ui/label.js.map +1 -0
  89. package/dist/components/ui/popover.d.ts +11 -0
  90. package/dist/components/ui/popover.d.ts.map +1 -0
  91. package/dist/components/ui/popover.js +26 -0
  92. package/dist/components/ui/popover.js.map +1 -0
  93. package/dist/components/ui/progress.d.ts +5 -0
  94. package/dist/components/ui/progress.d.ts.map +1 -0
  95. package/dist/components/ui/progress.js +9 -0
  96. package/dist/components/ui/progress.js.map +1 -0
  97. package/dist/components/ui/select.d.ts +16 -0
  98. package/dist/components/ui/select.d.ts.map +1 -0
  99. package/dist/components/ui/select.js +39 -0
  100. package/dist/components/ui/select.js.map +1 -0
  101. package/dist/components/ui/slider.d.ts +5 -0
  102. package/dist/components/ui/slider.d.ts.map +1 -0
  103. package/dist/components/ui/slider.js +15 -0
  104. package/dist/components/ui/slider.js.map +1 -0
  105. package/dist/components/ui/sonner.d.ts +4 -0
  106. package/dist/components/ui/sonner.d.ts.map +1 -0
  107. package/dist/components/ui/sonner.js +21 -0
  108. package/dist/components/ui/sonner.js.map +1 -0
  109. package/dist/components/ui/switch.d.ts +7 -0
  110. package/dist/components/ui/switch.d.ts.map +1 -0
  111. package/dist/components/ui/switch.js +9 -0
  112. package/dist/components/ui/switch.js.map +1 -0
  113. package/dist/components/ui/textarea.d.ts +4 -0
  114. package/dist/components/ui/textarea.d.ts.map +1 -0
  115. package/dist/components/ui/textarea.js +7 -0
  116. package/dist/components/ui/textarea.js.map +1 -0
  117. package/dist/components/ui/tooltip.d.ts +8 -0
  118. package/dist/components/ui/tooltip.d.ts.map +1 -0
  119. package/dist/components/ui/tooltip.js +18 -0
  120. package/dist/components/ui/tooltip.js.map +1 -0
  121. package/dist/context/index.d.ts +31 -0
  122. package/dist/context/index.d.ts.map +1 -0
  123. package/dist/context/index.js +98 -0
  124. package/dist/context/index.js.map +1 -0
  125. package/dist/context.d.ts +2 -0
  126. package/dist/context.d.ts.map +1 -0
  127. package/dist/context.js +2 -0
  128. package/dist/context.js.map +1 -0
  129. package/dist/hooks.d.ts +21 -0
  130. package/dist/hooks.d.ts.map +1 -0
  131. package/dist/hooks.js +156 -0
  132. package/dist/hooks.js.map +1 -0
  133. package/dist/idb.d.ts +13 -0
  134. package/dist/idb.d.ts.map +1 -0
  135. package/dist/idb.js +67 -0
  136. package/dist/idb.js.map +1 -0
  137. package/dist/lib/minimd.d.ts +3 -0
  138. package/dist/lib/minimd.d.ts.map +1 -0
  139. package/dist/lib/minimd.js +97 -0
  140. package/dist/lib/minimd.js.map +1 -0
  141. package/dist/lib/utils.d.ts +3 -0
  142. package/dist/lib/utils.d.ts.map +1 -0
  143. package/dist/lib/utils.js +6 -0
  144. package/dist/lib/utils.js.map +1 -0
  145. package/dist/load-client.d.ts +2 -0
  146. package/dist/load-client.d.ts.map +1 -0
  147. package/dist/load-client.js +6 -0
  148. package/dist/load-client.js.map +1 -0
  149. package/dist/main.d.ts +4 -0
  150. package/dist/main.d.ts.map +1 -0
  151. package/dist/main.js +16 -0
  152. package/dist/main.js.map +1 -0
  153. package/dist/mods/editor-ui/client.d.ts +6 -0
  154. package/dist/mods/editor-ui/client.d.ts.map +1 -0
  155. package/dist/mods/editor-ui/client.js +8 -0
  156. package/dist/mods/editor-ui/client.js.map +1 -0
  157. package/dist/mods/editor-ui/default-view.d.ts +2 -0
  158. package/dist/mods/editor-ui/default-view.d.ts.map +1 -0
  159. package/dist/mods/editor-ui/default-view.js +71 -0
  160. package/dist/mods/editor-ui/default-view.js.map +1 -0
  161. package/dist/mods/editor-ui/dir-view.d.ts +2 -0
  162. package/dist/mods/editor-ui/dir-view.d.ts.map +1 -0
  163. package/dist/mods/editor-ui/dir-view.js +42 -0
  164. package/dist/mods/editor-ui/dir-view.js.map +1 -0
  165. package/dist/mods/editor-ui/form-fields.d.ts +6 -0
  166. package/dist/mods/editor-ui/form-fields.d.ts.map +1 -0
  167. package/dist/mods/editor-ui/form-fields.js +401 -0
  168. package/dist/mods/editor-ui/form-fields.js.map +1 -0
  169. package/dist/mods/editor-ui/layout-view.d.ts +2 -0
  170. package/dist/mods/editor-ui/layout-view.d.ts.map +1 -0
  171. package/dist/mods/editor-ui/layout-view.js +22 -0
  172. package/dist/mods/editor-ui/layout-view.js.map +1 -0
  173. package/dist/mods/editor-ui/list-items.d.ts +2 -0
  174. package/dist/mods/editor-ui/list-items.d.ts.map +1 -0
  175. package/dist/mods/editor-ui/list-items.js +38 -0
  176. package/dist/mods/editor-ui/list-items.js.map +1 -0
  177. package/dist/mods/editor-ui/node-utils.d.ts +10 -0
  178. package/dist/mods/editor-ui/node-utils.d.ts.map +1 -0
  179. package/dist/mods/editor-ui/node-utils.js +76 -0
  180. package/dist/mods/editor-ui/node-utils.js.map +1 -0
  181. package/dist/mods/editor-ui/user-view.d.ts +2 -0
  182. package/dist/mods/editor-ui/user-view.d.ts.map +1 -0
  183. package/dist/mods/editor-ui/user-view.js +47 -0
  184. package/dist/mods/editor-ui/user-view.js.map +1 -0
  185. package/dist/mods/treenity/client.d.ts +4 -0
  186. package/dist/mods/treenity/client.d.ts.map +1 -0
  187. package/dist/mods/treenity/client.js +6 -0
  188. package/dist/mods/treenity/client.js.map +1 -0
  189. package/dist/mods/treenity/groups/index.d.ts +2 -0
  190. package/dist/mods/treenity/groups/index.d.ts.map +1 -0
  191. package/dist/mods/treenity/groups/index.js +27 -0
  192. package/dist/mods/treenity/groups/index.js.map +1 -0
  193. package/dist/mods/treenity/preview.d.ts +6 -0
  194. package/dist/mods/treenity/preview.d.ts.map +1 -0
  195. package/dist/mods/treenity/preview.js +95 -0
  196. package/dist/mods/treenity/preview.js.map +1 -0
  197. package/dist/mods/treenity/ref-view.d.ts +2 -0
  198. package/dist/mods/treenity/ref-view.d.ts.map +1 -0
  199. package/dist/mods/treenity/ref-view.js +29 -0
  200. package/dist/mods/treenity/ref-view.js.map +1 -0
  201. package/dist/mods/treenity/schema-form.d.ts +2 -0
  202. package/dist/mods/treenity/schema-form.d.ts.map +1 -0
  203. package/dist/mods/treenity/schema-form.js +38 -0
  204. package/dist/mods/treenity/schema-form.js.map +1 -0
  205. package/dist/mods/treenity/seed.d.ts +2 -0
  206. package/dist/mods/treenity/seed.d.ts.map +1 -0
  207. package/dist/mods/treenity/seed.js +53 -0
  208. package/dist/mods/treenity/seed.js.map +1 -0
  209. package/dist/mods/treenity/server.d.ts +2 -0
  210. package/dist/mods/treenity/server.d.ts.map +1 -0
  211. package/dist/mods/treenity/server.js +2 -0
  212. package/dist/mods/treenity/server.js.map +1 -0
  213. package/dist/mods/treenity/type-view.d.ts +2 -0
  214. package/dist/mods/treenity/type-view.d.ts.map +1 -0
  215. package/dist/mods/treenity/type-view.js +36 -0
  216. package/dist/mods/treenity/type-view.js.map +1 -0
  217. package/dist/remote-tree.d.ts +6 -0
  218. package/dist/remote-tree.d.ts.map +1 -0
  219. package/dist/remote-tree.js +18 -0
  220. package/dist/remote-tree.js.map +1 -0
  221. package/dist/schema-loader.d.ts +19 -0
  222. package/dist/schema-loader.d.ts.map +1 -0
  223. package/dist/schema-loader.js +63 -0
  224. package/dist/schema-loader.js.map +1 -0
  225. package/dist/trpc.d.ts +187 -0
  226. package/dist/trpc.d.ts.map +1 -0
  227. package/dist/trpc.js +21 -0
  228. package/dist/trpc.js.map +1 -0
  229. package/package.json +88 -0
  230. package/src/AclEditor.tsx +330 -0
  231. package/src/App.tsx +775 -0
  232. package/src/CLAUDE.md +16 -0
  233. package/src/Inspector.tsx +857 -0
  234. package/src/Tree.tsx +237 -0
  235. package/src/ViewPage.tsx +45 -0
  236. package/src/bind/bind.test.ts +316 -0
  237. package/src/bind/computed.ts +64 -0
  238. package/src/bind/engine.ts +198 -0
  239. package/src/bind/eval.ts +108 -0
  240. package/src/bind/hook.ts +112 -0
  241. package/src/bind/parse.ts +104 -0
  242. package/src/bind/pipes.ts +71 -0
  243. package/src/cache.test.ts +139 -0
  244. package/src/cache.ts +244 -0
  245. package/src/client-tree.test.ts +116 -0
  246. package/src/client-tree.ts +24 -0
  247. package/src/client.ts +11 -0
  248. package/src/components/ui/accordion.tsx +63 -0
  249. package/src/components/ui/badge.tsx +27 -0
  250. package/src/components/ui/button.tsx +44 -0
  251. package/src/components/ui/checkbox.tsx +19 -0
  252. package/src/components/ui/dialog.tsx +156 -0
  253. package/src/components/ui/drawer.tsx +132 -0
  254. package/src/components/ui/input.tsx +19 -0
  255. package/src/components/ui/label.tsx +21 -0
  256. package/src/components/ui/popover.tsx +86 -0
  257. package/src/components/ui/progress.tsx +30 -0
  258. package/src/components/ui/select.tsx +189 -0
  259. package/src/components/ui/slider.tsx +62 -0
  260. package/src/components/ui/sonner.tsx +32 -0
  261. package/src/components/ui/switch.tsx +34 -0
  262. package/src/components/ui/textarea.tsx +17 -0
  263. package/src/components/ui/tooltip.tsx +56 -0
  264. package/src/context/index.tsx +131 -0
  265. package/src/context.ts +1 -0
  266. package/src/hooks.ts +208 -0
  267. package/src/idb.ts +80 -0
  268. package/src/index.html +14 -0
  269. package/src/lib/minimd.css +28 -0
  270. package/src/lib/minimd.ts +95 -0
  271. package/src/lib/utils.ts +6 -0
  272. package/src/load-client.ts +5 -0
  273. package/src/main.tsx +22 -0
  274. package/src/mods/editor-ui/CLAUDE.md +3 -0
  275. package/src/mods/editor-ui/client.ts +8 -0
  276. package/src/mods/editor-ui/default-view.tsx +148 -0
  277. package/src/mods/editor-ui/dir-view.tsx +91 -0
  278. package/src/mods/editor-ui/form-fields.tsx +861 -0
  279. package/src/mods/editor-ui/layout-view.tsx +62 -0
  280. package/src/mods/editor-ui/list-items.tsx +63 -0
  281. package/src/mods/editor-ui/node-utils.ts +84 -0
  282. package/src/mods/editor-ui/user-view.tsx +101 -0
  283. package/src/mods/treenity/CLAUDE.md +7 -0
  284. package/src/mods/treenity/client.ts +6 -0
  285. package/src/mods/treenity/groups/index.tsx +65 -0
  286. package/src/mods/treenity/preview.tsx +133 -0
  287. package/src/mods/treenity/ref-view.tsx +87 -0
  288. package/src/mods/treenity/schema-form.tsx +65 -0
  289. package/src/mods/treenity/seed.ts +56 -0
  290. package/src/mods/treenity/server.ts +1 -0
  291. package/src/mods/treenity/type-view.tsx +116 -0
  292. package/src/remote-tree.test.ts +142 -0
  293. package/src/remote-tree.ts +25 -0
  294. package/src/schema-loader.ts +84 -0
  295. package/src/style.css +1269 -0
  296. package/src/trpc.ts +27 -0
  297. package/src/vite-env.d.ts +3 -0
@@ -0,0 +1,61 @@
1
+ // Computed store — separate reactive layer for $ref+$map resolved values
2
+ // Dual: valtio proxies for field-level React reactivity (useSnapshot),
3
+ // plus synchronous manual subs for bind engine and non-React consumers.
4
+ // Never persisted to IDB or server. No Meteor trap.
5
+ import { proxy, snapshot } from 'valtio/vanilla';
6
+ const proxies = new Map();
7
+ const subs = new Map();
8
+ function ensure(path) {
9
+ let p = proxies.get(path);
10
+ if (!p) {
11
+ p = proxy({});
12
+ proxies.set(path, p);
13
+ }
14
+ return p;
15
+ }
16
+ function fire(path) {
17
+ const s = subs.get(path);
18
+ if (s)
19
+ for (const cb of s)
20
+ cb();
21
+ }
22
+ export function getComputed(path) {
23
+ const p = proxies.get(path);
24
+ if (!p)
25
+ return undefined;
26
+ return snapshot(p);
27
+ }
28
+ /** Get the raw valtio proxy — for useSnapshot in hooks */
29
+ export function getComputedProxy(path) {
30
+ return proxies.get(path);
31
+ }
32
+ export function setComputed(path, field, value) {
33
+ const p = ensure(path);
34
+ if (Object.is(p[field], value))
35
+ return; // no-op if unchanged
36
+ p[field] = value;
37
+ fire(path); // synchronous for non-React consumers
38
+ }
39
+ export function clearComputed(path) {
40
+ const p = proxies.get(path);
41
+ if (p) {
42
+ for (const k of Object.keys(p))
43
+ delete p[k];
44
+ proxies.delete(path);
45
+ }
46
+ fire(path);
47
+ }
48
+ export function subscribeComputed(path, cb) {
49
+ if (!subs.has(path))
50
+ subs.set(path, new Set());
51
+ subs.get(path).add(cb);
52
+ return () => {
53
+ const s = subs.get(path);
54
+ if (s) {
55
+ s.delete(cb);
56
+ if (!s.size)
57
+ subs.delete(path);
58
+ }
59
+ };
60
+ }
61
+ //# sourceMappingURL=computed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed.js","sourceRoot":"","sources":["../../src/bind/computed.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,uEAAuE;AACvE,wEAAwE;AACxE,oDAAoD;AAEpD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAIjD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;AAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoB,CAAC;AAEzC,SAAS,MAAM,CAAC,IAAY;IAC1B,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,GAAG,KAAK,CAA0B,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,IAAI,CAAC,IAAY;IACxB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,CAAC;QAAE,KAAK,MAAM,EAAE,IAAI,CAAC;YAAE,EAAE,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,OAAO,QAAQ,CAAC,CAAC,CAA4B,CAAC;AAChD,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,KAAa,EAAE,KAAc;IACrE,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,qBAAqB;IAC7D,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;IACjB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,sCAAsC;AACpD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,EAAE,CAAC;QACN,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,CAAC;AACb,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,EAAO;IACrD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IAC/C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxB,OAAO,GAAG,EAAE;QACV,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,EAAE,CAAC;YACN,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACb,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Start the binding engine. Returns cleanup function. */
2
+ export declare function startBindEngine(): () => void;
3
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/bind/engine.ts"],"names":[],"mappings":"AA4JA,0DAA0D;AAC1D,wBAAgB,eAAe,IAAI,MAAM,IAAI,CAwC5C"}
@@ -0,0 +1,184 @@
1
+ // Binding engine — scans cache for $ref+$map fields, subscribes to sources,
2
+ // evaluates on change, writes to computed store.
3
+ // Supports $ref: "." (self) and @/path.field ref args in $map expressions.
4
+ import * as cache from '#cache';
5
+ import { trpc } from '#trpc';
6
+ import { isRef } from '@treenity/core/core';
7
+ import { clearComputed, getComputed, setComputed } from './computed';
8
+ import { evaluateRef, extractArgPaths, hasOnce, isCollectionRef } from './eval';
9
+ // Active bindings: targetPath → field → { ref, unsub }
10
+ const active = new Map();
11
+ // Collection paths with active SSE watches
12
+ const watchedCollections = new Set();
13
+ // Single-node paths already fetched
14
+ const fetchedNodes = new Set();
15
+ const ctx = {
16
+ getNode: (p) => cache.get(p),
17
+ getChildren: (p) => cache.getChildren(p),
18
+ };
19
+ /** Fetch collection children from server into cache */
20
+ function fetchChildren(path) {
21
+ trpc.getChildren
22
+ .query({ path, watch: true, watchNew: true })
23
+ .then((r) => cache.putMany(r.items, path));
24
+ }
25
+ /** Ensure source data is in cache by fetching from server */
26
+ function ensureInCache(path, collection) {
27
+ if (collection) {
28
+ if (!watchedCollections.has(path)) {
29
+ watchedCollections.add(path);
30
+ fetchChildren(path);
31
+ }
32
+ }
33
+ else {
34
+ if (fetchedNodes.has(path))
35
+ return;
36
+ fetchedNodes.add(path);
37
+ trpc.get.query({ path }).then((n) => {
38
+ if (n)
39
+ cache.put(n);
40
+ });
41
+ }
42
+ }
43
+ function evaluate(targetPath, field, ref) {
44
+ // Resolve $ref: "." → actual target path before eval
45
+ const resolved = ref.$ref === '.' ? { ...ref, $ref: targetPath } : ref;
46
+ try {
47
+ const value = evaluateRef(resolved, ctx);
48
+ setComputed(targetPath, field, value);
49
+ }
50
+ catch (e) {
51
+ console.warn(`[bind] eval error ${targetPath}.${field}:`, e);
52
+ }
53
+ }
54
+ function registerBinding(targetPath, field, ref) {
55
+ const once = hasOnce(ref);
56
+ const unsubs = [];
57
+ const cb = () => evaluate(targetPath, field, ref);
58
+ const mainPath = ref.$ref === '.' ? targetPath : ref.$ref;
59
+ const collection = isCollectionRef(ref);
60
+ if (mainPath !== targetPath) {
61
+ ensureInCache(mainPath, collection);
62
+ }
63
+ // `once` — evaluate once, no reactive subscription
64
+ if (!once) {
65
+ unsubs.push(collection
66
+ ? cache.subscribeChildren(mainPath, cb)
67
+ : cache.subscribePath(mainPath, cb));
68
+ for (const argPath of extractArgPaths(ref)) {
69
+ unsubs.push(cache.subscribePath(argPath, cb));
70
+ ensureInCache(argPath, false);
71
+ }
72
+ }
73
+ if (!active.has(targetPath))
74
+ active.set(targetPath, new Map());
75
+ active.get(targetPath).set(field, { ref, unsub: () => unsubs.forEach(u => u()) });
76
+ evaluate(targetPath, field, ref);
77
+ }
78
+ function unregisterAll(targetPath) {
79
+ const bindings = active.get(targetPath);
80
+ if (!bindings)
81
+ return;
82
+ for (const { unsub } of bindings.values())
83
+ unsub();
84
+ active.delete(targetPath);
85
+ clearComputed(targetPath);
86
+ }
87
+ /** Scan a single node for $ref+$map fields, register/update bindings */
88
+ function scanNode(node) {
89
+ const path = node.$path;
90
+ const newRefs = new Map();
91
+ // Scan node-level fields
92
+ for (const [key, value] of Object.entries(node)) {
93
+ if (key.startsWith('$'))
94
+ continue;
95
+ if (isRef(value) && value.$map) {
96
+ newRefs.set(key, value);
97
+ }
98
+ // Scan sub-component fields
99
+ if (typeof value === 'object' && value !== null && '$type' in value) {
100
+ for (const [subKey, subVal] of Object.entries(value)) {
101
+ if (subKey.startsWith('$'))
102
+ continue;
103
+ if (isRef(subVal) && subVal.$map) {
104
+ newRefs.set(`${key}.${subKey}`, subVal);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ const existing = active.get(path);
110
+ // No bindings before or after — nothing to do
111
+ if (!existing && newRefs.size === 0)
112
+ return;
113
+ // Remove stale bindings
114
+ if (existing) {
115
+ for (const [field, { unsub }] of existing) {
116
+ if (!newRefs.has(field)) {
117
+ unsub();
118
+ existing.delete(field);
119
+ }
120
+ }
121
+ if (existing.size === 0 && newRefs.size === 0) {
122
+ active.delete(path);
123
+ clearComputed(path);
124
+ return;
125
+ }
126
+ }
127
+ // Register new/updated bindings
128
+ for (const [field, ref] of newRefs) {
129
+ const prev = existing?.get(field);
130
+ // Skip if same expression
131
+ if (prev && prev.ref.$ref === ref.$ref && prev.ref.$map === ref.$map)
132
+ continue;
133
+ // Unregister old
134
+ if (prev)
135
+ prev.unsub();
136
+ registerBinding(path, field, ref);
137
+ }
138
+ }
139
+ function handleRemove(path) {
140
+ unregisterAll(path);
141
+ }
142
+ /** Start the binding engine. Returns cleanup function. */
143
+ export function startBindEngine() {
144
+ // 1. Scan all existing nodes in cache
145
+ for (const [, node] of cache.raw()) {
146
+ scanNode(node);
147
+ }
148
+ // 2. Reactive: scan each node as it arrives/changes — instant, no polling
149
+ const unsubPut = cache.onNodePut((path) => {
150
+ const node = cache.get(path);
151
+ if (node)
152
+ scanNode(node);
153
+ });
154
+ // 3. Detect removed nodes — clean up stale bindings
155
+ const unsubGlobal = cache.subscribeGlobal(() => {
156
+ for (const path of active.keys()) {
157
+ if (!cache.get(path))
158
+ handleRemove(path);
159
+ }
160
+ });
161
+ // Dev debug — inspect binding engine state from console
162
+ if (typeof window !== 'undefined') {
163
+ window.__bind = {
164
+ active: () => Object.fromEntries([...active].map(([k, v]) => [k, [...v.keys()]])),
165
+ watched: () => [...watchedCollections],
166
+ fetched: () => [...fetchedNodes],
167
+ computed: () => {
168
+ const result = {};
169
+ for (const p of active.keys())
170
+ result[p] = getComputed(p);
171
+ return result;
172
+ },
173
+ };
174
+ }
175
+ return () => {
176
+ unsubPut();
177
+ unsubGlobal();
178
+ for (const path of [...active.keys()])
179
+ unregisterAll(path);
180
+ watchedCollections.clear();
181
+ fetchedNodes.clear();
182
+ };
183
+ }
184
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/bind/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { NodeData, Ref } from '@treenity/core/core';
2
+ export type BindCtx = {
3
+ getNode: (path: string) => NodeData | undefined;
4
+ getChildren: (path: string) => NodeData[];
5
+ };
6
+ export declare function evaluateRef(ref: Ref, ctx: BindCtx): unknown;
7
+ /** Check if first pipe in $map is a collection pipe (needs children subscription) */
8
+ export declare function isCollectionRef(ref: Ref): boolean;
9
+ /** Check if $map contains `once` pipe — disables reactive subscription */
10
+ export declare function hasOnce(ref: Ref): boolean;
11
+ /** Extract all external #/path refs from a $map expression (for subscriptions) */
12
+ export declare function extractArgPaths(ref: Ref): string[];
13
+ //# sourceMappingURL=eval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../src/bind/eval.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAIzD,MAAM,MAAM,OAAO,GAAG;IACpB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAC;IAChD,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;CAC3C,CAAC;AA6BF,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAmC3D;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAKjD;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAIzC;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,EAAE,CAclD"}
@@ -0,0 +1,97 @@
1
+ // $ref + $map evaluator
2
+ // Resolves source from $ref, applies $map pipeline
3
+ // #field (self) and #/path.field (external) args resolved from context
4
+ import { isRefArg, parseMapExpr } from './parse';
5
+ import { getPipe } from './pipes';
6
+ // Collection pipe names — when first step is one of these, resolve source as children
7
+ const COLLECTION_PIPES = new Set(['last', 'first', 'count', 'avg', 'max', 'min', 'sum', 'map']);
8
+ // Parsed expression cache
9
+ const exprCache = new Map();
10
+ function getCachedExpr(map) {
11
+ let expr = exprCache.get(map);
12
+ if (!expr) {
13
+ expr = parseMapExpr(map);
14
+ exprCache.set(map, expr);
15
+ }
16
+ return expr;
17
+ }
18
+ /** Resolve a pipe argument — ref args looked up from context, scalars pass through */
19
+ function resolveArg(arg, ctx, refPath) {
20
+ if (!isRefArg(arg))
21
+ return arg;
22
+ const path = arg.$ref === '.' ? refPath : arg.$ref;
23
+ let val = ctx.getNode(path);
24
+ for (const f of arg.fields) {
25
+ if (val == null || typeof val !== 'object')
26
+ return undefined;
27
+ val = val[f];
28
+ }
29
+ return val;
30
+ }
31
+ export function evaluateRef(ref, ctx) {
32
+ // Plain ref without $map — resolve to node
33
+ if (!ref.$map) {
34
+ return ctx.getNode(ref.$ref);
35
+ }
36
+ const expr = getCachedExpr(ref.$map);
37
+ const firstStep = expr.steps[0];
38
+ // Determine source: children (if first pipe is collection) or single node
39
+ let value;
40
+ if (firstStep?.type === 'pipe' && COLLECTION_PIPES.has(firstStep.name)) {
41
+ value = ctx.getChildren(ref.$ref);
42
+ }
43
+ else {
44
+ value = ctx.getNode(ref.$ref);
45
+ }
46
+ // Apply pipeline left-to-right
47
+ for (const step of expr.steps) {
48
+ if (value === undefined || value === null)
49
+ return undefined;
50
+ if (step.type === 'field') {
51
+ value = value[step.name];
52
+ }
53
+ else {
54
+ const fn = getPipe(step.name);
55
+ if (!fn) {
56
+ console.warn(`[bind] unknown pipe: ${step.name}`);
57
+ return undefined;
58
+ }
59
+ const resolved = step.args.map(a => resolveArg(a, ctx, ref.$ref));
60
+ value = fn(value, ...resolved);
61
+ }
62
+ }
63
+ return value;
64
+ }
65
+ /** Check if first pipe in $map is a collection pipe (needs children subscription) */
66
+ export function isCollectionRef(ref) {
67
+ if (!ref.$map)
68
+ return false;
69
+ const expr = getCachedExpr(ref.$map);
70
+ const first = expr.steps[0];
71
+ return first?.type === 'pipe' && COLLECTION_PIPES.has(first.name);
72
+ }
73
+ /** Check if $map contains `once` pipe — disables reactive subscription */
74
+ export function hasOnce(ref) {
75
+ if (!ref.$map)
76
+ return false;
77
+ const expr = getCachedExpr(ref.$map);
78
+ return expr.steps.some(s => s.type === 'pipe' && s.name === 'once');
79
+ }
80
+ /** Extract all external #/path refs from a $map expression (for subscriptions) */
81
+ export function extractArgPaths(ref) {
82
+ if (!ref.$map)
83
+ return [];
84
+ const expr = getCachedExpr(ref.$map);
85
+ const paths = [];
86
+ for (const step of expr.steps) {
87
+ if (step.type === 'pipe') {
88
+ for (const arg of step.args) {
89
+ if (isRefArg(arg) && arg.$ref !== '.') {
90
+ paths.push(arg.$ref);
91
+ }
92
+ }
93
+ }
94
+ }
95
+ return paths;
96
+ }
97
+ //# sourceMappingURL=eval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.js","sourceRoot":"","sources":["../../src/bind/eval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type NodeData } from '@treenity/core/core';
2
+ /** Reactive access to computed binding values for a node */
3
+ export declare function useComputed(path: string): Record<string, unknown>;
4
+ /** Node with computed bindings merged — raw + computed overlay */
5
+ export declare function useResolvedNode(path: string): [NodeData | undefined, (next: NodeData) => Promise<void>];
6
+ /** Evaluate a $ref+$map expression reactively — no node needed */
7
+ export declare function useEvalRef(path: string, map: string): unknown;
8
+ //# sourceMappingURL=hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/bind/hook.ts"],"names":[],"mappings":"AAIA,OAAO,EAAS,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAS3D,4DAA4D;AAC5D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUjE;AAED,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,QAAQ,GAAG,SAAS,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAkDvG;AAOD,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CA0B7D"}
@@ -0,0 +1,99 @@
1
+ // React hooks for computed bindings
2
+ import * as cache from '#cache';
3
+ import { set, usePath } from '#hooks';
4
+ import { isRef } from '@treenity/core/core';
5
+ import { useCallback, useMemo, useSyncExternalStore } from 'react';
6
+ import { useSnapshot } from 'valtio';
7
+ import { proxy } from 'valtio/vanilla';
8
+ import { getComputed, getComputedProxy, subscribeComputed } from './computed';
9
+ import { evaluateRef, extractArgPaths, isCollectionRef } from './eval';
10
+ const EMPTY_PROXY = proxy({});
11
+ /** Reactive access to computed binding values for a node */
12
+ export function useComputed(path) {
13
+ // Structural: detect proxy creation (first computed value for this path)
14
+ useSyncExternalStore(useCallback((cb) => subscribeComputed(path, cb), [path]), useCallback(() => getComputed(path), [path]));
15
+ // Field-level: re-render only when accessed computed fields change
16
+ const p = getComputedProxy(path);
17
+ return useSnapshot(p ?? EMPTY_PROXY);
18
+ }
19
+ /** Node with computed bindings merged — raw + computed overlay */
20
+ export function useResolvedNode(path) {
21
+ const node = usePath(path);
22
+ const computed = useComputed(path);
23
+ if (!node)
24
+ return [undefined, set];
25
+ // Check if node has any $ref+$map bindings that need resolving
26
+ const hasComputed = Object.keys(computed).length > 0;
27
+ const hasBindings = Object.values(node).some(v => isRef(v) && v.$map);
28
+ if (!hasComputed && !hasBindings)
29
+ return [node, set];
30
+ const merged = { ...node };
31
+ // Apply computed values
32
+ for (const [key, value] of Object.entries(computed)) {
33
+ // Support dotted keys for sub-component fields (e.g. "mesh.width")
34
+ if (key.includes('.')) {
35
+ const [comp, field] = key.split('.');
36
+ if (merged[comp] && typeof merged[comp] === 'object') {
37
+ merged[comp] = { ...merged[comp], [field]: value };
38
+ }
39
+ }
40
+ else {
41
+ merged[key] = value;
42
+ }
43
+ }
44
+ // Strip unresolved $ref+$map bindings — computed not ready yet, use 0 default
45
+ // Without this, raw ref objects leak to consumers (e.g. Three.js rotation={[0, {$ref:...}, 0]} → NaN)
46
+ for (const key of Object.keys(merged)) {
47
+ if (key.startsWith('$'))
48
+ continue;
49
+ const v = merged[key];
50
+ if (isRef(v) && v.$map) {
51
+ merged[key] = 0;
52
+ }
53
+ // Sub-component fields
54
+ if (v && typeof v === 'object' && !isRef(v) && '$type' in v) {
55
+ let changed = false;
56
+ const comp = { ...v };
57
+ for (const sk of Object.keys(comp)) {
58
+ if (sk.startsWith('$'))
59
+ continue;
60
+ if (isRef(comp[sk]) && comp[sk].$map) {
61
+ comp[sk] = 0;
62
+ changed = true;
63
+ }
64
+ }
65
+ if (changed)
66
+ merged[key] = comp;
67
+ }
68
+ }
69
+ return [merged, set];
70
+ }
71
+ const evalCtx = {
72
+ getNode: (p) => cache.get(p),
73
+ getChildren: (p) => cache.getChildren(p),
74
+ };
75
+ /** Evaluate a $ref+$map expression reactively — no node needed */
76
+ export function useEvalRef(path, map) {
77
+ const ref = useMemo(() => ({ $ref: path, $map: map }), [path, map]);
78
+ // Subscribe to all relevant paths: main source + @/path args
79
+ const subscribe = useCallback((cb) => {
80
+ const unsubs = [];
81
+ unsubs.push(isCollectionRef(ref)
82
+ ? cache.subscribeChildren(path, cb)
83
+ : cache.subscribePath(path, cb));
84
+ for (const argPath of extractArgPaths(ref)) {
85
+ unsubs.push(cache.subscribePath(argPath, cb));
86
+ }
87
+ return () => unsubs.forEach(u => u());
88
+ }, [ref, path]);
89
+ const getSnapshot = useCallback(() => {
90
+ try {
91
+ return evaluateRef(ref, evalCtx);
92
+ }
93
+ catch {
94
+ return undefined;
95
+ }
96
+ }, [ref]);
97
+ return useSyncExternalStore(subscribe, getSnapshot);
98
+ }
99
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/bind/hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export type RefArg = {
2
+ $ref: string;
3
+ fields: string[];
4
+ };
5
+ export type PipeArg = number | string | RefArg;
6
+ export type MapExpr = {
7
+ steps: PipeStep[];
8
+ };
9
+ export type PipeStep = {
10
+ type: 'pipe';
11
+ name: string;
12
+ args: PipeArg[];
13
+ } | {
14
+ type: 'field';
15
+ name: string;
16
+ };
17
+ export declare function isRefArg(arg: PipeArg): arg is RefArg;
18
+ export declare function parseMapExpr(expr: string): MapExpr;
19
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/bind/parse.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AACxD,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/C,MAAM,MAAM,OAAO,GAAG;IAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,CAAC;AAE5C,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM,CAEpD;AA0ED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CASlD"}
@@ -0,0 +1,86 @@
1
+ // $map expression parser
2
+ // Syntax: selector.field | pipe1(args) | pipe2(args)
3
+ // Source path lives in $ref, not here — parser handles $map content only
4
+ //
5
+ // Access modes:
6
+ // .field = drill into current pipe value
7
+ // #field = lookup from source node ($ref path) — like URI fragment
8
+ // #/path.field = lookup from external node — absolute path after #
9
+ export function isRefArg(arg) {
10
+ return typeof arg === 'object' && arg !== null && '$ref' in arg;
11
+ }
12
+ const PIPE_RE = /^([a-zA-Z_]\w*)\(([^)]*)\)(.*)$/;
13
+ function parseArg(s) {
14
+ const t = s.trim();
15
+ // # = node ref: #field (self), #/path.field (external)
16
+ if (t.startsWith('#')) {
17
+ const rest = t.slice(1);
18
+ if (rest.startsWith('/')) {
19
+ // External: #/path.field
20
+ const dotIdx = rest.indexOf('.');
21
+ if (dotIdx === -1)
22
+ return { $ref: rest, fields: [] };
23
+ return { $ref: rest.slice(0, dotIdx), fields: rest.slice(dotIdx + 1).split('.') };
24
+ }
25
+ // Self: #field or #comp.field
26
+ return { $ref: '.', fields: rest.length ? rest.split('.') : [] };
27
+ }
28
+ const n = Number(t);
29
+ return Number.isFinite(n) ? n : t;
30
+ }
31
+ function parseSegment(raw) {
32
+ const s = raw.trim();
33
+ if (!s)
34
+ return [];
35
+ // #field — self-ref field access (like URI fragment)
36
+ if (s.startsWith('#') && !s.startsWith('#/')) {
37
+ const rest = s.slice(1);
38
+ return rest.split('.').map(name => ({ type: 'field', name }));
39
+ }
40
+ // Pure field chain: .foo.bar — drill into pipe value
41
+ if (s.startsWith('.')) {
42
+ return parseFieldChain(s);
43
+ }
44
+ // pipe(args) optionally followed by .field chain
45
+ const m = PIPE_RE.exec(s);
46
+ if (m) {
47
+ const steps = [{
48
+ type: 'pipe',
49
+ name: m[1],
50
+ args: m[2] ? m[2].split(',').map(parseArg) : [],
51
+ }];
52
+ if (m[3])
53
+ steps.push(...parseFieldChain(m[3]));
54
+ return steps;
55
+ }
56
+ // Bare name (round, abs): pipe with no args, optionally followed by .field
57
+ const bare = /^([a-zA-Z_]\w*)(.*)$/.exec(s);
58
+ if (bare) {
59
+ const steps = [{ type: 'pipe', name: bare[1], args: [] }];
60
+ if (bare[2])
61
+ steps.push(...parseFieldChain(bare[2]));
62
+ return steps;
63
+ }
64
+ return [];
65
+ }
66
+ function parseFieldChain(s) {
67
+ const steps = [];
68
+ let rest = s;
69
+ while (rest) {
70
+ const m = /^\.([a-zA-Z_$]\w*)(.*)$/.exec(rest);
71
+ if (!m)
72
+ break;
73
+ steps.push({ type: 'field', name: m[1] });
74
+ rest = m[2];
75
+ }
76
+ return steps;
77
+ }
78
+ export function parseMapExpr(expr) {
79
+ const parts = expr.split('|').map(s => s.trim());
80
+ const steps = [];
81
+ for (const part of parts) {
82
+ steps.push(...parseSegment(part));
83
+ }
84
+ return { steps };
85
+ }
86
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/bind/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type PipeFn = (input: unknown, ...args: unknown[]) => unknown;
2
+ export declare function registerPipe(name: string, fn: PipeFn): void;
3
+ export declare function getPipe(name: string): PipeFn | undefined;
4
+ //# sourceMappingURL=pipes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipes.d.ts","sourceRoot":"","sources":["../../src/bind/pipes.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;AAIrE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAE3D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAExD"}