@elaraai/e3-ui 1.0.103 → 1.0.104

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 (287) hide show
  1. package/dist/src/allocation/functions.d.ts +2 -1
  2. package/dist/src/allocation/functions.d.ts.map +1 -1
  3. package/dist/src/allocation/functions.js +3 -2
  4. package/dist/src/allocation/functions.js.map +1 -1
  5. package/dist/src/allocation/index.d.ts +120 -1
  6. package/dist/src/allocation/index.d.ts.map +1 -1
  7. package/dist/src/allocation/index.js +24 -4
  8. package/dist/src/allocation/index.js.map +1 -1
  9. package/dist/src/bind/data-indexed.d.ts +25 -4
  10. package/dist/src/bind/data-indexed.d.ts.map +1 -1
  11. package/dist/src/bind/data-indexed.js +58 -7
  12. package/dist/src/bind/data-indexed.js.map +1 -1
  13. package/dist/src/bind/data.d.ts +12 -14
  14. package/dist/src/bind/data.d.ts.map +1 -1
  15. package/dist/src/bind/data.js +11 -11
  16. package/dist/src/bind/data.js.map +1 -1
  17. package/dist/src/bind/func.d.ts +7 -2
  18. package/dist/src/bind/func.d.ts.map +1 -1
  19. package/dist/src/bind/func.js +10 -3
  20. package/dist/src/bind/func.js.map +1 -1
  21. package/dist/src/calendar/index.d.ts +148 -1
  22. package/dist/src/calendar/index.d.ts.map +1 -1
  23. package/dist/src/calendar/index.js +55 -5
  24. package/dist/src/calendar/index.js.map +1 -1
  25. package/dist/src/flowchart/canvas.d.ts +32 -14
  26. package/dist/src/flowchart/canvas.d.ts.map +1 -1
  27. package/dist/src/flowchart/canvas.js +21 -6
  28. package/dist/src/flowchart/canvas.js.map +1 -1
  29. package/dist/src/flowchart/details.d.ts +469 -0
  30. package/dist/src/flowchart/details.d.ts.map +1 -0
  31. package/dist/src/flowchart/details.js +1035 -0
  32. package/dist/src/flowchart/details.js.map +1 -0
  33. package/dist/src/flowchart/flowchart.d.ts +16 -72
  34. package/dist/src/flowchart/flowchart.d.ts.map +1 -1
  35. package/dist/src/flowchart/flowchart.js +10 -1
  36. package/dist/src/flowchart/flowchart.js.map +1 -1
  37. package/dist/src/flowchart/index.d.ts +282 -251
  38. package/dist/src/flowchart/index.d.ts.map +1 -1
  39. package/dist/src/flowchart/index.js +234 -220
  40. package/dist/src/flowchart/index.js.map +1 -1
  41. package/dist/src/flowchart/kinds.d.ts +438 -0
  42. package/dist/src/flowchart/kinds.d.ts.map +1 -0
  43. package/dist/src/flowchart/kinds.js +799 -0
  44. package/dist/src/flowchart/kinds.js.map +1 -0
  45. package/dist/src/flowchart/library.d.ts +154 -739
  46. package/dist/src/flowchart/library.d.ts.map +1 -1
  47. package/dist/src/flowchart/library.js +191 -673
  48. package/dist/src/flowchart/library.js.map +1 -1
  49. package/dist/src/flowchart/payload.d.ts +3652 -7843
  50. package/dist/src/flowchart/payload.d.ts.map +1 -1
  51. package/dist/src/flowchart/payload.js +331 -469
  52. package/dist/src/flowchart/payload.js.map +1 -1
  53. package/dist/src/flowchart/templates.d.ts +657 -0
  54. package/dist/src/flowchart/templates.d.ts.map +1 -0
  55. package/dist/src/flowchart/templates.js +658 -0
  56. package/dist/src/flowchart/templates.js.map +1 -0
  57. package/dist/src/flowchart/types.d.ts +2258 -214
  58. package/dist/src/flowchart/types.d.ts.map +1 -1
  59. package/dist/src/flowchart/types.js +374 -124
  60. package/dist/src/flowchart/types.js.map +1 -1
  61. package/dist/src/index.d.ts +13 -15
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js +24 -29
  64. package/dist/src/index.js.map +1 -1
  65. package/dist/src/internal.d.ts +5 -7
  66. package/dist/src/internal.d.ts.map +1 -1
  67. package/dist/src/internal.js +12 -19
  68. package/dist/src/internal.js.map +1 -1
  69. package/dist/src/ontology/index.d.ts +44 -15
  70. package/dist/src/ontology/index.d.ts.map +1 -1
  71. package/dist/src/ontology/index.js +19 -11
  72. package/dist/src/ontology/index.js.map +1 -1
  73. package/dist/src/plan/event-rows.d.ts +2 -1
  74. package/dist/src/plan/event-rows.d.ts.map +1 -1
  75. package/dist/src/plan/event-rows.js +6 -4
  76. package/dist/src/plan/event-rows.js.map +1 -1
  77. package/dist/src/plan/ir.d.ts +1 -0
  78. package/dist/src/plan/ir.d.ts.map +1 -1
  79. package/dist/src/plan/plan.d.ts +145 -1
  80. package/dist/src/plan/plan.d.ts.map +1 -1
  81. package/dist/src/plan/plan.js +67 -3
  82. package/dist/src/plan/plan.js.map +1 -1
  83. package/dist/src/plan/types.d.ts +1 -0
  84. package/dist/src/plan/types.d.ts.map +1 -1
  85. package/dist/src/query/builder.d.ts +362 -315
  86. package/dist/src/query/builder.d.ts.map +1 -1
  87. package/dist/src/query/builder.js +12 -1
  88. package/dist/src/query/builder.js.map +1 -1
  89. package/dist/src/query/index.d.ts +5 -1
  90. package/dist/src/query/index.d.ts.map +1 -1
  91. package/dist/src/query/index.js +3 -1
  92. package/dist/src/query/index.js.map +1 -1
  93. package/dist/src/roster/fit.d.ts +5 -2
  94. package/dist/src/roster/fit.d.ts.map +1 -1
  95. package/dist/src/roster/fit.js +5 -3
  96. package/dist/src/roster/fit.js.map +1 -1
  97. package/dist/src/roster/index.d.ts +103 -2
  98. package/dist/src/roster/index.d.ts.map +1 -1
  99. package/dist/src/roster/index.js +45 -6
  100. package/dist/src/roster/index.js.map +1 -1
  101. package/dist/src/runtime/index.d.ts +1 -3
  102. package/dist/src/runtime/index.d.ts.map +1 -1
  103. package/dist/src/runtime/index.js +1 -3
  104. package/dist/src/runtime/index.js.map +1 -1
  105. package/dist/src/schedule/record-window.d.ts +1 -0
  106. package/dist/src/schedule/record-window.d.ts.map +1 -1
  107. package/dist/src/schematic/index.d.ts +1 -1
  108. package/dist/src/schematic/index.d.ts.map +1 -1
  109. package/dist/src/schematic/index.js +1 -1
  110. package/dist/src/schematic/index.js.map +1 -1
  111. package/dist/src/schematic/kinds.d.ts +4 -24
  112. package/dist/src/schematic/kinds.d.ts.map +1 -1
  113. package/dist/src/schematic/kinds.js +8 -212
  114. package/dist/src/schematic/kinds.js.map +1 -1
  115. package/dist/src/schematic/payload.d.ts +140 -1
  116. package/dist/src/schematic/payload.d.ts.map +1 -1
  117. package/dist/src/schematic/payload.js +38 -1
  118. package/dist/src/schematic/payload.js.map +1 -1
  119. package/dist/src/schematic/types.d.ts.map +1 -1
  120. package/dist/src/schematic/types.js +4 -36
  121. package/dist/src/schematic/types.js.map +1 -1
  122. package/dist/src/schematic/window.d.ts +9 -42
  123. package/dist/src/schematic/window.d.ts.map +1 -1
  124. package/dist/src/schematic/window.js +10 -115
  125. package/dist/src/schematic/window.js.map +1 -1
  126. package/dist/src/sheet/actions.d.ts +388 -0
  127. package/dist/src/sheet/actions.d.ts.map +1 -0
  128. package/dist/src/sheet/actions.js +594 -0
  129. package/dist/src/sheet/actions.js.map +1 -0
  130. package/dist/src/sheet/bridge.d.ts +12 -1
  131. package/dist/src/sheet/bridge.d.ts.map +1 -1
  132. package/dist/src/sheet/bridge.js +30 -6
  133. package/dist/src/sheet/bridge.js.map +1 -1
  134. package/dist/src/sheet/columns.d.ts +5 -2
  135. package/dist/src/sheet/columns.d.ts.map +1 -1
  136. package/dist/src/sheet/columns.js.map +1 -1
  137. package/dist/src/sheet/draft-bridge.d.ts +9 -4
  138. package/dist/src/sheet/draft-bridge.d.ts.map +1 -1
  139. package/dist/src/sheet/draft-bridge.js +22 -7
  140. package/dist/src/sheet/draft-bridge.js.map +1 -1
  141. package/dist/src/sheet/fields.d.ts +13 -0
  142. package/dist/src/sheet/fields.d.ts.map +1 -1
  143. package/dist/src/sheet/fields.js +3 -0
  144. package/dist/src/sheet/fields.js.map +1 -1
  145. package/dist/src/sheet/index.d.ts +32 -2
  146. package/dist/src/sheet/index.d.ts.map +1 -1
  147. package/dist/src/sheet/index.js +18 -3
  148. package/dist/src/sheet/index.js.map +1 -1
  149. package/dist/src/sheet/library.d.ts +8 -0
  150. package/dist/src/sheet/library.d.ts.map +1 -1
  151. package/dist/src/sheet/root.d.ts +23 -1
  152. package/dist/src/sheet/root.d.ts.map +1 -1
  153. package/dist/src/sheet/root.js +40 -5
  154. package/dist/src/sheet/root.js.map +1 -1
  155. package/dist/src/sheet/sheet.d.ts +7843 -4132
  156. package/dist/src/sheet/sheet.d.ts.map +1 -1
  157. package/dist/src/sheet/sheet.js +41 -2
  158. package/dist/src/sheet/sheet.js.map +1 -1
  159. package/dist/src/sheet/templates.d.ts +4 -0
  160. package/dist/src/sheet/templates.d.ts.map +1 -1
  161. package/dist/src/sheet/types.d.ts +12449 -5268
  162. package/dist/src/sheet/types.d.ts.map +1 -1
  163. package/dist/src/sheet/types.js +114 -2
  164. package/dist/src/sheet/types.js.map +1 -1
  165. package/dist/src/utils/derive.d.ts +1 -1
  166. package/dist/src/utils/derive.js +1 -1
  167. package/dist/src/utils/record-kind.d.ts +625 -0
  168. package/dist/src/utils/record-kind.d.ts.map +1 -0
  169. package/dist/src/utils/record-kind.js +450 -0
  170. package/dist/src/utils/record-kind.js.map +1 -0
  171. package/dist/src/utils/views.d.ts +55 -0
  172. package/dist/src/utils/views.d.ts.map +1 -0
  173. package/dist/src/utils/views.js +72 -0
  174. package/dist/src/utils/views.js.map +1 -0
  175. package/dist/src/utils/vocabulary.d.ts +48 -0
  176. package/dist/src/utils/vocabulary.d.ts.map +1 -0
  177. package/dist/src/utils/vocabulary.js +47 -0
  178. package/dist/src/utils/vocabulary.js.map +1 -0
  179. package/dist/test/allocation/allocation.examples.d.ts +2 -0
  180. package/dist/test/allocation/allocation.examples.d.ts.map +1 -1
  181. package/dist/test/allocation/allocation.examples.js +81 -2
  182. package/dist/test/allocation/allocation.examples.js.map +1 -1
  183. package/dist/test/bind/func/func.examples.d.ts +19 -1
  184. package/dist/test/bind/func/func.examples.d.ts.map +1 -1
  185. package/dist/test/bind/func/func.examples.js +36 -1
  186. package/dist/test/bind/func/func.examples.js.map +1 -1
  187. package/dist/test/calendar/calendar.examples.d.ts +2 -0
  188. package/dist/test/calendar/calendar.examples.d.ts.map +1 -1
  189. package/dist/test/calendar/calendar.examples.js +80 -2
  190. package/dist/test/calendar/calendar.examples.js.map +1 -1
  191. package/dist/test/decision/queue.examples.d.ts +1 -0
  192. package/dist/test/decision/queue.examples.d.ts.map +1 -1
  193. package/dist/test/decision/queue.examples.js +12 -0
  194. package/dist/test/decision/queue.examples.js.map +1 -1
  195. package/dist/test/examples-package.d.ts.map +1 -1
  196. package/dist/test/examples-package.js +5 -4
  197. package/dist/test/examples-package.js.map +1 -1
  198. package/dist/test/flowchart/flowchart.examples.d.ts +1250 -4605
  199. package/dist/test/flowchart/flowchart.examples.d.ts.map +1 -1
  200. package/dist/test/flowchart/flowchart.examples.js +861 -512
  201. package/dist/test/flowchart/flowchart.examples.js.map +1 -1
  202. package/dist/test/ontology/ontology.examples.d.ts +2 -3
  203. package/dist/test/ontology/ontology.examples.d.ts.map +1 -1
  204. package/dist/test/ontology/ontology.examples.js +32 -21
  205. package/dist/test/ontology/ontology.examples.js.map +1 -1
  206. package/dist/test/plan/plan-events.examples.d.ts +1 -0
  207. package/dist/test/plan/plan-events.examples.d.ts.map +1 -1
  208. package/dist/test/plan/plan-events.examples.js +44 -0
  209. package/dist/test/plan/plan-events.examples.js.map +1 -1
  210. package/dist/test/plan/plan-nested.examples.d.ts +2 -2
  211. package/dist/test/plan/plan-nested.examples.js +5 -5
  212. package/dist/test/plan/plan-nested.examples.js.map +1 -1
  213. package/dist/test/plan/plan-records.examples.d.ts.map +1 -1
  214. package/dist/test/plan/plan-records.examples.js +1 -1
  215. package/dist/test/plan/plan-records.examples.js.map +1 -1
  216. package/dist/test/query/query.examples.d.ts +2 -0
  217. package/dist/test/query/query.examples.d.ts.map +1 -1
  218. package/dist/test/query/query.examples.js +37 -1
  219. package/dist/test/query/query.examples.js.map +1 -1
  220. package/dist/test/roster/roster.examples.d.ts +2 -0
  221. package/dist/test/roster/roster.examples.d.ts.map +1 -1
  222. package/dist/test/roster/roster.examples.js +76 -15
  223. package/dist/test/roster/roster.examples.js.map +1 -1
  224. package/dist/test/schematic/schematic-records.examples.d.ts.map +1 -1
  225. package/dist/test/schematic/schematic-records.examples.js +6 -4
  226. package/dist/test/schematic/schematic-records.examples.js.map +1 -1
  227. package/dist/test/schematic/schematic.examples.d.ts +1 -0
  228. package/dist/test/schematic/schematic.examples.d.ts.map +1 -1
  229. package/dist/test/schematic/schematic.examples.js +144 -0
  230. package/dist/test/schematic/schematic.examples.js.map +1 -1
  231. package/dist/test/sheet/sheet-actions.examples.d.ts +1264 -0
  232. package/dist/test/sheet/sheet-actions.examples.d.ts.map +1 -0
  233. package/dist/test/sheet/sheet-actions.examples.js +394 -0
  234. package/dist/test/sheet/sheet-actions.examples.js.map +1 -0
  235. package/dist/test/sheet/sheet.examples.d.ts +1 -0
  236. package/dist/test/sheet/sheet.examples.d.ts.map +1 -1
  237. package/dist/test/sheet/sheet.examples.js +77 -0
  238. package/dist/test/sheet/sheet.examples.js.map +1 -1
  239. package/dist/test/studio/studio.examples.d.ts +1 -0
  240. package/dist/test/studio/studio.examples.d.ts.map +1 -1
  241. package/dist/test/studio/studio.examples.js +18 -8
  242. package/dist/test/studio/studio.examples.js.map +1 -1
  243. package/package.json +12 -12
  244. package/dist/src/diff/index.d.ts +0 -407
  245. package/dist/src/diff/index.d.ts.map +0 -1
  246. package/dist/src/diff/index.js +0 -203
  247. package/dist/src/diff/index.js.map +0 -1
  248. package/dist/src/experiment/index.d.ts +0 -1033
  249. package/dist/src/experiment/index.d.ts.map +0 -1
  250. package/dist/src/experiment/index.js +0 -197
  251. package/dist/src/experiment/index.js.map +0 -1
  252. package/dist/src/experiment/types.d.ts +0 -1093
  253. package/dist/src/experiment/types.d.ts.map +0 -1
  254. package/dist/src/experiment/types.js +0 -423
  255. package/dist/src/experiment/types.js.map +0 -1
  256. package/dist/src/flowchart/over.d.ts +0 -227
  257. package/dist/src/flowchart/over.d.ts.map +0 -1
  258. package/dist/src/flowchart/over.js +0 -213
  259. package/dist/src/flowchart/over.js.map +0 -1
  260. package/dist/src/flowchart/patch.d.ts +0 -64
  261. package/dist/src/flowchart/patch.d.ts.map +0 -1
  262. package/dist/src/flowchart/patch.js +0 -67
  263. package/dist/src/flowchart/patch.js.map +0 -1
  264. package/dist/src/flowchart/values.d.ts +0 -271
  265. package/dist/src/flowchart/values.d.ts.map +0 -1
  266. package/dist/src/flowchart/values.js +0 -220
  267. package/dist/src/flowchart/values.js.map +0 -1
  268. package/dist/src/flowchart/window.d.ts +0 -306
  269. package/dist/src/flowchart/window.d.ts.map +0 -1
  270. package/dist/src/flowchart/window.js +0 -63
  271. package/dist/src/flowchart/window.js.map +0 -1
  272. package/dist/src/runtime/diff.d.ts +0 -36
  273. package/dist/src/runtime/diff.d.ts.map +0 -1
  274. package/dist/src/runtime/diff.js +0 -34
  275. package/dist/src/runtime/diff.js.map +0 -1
  276. package/dist/src/runtime/experiment.d.ts +0 -48
  277. package/dist/src/runtime/experiment.d.ts.map +0 -1
  278. package/dist/src/runtime/experiment.js +0 -10
  279. package/dist/src/runtime/experiment.js.map +0 -1
  280. package/dist/test/diff/diff.examples.d.ts +0 -313
  281. package/dist/test/diff/diff.examples.d.ts.map +0 -1
  282. package/dist/test/diff/diff.examples.js +0 -452
  283. package/dist/test/diff/diff.examples.js.map +0 -1
  284. package/dist/test/experiment/experiment.examples.d.ts +0 -1512
  285. package/dist/test/experiment/experiment.examples.d.ts.map +0 -1
  286. package/dist/test/experiment/experiment.examples.js +0 -609
  287. package/dist/test/experiment/experiment.examples.js.map +0 -1
@@ -0,0 +1,799 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * The Flowchart's kinds (#1500, `Flowchart Records Spec.md` §2, §3, R1–R4):
7
+ * `Flowchart.states`, `transitions`, `lanes` and `decisions`. Each takes a
8
+ * record of the app's and maps its fields to the Flowchart's roles, as the
9
+ * Schematic's kinds do (`schematic/kinds.ts`): the Flowchart stores nothing in
10
+ * a shape of its own, and no record of the app's holds a type of the
11
+ * Flowchart's.
12
+ *
13
+ * - **A role is a field of the row where a gesture writes it or it names
14
+ * another row's key** (R2): a state's `label`, `lane` and `order`; a
15
+ * transition's `from`, `to` and `decision`; a lane's `label` and `order`; a
16
+ * decision's `queue`. Each is checked against the row's type when the code
17
+ * compiles — a field of another type is a type error naming the fields that
18
+ * fit — and again at build, in the kind's words. Every other role is an
19
+ * accessor over the row and its key, reified once and called per row: a
20
+ * state's `members`; a transition's `kind` and `evidence`; a decision's
21
+ * `label`, `letter`, `owner` and `outcomes`.
22
+ * - **A gesture writes only its roles' fields** (R8): every other field of the
23
+ * row reads back as it was, and a new row takes a card's values, or its
24
+ * type's defaults.
25
+ * - **How a kind is bound follows how it is read** (R3): a state or a
26
+ * transition `Record.bind(record)`, editable — read whole, or through its
27
+ * source of the slice with `entries: Data.bindPaged(record)` beside it —
28
+ * `Data.bind(record)`, read only and whole, or `Data.bindPaged(record)`
29
+ * alone, read only, through its source; a lane or a decision `Record.bind`
30
+ * or `Data.bind`, read whole. Every other form is refused, naming the one to
31
+ * use.
32
+ *
33
+ * A kind closes its record behind East functions over beast2 bytes (§3, "What
34
+ * the payload carries") — its stored rows a read holds, each one's roles
35
+ * beside its bytes; a drafted row's roles; a gesture's write and a new row;
36
+ * the fields an author's card sets; the shared editing session over the
37
+ * record with its patch door; the record read by key; its history, its form,
38
+ * its own Details and the app's check — through the machinery the Schematic's
39
+ * kinds share (`utils/record-kind.ts`), so the payload is one type whatever
40
+ * the rows hold, and the renderer needs no row type.
41
+ *
42
+ * @packageDocumentation
43
+ */
44
+ import { ArrayType, AsyncFunctionType, BlobType, East, Expr, FloatType, IntegerType, OptionType, PatchType, SetType, StringType, defaultValue, isTypeEqual, none, printType, some, variant, } from "@elaraai/east";
45
+ import { resolveRowSource } from "@elaraai/east-ui/internal";
46
+ import { RecordOutcomeType } from "../bind/record.js";
47
+ import { fieldOf } from "../schedule/fields.js";
48
+ import { checkEntries, typeText } from "../schedule/window.js";
49
+ import { accessorRole, called, fieldTypeOf, kindSourceRows, kindWholeRows, readOf, recordSide, roleField, rowWith, rowsReadOf, storedRows, valuesTypeOf, } from "../utils/record-kind.js";
50
+ import { isFlowchartDetails } from "./details.js";
51
+ import { checkedFlowchartTemplates } from "./templates.js";
52
+ import { FlowchartDecisionEntryType, FlowchartDecisionKindType, FlowchartDecisionRolesType, FlowchartEvidenceType, FlowchartLaneEntryType, FlowchartLaneKindType, FlowchartLaneRolesType, FlowchartLaneWriteType, FlowchartLinkKindType, FlowchartStateEntryType, FlowchartStateKindType, FlowchartStateRolesType, FlowchartStateWriteType, FlowchartTemplateType, FlowchartTransitionEntryType, FlowchartTransitionKindType, FlowchartTransitionRolesType, FlowchartTransitionWriteType, } from "./types.js";
53
+ /**
54
+ * Tells a kind's binding by its handle's East struct (`bind/sources.ts`'
55
+ * rule): a `page` field is `Data.bindPaged`'s, a `mutate` field
56
+ * `Record.bind`'s — checked for its patch door — and any other `Data.bind`'s.
57
+ *
58
+ * @param record - What the kind was given
59
+ * @param where - The kind, as a refusal names it
60
+ * @param noun - What its rows are, as a refusal names them (`states`)
61
+ * @param whole - Whether the kind is read whole only: a lane or a decision
62
+ * @returns The binding
63
+ * @throws {Error} Naming the forms to use: anything but a binding of a record of structs keyed by String — a paged read
64
+ * for a kind read whole, one paging an index's window, and one naming no snapshot among them — and a `Record.bind`
65
+ * without its patch door
66
+ */
67
+ function boundOf(record, where, noun, whole) {
68
+ const forms = whole
69
+ ? "bind Record.bind(record) to edit them, or Data.bind(record) to read them"
70
+ : "bind Record.bind(record) to edit them, Data.bind(record) to read them whole, or Data.bindPaged(record) to read them through their source";
71
+ const refuse = (why) => { throw new Error(`${where}: the ${noun} are a record of the app's${whole ? ", read whole" : ""}: ${forms}${why}`); };
72
+ if (!(record instanceof Expr))
73
+ return refuse("");
74
+ const type = Expr.type(record);
75
+ const fields = type.type === "Struct" ? type.fields : undefined;
76
+ if (fields === undefined)
77
+ return refuse(` — and this is ${printType(type)}`);
78
+ let form;
79
+ let recordType;
80
+ if (fields["page"] !== undefined) {
81
+ if (whole)
82
+ return refuse(" — and this is Data.bindPaged(record), which reads a record through its source of the slice");
83
+ form = "paged";
84
+ if (fields["indexes"] !== undefined) {
85
+ return refuse(` — and this paged read reads the record through its indexes: bind its own entries, Data.bindPaged(record), and name the indexed read ` +
86
+ `as the ${noun}' source of the slice`);
87
+ }
88
+ const resolved = resolveRowSource(record, where);
89
+ if (resolved.kind !== "paged")
90
+ return refuse(" — and this paged read pages an index's window: bind the record's own entries, Data.bindPaged(record)");
91
+ recordType = resolved.collectionType;
92
+ }
93
+ else {
94
+ form = fields["mutate"] !== undefined ? "record" : "data";
95
+ const read = fields["read"];
96
+ if (read === undefined || read.type !== "Function" || read.inputs.length !== 0 || fields["binding"] === undefined)
97
+ return refuse("");
98
+ recordType = read.output;
99
+ }
100
+ if (recordType.type !== "Dict" || !isTypeEqual(recordType.key, StringType) || recordType.value.type !== "Struct") {
101
+ throw new Error(`${where}: the ${noun}' record holds its rows by String key, each a struct — and this one holds ${typeText(recordType)}`);
102
+ }
103
+ const rowType = recordType.value;
104
+ // A paged read of the record's own entries, at the snapshot every read of it is at.
105
+ if (form === "paged")
106
+ checkEntries(record, StringType, rowType, `${where}: Data.bindPaged(record)`);
107
+ if (form === "record") {
108
+ // The patch door: the record's mutation.patch(), the mutation named `patch` taking the record's patch.
109
+ const commit = fields["commit"];
110
+ const door = commit?.type === "Struct" ? commit.fields["patch"] : undefined;
111
+ if (door === undefined || !isTypeEqual(door, AsyncFunctionType([StringType, PatchType(recordType)], RecordOutcomeType))) {
112
+ throw new Error(`${where}: the ${noun}' record is bound without its patch door — its record declares patch: mutation.patch(), ` +
113
+ "which Save writes each change through");
114
+ }
115
+ }
116
+ return { form, handle: record, rowType };
117
+ }
118
+ /**
119
+ * Checks a kind's `entries` where it declares them (R3): for a record bound to
120
+ * be edited, a paged read of its own entries.
121
+ *
122
+ * @param bound - The kind's binding
123
+ * @param entries - What the kind was given
124
+ * @param where - The kind, as a refusal names it
125
+ * @param noun - What its rows are, as a refusal names them
126
+ * @returns The paged read, checked; `undefined` for none
127
+ * @throws {Error} When a read-only binding is given `entries`, or they are no paged read of the record's own entries
128
+ */
129
+ function entriesOf(bound, entries, where, noun) {
130
+ if (entries === undefined)
131
+ return undefined;
132
+ if (bound.form !== "record") {
133
+ throw new Error(`${where}: entries reads beside Record.bind: bind the ${noun} with Record.bind(record), ` +
134
+ "or bind Data.bindPaged(record) alone to read them through their source, read only");
135
+ }
136
+ return checkEntries(entries, StringType, bound.rowType, `${where}: \`entries\``);
137
+ }
138
+ /**
139
+ * A state's or a transition's reads, as its binding and its source of the
140
+ * slice decide them (R3, R4): whole, or complete through its source; and the
141
+ * record read by key.
142
+ *
143
+ * @param bound - The kind's binding
144
+ * @param entries - Its `entries`, checked
145
+ * @param part - Its source of the slice, named after it, when the slice has one
146
+ * @param where - The kind, as a refusal names it
147
+ * @param noun - The kind, as the slice's source is named after it
148
+ * @param every - Whether, read through its source, it reads every row: under `narrowed="dim"` (R6)
149
+ * @returns `()` → its rows, by key, and the paged read its rows are read by key through, if any
150
+ * @throws {Error} Naming the form to use, for each binding its read does not take
151
+ */
152
+ function readsOf(bound, entries, part, where, noun, every) {
153
+ const source = `give a source named ${noun}, Data.bindPaged(record, { indexes }) over the ${noun}' record`;
154
+ if (part === undefined) {
155
+ if (bound.form === "paged") {
156
+ throw new Error(`${where}: Data.bindPaged(record) reads the ${noun} through their source of the slice: ${source} — ` +
157
+ "or bind Data.bind(record) to read them whole");
158
+ }
159
+ if (entries !== undefined)
160
+ throw new Error(`${where}: the ${noun} are read through their source of the slice: ${source}, or drop entries`);
161
+ return { rows: kindWholeRows(bound.handle, bound.rowType), byKey: undefined };
162
+ }
163
+ if (bound.form === "data") {
164
+ throw new Error(`${where}: Data.bind(record) reads the ${noun} whole, and the slice's source "${noun}" reads them through it — ` +
165
+ "bind Data.bindPaged(record) to read them through their source, read only, or Record.bind(record) with entries: Data.bindPaged(record) to edit them");
166
+ }
167
+ if (bound.form === "record" && entries === undefined) {
168
+ throw new Error(`${where}: the slice's source "${noun}" reads only its narrowing, and a row is read by its key — the inspector's, ` +
169
+ `a gesture's original and Save's confirmation: give entries: Data.bindPaged(record) beside Record.bind, the ${noun}' record's own entries`);
170
+ }
171
+ return {
172
+ rows: kindSourceRows(part, noun, bound.rowType, where, every, `name it "${noun}", over the ${noun}' own record`),
173
+ byKey: bound.form === "paged" ? bound.handle : entries,
174
+ };
175
+ }
176
+ /**
177
+ * Checks a text role: a String field, or an Option of one.
178
+ *
179
+ * @param rowType - The kind's row type
180
+ * @param where - The kind, as a refusal names it
181
+ * @param role - The role, as the refusal names it
182
+ * @param name - What it was given
183
+ * @returns The field, checked
184
+ * @throws {Error} When it names no field of the row, or one of another type
185
+ */
186
+ function textField(rowType, where, role, name) {
187
+ if (typeof name !== "string")
188
+ throw new Error(`${where}: \`${role}\` names a String field of the row, or an Option of one`);
189
+ const type = fieldTypeOf(rowType, where)(role, name);
190
+ if (isTypeEqual(type, StringType))
191
+ return { field: name, optional: false };
192
+ if (isTypeEqual(type, OptionType(StringType)))
193
+ return { field: name, optional: true };
194
+ throw new Error(`${where}: \`${role}\` names a String field, or an Option of one — "${name}" holds ${typeText(type)}`);
195
+ }
196
+ /** A text field's value as a String: an Option field holding none is empty. */
197
+ function textOf(row, text) {
198
+ const value = fieldOf(row, text.field);
199
+ return text.optional
200
+ ? value.match({ none: (_$) => East.value("", StringType), some: (_$, t) => t })
201
+ : value;
202
+ }
203
+ /** A String written to a text field: into an Option field, an empty one is none. */
204
+ function textValue(text, value) {
205
+ if (!text.optional)
206
+ return value;
207
+ return East.equal(value, "").ifElse((_$) => East.value(none, OptionType(StringType)), (_$) => East.value(some(value), OptionType(StringType)));
208
+ }
209
+ /**
210
+ * A field written from a gesture's Option, `none` keeping it as it was.
211
+ *
212
+ * @param given - The gesture's value for the field
213
+ * @param source - The row it is written over
214
+ * @param field - The field
215
+ * @param value - What a given value writes
216
+ * @returns The field's value
217
+ */
218
+ function kept(given, source, field, value) {
219
+ return given.match({
220
+ none: (_$) => fieldOf(source, field),
221
+ some: (_$, v) => value(v),
222
+ });
223
+ }
224
+ /** Checks a kind's `name` or `icon`: a string when given, else its default. */
225
+ function wordOf(where, prop, given, otherwise) {
226
+ if (given === undefined)
227
+ return otherwise;
228
+ if (typeof given !== "string" || given === "") {
229
+ throw new Error(`${where}: \`${prop}\` is ${prop === "name" ? "what one is called, a string" : "a Font Awesome solid icon's name"}`);
230
+ }
231
+ return given;
232
+ }
233
+ /** Each field's type default, for the fields a new row takes from a gesture rather than from a card's values. */
234
+ function defaultsOf(rowType, placed) {
235
+ const fields = rowType.fields;
236
+ return Object.fromEntries(placed.map((name) => [name, East.value(defaultValue(fields[name]), fields[name])]));
237
+ }
238
+ /**
239
+ * A new row's source: a card's values, or the values' type defaults, with the
240
+ * fields a drop writes at their type defaults — what a gesture then writes its
241
+ * roles over.
242
+ *
243
+ * @param rowType - The record's row type
244
+ * @param valuesType - The values' type: the row's fields less those `placed` names
245
+ * @param placed - The fields a drop writes
246
+ * @returns `(values)` → the row, from a card's values' bytes, if any
247
+ */
248
+ function sourceOf(rowType, valuesType, placed) {
249
+ return East.function([OptionType(BlobType)], rowType, ($, values) => {
250
+ const given = $.const(values.match({
251
+ some: (_$2, bytes) => bytes.decodeBeast(valuesType, "v2"),
252
+ none: (_$2) => East.value(defaultValue(valuesType), valuesType),
253
+ }));
254
+ return rowWith(rowType, given, defaultsOf(rowType, placed));
255
+ });
256
+ }
257
+ /** The key a Flowchart's declarations carry their sort under. */
258
+ export const FLOWCHART_DEF = Symbol("Flowchart.def");
259
+ /**
260
+ * Whether something is a Flowchart kind of the sort given.
261
+ *
262
+ * @param value - What a prop holds
263
+ * @param sort - The sort the prop takes
264
+ * @returns Whether it is one
265
+ */
266
+ export function isFlowchartKind(value, sort) {
267
+ return typeof value === "object" && value !== null && FLOWCHART_DEF in value && value[FLOWCHART_DEF] === sort;
268
+ }
269
+ /**
270
+ * A state's or a transition's details, checked where the kind declares them
271
+ * (#1507, R21): `Flowchart.details`', and on a transition what its label draws.
272
+ *
273
+ * @param details - What the kind's `details` holds
274
+ * @param where - The kind, as a refusal names it
275
+ * @param noun - The kind's rows
276
+ * @returns The details; `undefined` for none
277
+ * @throws {Error} When they are not `Flowchart.details`', and on a transition, a tags or a histogram read on the canvas
278
+ * and lines past three
279
+ */
280
+ function detailsOf(details, where, noun) {
281
+ if (details === undefined)
282
+ return undefined;
283
+ if (!isFlowchartDetails(details)) {
284
+ throw new Error(`${where}: \`details\` takes Flowchart.details(binding, { details: [ … ] }) — the reads over the app's rows, keyed as the ${noun} are`);
285
+ }
286
+ details.check(noun, where);
287
+ return details;
288
+ }
289
+ /**
290
+ * Declares the states (see the module docs, R1–R3).
291
+ *
292
+ * @typeParam R - The record's row type
293
+ * @typeParam L - The `lane` field
294
+ * @typeParam O - The `order` field
295
+ * @param binding - The app's record of states: `Record.bind(record)`, its record declaring `patch: mutation.patch()`, to edit
296
+ * them — read whole, or through the slice's `states` source with `entries: Data.bindPaged(record)` — or `Data.bind(record)`,
297
+ * read whole, or `Data.bindPaged(record)`, read through their source, to read them only
298
+ * @param spec - What one is called, its icon, the fields its roles are, its accessors, and its cards, form, Details and check
299
+ * @returns The states, for the Flowchart's `states`
300
+ * @throws {Error} Naming the role or the binding (R2, R3): a role naming a field the row lacks, or one of another type;
301
+ * `label` and `lane` naming one field; an accessor returning another type; cards written in the code, or giving other
302
+ * fields than every field but `lane` and `order`; and a record that is no binding of a record of structs keyed by
303
+ * String, a `Record.bind` without its patch door, or `entries` beside a read-only binding
304
+ *
305
+ * @example
306
+ * ```tsx
307
+ * // .tsx file with the `@jsxImportSource @elaraai/e3-ui` pragma
308
+ * import { DateTimeType, DictType, East, FloatType, IntegerType, NullType, OptionType, StringType, StructType, VariantType, none, some, variant } from "@elaraai/east";
309
+ * import { Box, Reactive, UIComponentType } from "@elaraai/east-ui";
310
+ * import { Flowchart, Record } from "@elaraai/e3-ui";
311
+ * import e3 from "@elaraai/e3";
312
+ *
313
+ * // The depot's four records, each declaring its patch door: Save writes each through its own.
314
+ * export const DepotState = StructType({
315
+ * name: StringType, // what its card calls it
316
+ * phase: StringType, // the lane it stands in, by the lane's key
317
+ * seq: FloatType, // its place in its lane
318
+ * slots: OptionType(IntegerType), // a class of interchangeable states: the ×N badge
319
+ * flow: StringType, // the flow it belongs to: one record holds the depot's flows
320
+ * });
321
+ * export const DepotTransition = StructType({
322
+ * src: StringType, // the state it leaves, by its key
323
+ * dst: StringType, // the state it enters
324
+ * kind: VariantType({ planned: NullType, observed: NullType }),
325
+ * trigger: OptionType(StringType), // the decision that governs it, by its key
326
+ * volume: OptionType(FloatType), // the parcels measured on it
327
+ * n: OptionType(IntegerType), // the moves behind them
328
+ * at: OptionType(DateTimeType), // when they were measured
329
+ * flow: StringType,
330
+ * });
331
+ * export const DepotLane = StructType({ label: StringType, seq: FloatType });
332
+ * export const DepotDecision = StructType({ name: StringType, owner: StringType });
333
+ * export const depotStates = e3.record("flowchart_depot_states", DictType(StringType, DepotState), {
334
+ * initial: new Map([
335
+ * ["ARV", { name: "Arrived", phase: "intake", seq: 1, slots: none, flow: "Parcels" }],
336
+ * ["SCN", { name: "Scanned", phase: "intake", seq: 2, slots: none, flow: "Parcels" }],
337
+ * ["IND", { name: "Inducted", phase: "induct", seq: 1, slots: none, flow: "Parcels" }],
338
+ * ["LBL", { name: "Relabelled", phase: "induct", seq: 2, slots: none, flow: "Parcels" }],
339
+ * ["CH*", { name: "Sort chutes (class)", phase: "sort", seq: 1, slots: some(14n), flow: "Parcels" }],
340
+ * ["SRD", { name: "Sorted", phase: "sort", seq: 2, slots: none, flow: "Parcels" }],
341
+ * ["HLD", { name: "Held", phase: "hold", seq: 1, slots: none, flow: "Parcels" }],
342
+ * ["CLR", { name: "Cleared", phase: "hold", seq: 2, slots: none, flow: "Parcels" }],
343
+ * ["LDD", { name: "Loaded", phase: "dispatch", seq: 1, slots: none, flow: "Parcels" }],
344
+ * ["DSP", { name: "Dispatched", phase: "dispatch", seq: 2, slots: none, flow: "Parcels" }],
345
+ * // The returns flow's states, beside the parcels'.
346
+ * ["RCV", { name: "Received", phase: "intake", seq: 3, slots: none, flow: "Returns" }],
347
+ * ["INS", { name: "Inspected", phase: "hold", seq: 3, slots: none, flow: "Returns" }],
348
+ * ["RSD", { name: "Resent", phase: "dispatch", seq: 3, slots: none, flow: "Returns" }],
349
+ * ]),
350
+ * mutations: (mutation) => ({ patch: mutation.patch() }),
351
+ * indexes: (index) => ({
352
+ * flowchart_states_by_flow: index.on(["flow"]),
353
+ * flowchart_states_by_lane: index.on(["flow", "phase"]),
354
+ * }),
355
+ * });
356
+ * export const depotTransitions = e3.record("flowchart_depot_transitions", DictType(StringType, DepotTransition), {
357
+ * initial: new Map([
358
+ * ["l1", { src: "ARV", dst: "SCN", kind: variant("planned", null), trigger: none, volume: some(18460), n: some(412n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
359
+ * ["l2", { src: "SCN", dst: "IND", kind: variant("planned", null), trigger: none, volume: some(18390), n: some(409n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
360
+ * // In place: parcels inducted again, counted but not weighed.
361
+ * ["l3", { src: "IND", dst: "IND", kind: variant("observed", null), trigger: none, volume: none, n: some(2n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
362
+ * ["l4", { src: "IND", dst: "CH*", kind: variant("planned", null), trigger: some("route"), volume: some(17350), n: some(386n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
363
+ * ["l5", { src: "CH*", dst: "SRD", kind: variant("planned", null), trigger: none, volume: some(18210), n: some(405n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
364
+ * ["l6", { src: "SRD", dst: "HLD", kind: variant("planned", null), trigger: none, volume: some(8420), n: some(188n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
365
+ * ["l7", { src: "HLD", dst: "CLR", kind: variant("planned", null), trigger: some("customs"), volume: some(8350), n: some(186n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
366
+ * ["l8", { src: "CLR", dst: "LDD", kind: variant("planned", null), trigger: none, volume: some(8240), n: some(183n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
367
+ * ["l9", { src: "LDD", dst: "DSP", kind: variant("planned", null), trigger: none, volume: some(17030), n: some(378n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
368
+ * // Its far end names a state no row is keyed by: drawn as a ghost, and listed in Issues.
369
+ * ["l10", { src: "DSP", dst: "DLV", kind: variant("planned", null), trigger: none, volume: none, n: none, at: none, flow: "Parcels" }],
370
+ * // Observed, not planned: parcels relabelled before they are sorted.
371
+ * ["l11", { src: "IND", dst: "LBL", kind: variant("observed", null), trigger: none, volume: some(980), n: some(22n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
372
+ * ["l12", { src: "LBL", dst: "CH*", kind: variant("observed", null), trigger: none, volume: some(975), n: some(22n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
373
+ * ["l13", { src: "SRD", dst: "LDD", kind: variant("planned", null), trigger: none, volume: some(8790), n: some(195n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Parcels" }],
374
+ * ["r1", { src: "RCV", dst: "INS", kind: variant("planned", null), trigger: none, volume: some(640), n: some(15n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Returns" }],
375
+ * ["r2", { src: "INS", dst: "RSD", kind: variant("planned", null), trigger: none, volume: some(610), n: some(14n), at: some(new Date("2026-06-30T00:00:00Z")), flow: "Returns" }],
376
+ * ]),
377
+ * mutations: (mutation) => ({ patch: mutation.patch() }),
378
+ * indexes: (index) => ({
379
+ * flowchart_transitions_by_flow: index.on(["flow"]),
380
+ * }),
381
+ * });
382
+ * export const depotLanes = e3.record("flowchart_depot_lanes", DictType(StringType, DepotLane), {
383
+ * initial: new Map([
384
+ * ["intake", { label: "Intake", seq: 1 }], ["induct", { label: "Induct", seq: 2 }], ["sort", { label: "Sort", seq: 3 }],
385
+ * ["hold", { label: "Hold", seq: 4 }], ["dispatch", { label: "Dispatch", seq: 5 }],
386
+ * ]),
387
+ * mutations: (mutation) => ({ patch: mutation.patch() }),
388
+ * });
389
+ * export const depotDecisions = e3.record("flowchart_depot_decisions", DictType(StringType, DepotDecision), {
390
+ * initial: new Map([["route", { name: "route", owner: "sort-planner" }], ["customs", { name: "customs", owner: "customs-desk" }]]),
391
+ * mutations: (mutation) => ({ patch: mutation.patch() }),
392
+ * });
393
+ *
394
+ * const flowchartDepotEditing = East.function([], UIComponentType, (_$) => (
395
+ * <Reactive>{$ => {
396
+ * const states = $.let(Record.bind(depotStates));
397
+ * const transitions = $.let(Record.bind(depotTransitions));
398
+ * const lanes = $.let(Record.bind(depotLanes));
399
+ * const decisions = $.let(Record.bind(depotDecisions));
400
+ * return (
401
+ * <Box height="600px">
402
+ * <Flowchart
403
+ * states={Flowchart.states(states, {
404
+ * label: "name", lane: "phase", order: "seq", members: (s) => s.slots,
405
+ * // The app's check on a drafted state: Save waits until it names its flow, and Issues says why.
406
+ * ready: (s) => s.flow.equal("").ifElse(
407
+ * () => variant("incomplete", [{ field: "flow", message: "Give the state its flow" }]),
408
+ * () => variant("ready", null),
409
+ * ),
410
+ * })}
411
+ * transitions={Flowchart.transitions(transitions, { from: "src", to: "dst", decision: "trigger", kind: (t) => t.kind })}
412
+ * lanes={Flowchart.lanes(lanes, { label: "label", order: "seq" })}
413
+ * decisions={Flowchart.decisions(decisions, { label: (d) => d.name, owner: (d) => some(d.owner) })}
414
+ * name="depotEditing"
415
+ * />
416
+ * </Box>
417
+ * );
418
+ * }}</Reactive>
419
+ * ));
420
+ * ```
421
+ */
422
+ export function flowchartStates(binding, spec) {
423
+ const where = "Flowchart.states";
424
+ const bound = boundOf(binding, where, "states", false);
425
+ const rowType = bound.rowType;
426
+ const role = roleField(rowType, where);
427
+ const entries = entriesOf(bound, spec.entries, where, "states");
428
+ const name = wordOf(where, "name", spec.name, "State");
429
+ const icon = wordOf(where, "icon", spec.icon, "square");
430
+ // The roles that are fields.
431
+ const label = textField(rowType, where, "label", spec.label);
432
+ const laneField = role("lane", spec.lane, StringType, "a String field holding its lane's key");
433
+ const orderField = role("order", spec.order, FloatType, "a Float field, the state's place in its lane");
434
+ if (laneField !== undefined && laneField === label.field) {
435
+ throw new Error(`${where}: \`label\` and \`lane\` both name "${laneField}" — a state's name and its lane are two fields`);
436
+ }
437
+ // The role the app computes.
438
+ const membersOf = accessorRole(rowType, where, "members", OptionType(IntegerType), "an Option of an Integer", spec.members);
439
+ // Its details, read as the states are (#1507).
440
+ const details = detailsOf(spec.details, where, "states");
441
+ // The cards: every field but the lane and the order.
442
+ const placed = [laneField, orderField].filter((field) => field !== undefined);
443
+ const ValuesType = valuesTypeOf(rowType, placed);
444
+ const templates = checkedFlowchartTemplates(spec.templates, ValuesType, placed, where);
445
+ // One state's roles, from its row and its key.
446
+ const rolesOf = East.function([rowType, StringType], FlowchartStateRolesType, ($, row, key) => East.value({
447
+ label: textOf(row, label),
448
+ lane: laneField === undefined ? none : some(fieldOf(row, laneField)),
449
+ order: orderField === undefined ? none : some(fieldOf(row, orderField)),
450
+ members: called($, membersOf, row, key, (m) => m, none),
451
+ }, FlowchartStateRolesType));
452
+ // The row with a gesture's roles written over `source`, each where given, every other field as it was (R8).
453
+ const written = (source, w) => ({
454
+ [label.field]: kept(w.label, source, label.field, (t) => textValue(label, t)),
455
+ ...(laneField === undefined ? {} : { [laneField]: kept(w.lane, source, laneField, (k) => k) }),
456
+ ...(orderField === undefined ? {} : { [orderField]: kept(w.order, source, orderField, (o) => o) }),
457
+ });
458
+ const write = East.function([BlobType, FlowchartStateWriteType], OptionType(BlobType), ($, bytes, w) => {
459
+ const row = $.const(bytes.decodeBeast(rowType, "v2"));
460
+ return East.value(some(East.Blob.encodeBeast(rowWith(rowType, row, written(row, w)), "v2")), OptionType(BlobType));
461
+ });
462
+ // A new state: its roles over a card's values, or its type's defaults.
463
+ const source = sourceOf(rowType, ValuesType, placed);
464
+ const create = East.function([FlowchartStateWriteType, OptionType(BlobType)], OptionType(BlobType), ($, w, values) => {
465
+ const from = $.const(source);
466
+ const row = $.const(from(values));
467
+ return East.value(some(East.Blob.encodeBeast(rowWith(rowType, row, written(row, w)), "v2")), OptionType(BlobType));
468
+ });
469
+ return {
470
+ [FLOWCHART_DEF]: "states",
471
+ rowType,
472
+ name,
473
+ form: bound.form,
474
+ lane: laneField !== undefined,
475
+ inspectorReads: details?.inspectorReads ?? false,
476
+ weighedBy: details?.source === undefined ? undefined : { source: details.source, rowType: details.rowType },
477
+ hasTemplates: templates !== undefined,
478
+ templatesSource: templates?.source,
479
+ build(part, every) {
480
+ const { rows, byKey } = readsOf(bound, entries, part, where, "states", every);
481
+ const side = recordSide(bound, entries, byKey, spec, [label.field, laneField, orderField], where);
482
+ return East.value({
483
+ ...side,
484
+ name,
485
+ icon,
486
+ rows: storedRows(rows, rolesOf, FlowchartStateEntryType),
487
+ // Rows a reader read by key through the states' source — a hidden end's, Find's — made stored states (R6, R17).
488
+ rowsOf: rowsReadOf(rowType, rolesOf, FlowchartStateEntryType),
489
+ read: readOf(rowType, rolesOf, FlowchartStateRolesType),
490
+ write,
491
+ create,
492
+ templates: templates?.items ?? East.value([], ArrayType(FlowchartTemplateType)),
493
+ templatesSource: templates?.source === undefined ? none : some(templates.source),
494
+ // The field naming a state's lane: a conflict on it named by the lane's label (#1503).
495
+ laneField: laneField === undefined ? none : some(laneField),
496
+ // Its details, read as the states are: whole, or by the drawn rows' keys (#1507, R19).
497
+ details: details === undefined ? none : some(details.build("states", where, part !== undefined)),
498
+ }, FlowchartStateKindType);
499
+ },
500
+ };
501
+ }
502
+ /**
503
+ * Declares the transitions (see the module docs, R1–R3).
504
+ *
505
+ * @typeParam R - The record's row type
506
+ * @typeParam F - The `from` field
507
+ * @typeParam T - The `to` field
508
+ * @typeParam D - The `decision` field
509
+ * @param binding - The app's record of transitions, bound as `Flowchart.states`' is
510
+ * @param spec - What one is called, its icon, its ends and its decision, its accessors, and its cards, form, Details and check
511
+ * @returns The transitions, for the Flowchart's `transitions`
512
+ * @throws {Error} Naming the role or the binding, as `Flowchart.states` does, and `from`, `to` and `decision` naming one field
513
+ */
514
+ export function flowchartTransitions(binding, spec) {
515
+ const where = "Flowchart.transitions";
516
+ const bound = boundOf(binding, where, "transitions", false);
517
+ const rowType = bound.rowType;
518
+ const role = roleField(rowType, where);
519
+ const entries = entriesOf(bound, spec.entries, where, "transitions");
520
+ const name = wordOf(where, "name", spec.name, "Transition");
521
+ const icon = wordOf(where, "icon", spec.icon, "arrow-right");
522
+ // The ends, each a String field naming a state by its key, and the decision.
523
+ const end = (prop, given) => {
524
+ if (typeof given !== "string")
525
+ throw new Error(`${where}: \`${prop}\` names the String field holding a state's key`);
526
+ return role(prop, given, StringType, "a state by its key, a String field");
527
+ };
528
+ const fromField = end("from", spec.from);
529
+ const toField = end("to", spec.to);
530
+ if (fromField === toField)
531
+ throw new Error(`${where}: \`from\` and \`to\` both name "${fromField}" — a transition's ends are two fields`);
532
+ const decision = spec.decision === undefined ? undefined : textField(rowType, where, "decision", spec.decision);
533
+ if (decision !== undefined && (decision.field === fromField || decision.field === toField)) {
534
+ throw new Error(`${where}: \`decision\` and \`${decision.field === fromField ? "from" : "to"}\` both name "${decision.field}" — a transition's decision and its ends are three fields`);
535
+ }
536
+ // The roles the app computes.
537
+ const kindOf = accessorRole(rowType, where, "kind", FlowchartLinkKindType, "a Flowchart.Types.Kind, planned or observed", spec.kind);
538
+ const evidenceOf = accessorRole(rowType, where, "evidence", OptionType(FlowchartEvidenceType), "an Option of a Flowchart.Types.Evidence", spec.evidence);
539
+ // Its details, read as the transitions are (#1507): what its label draws, checked.
540
+ const details = detailsOf(spec.details, where, "transitions");
541
+ // The cards: every field but the ends.
542
+ const placed = [fromField, toField];
543
+ const ValuesType = valuesTypeOf(rowType, placed);
544
+ const templates = checkedFlowchartTemplates(spec.templates, ValuesType, placed, where);
545
+ // One transition's roles, from its row and its key: a decision's String field, empty, names none.
546
+ const rolesOf = East.function([rowType, StringType], FlowchartTransitionRolesType, ($, row, key) => {
547
+ let named = none;
548
+ if (decision !== undefined) {
549
+ const held = $.const(fieldOf(row, decision.field));
550
+ named = decision.optional ? held : East.equal(held, "").ifElse((_$2) => East.value(none, OptionType(StringType)), (_$2) => East.value(some(held), OptionType(StringType)));
551
+ }
552
+ return East.value({
553
+ from: fieldOf(row, fromField),
554
+ to: fieldOf(row, toField),
555
+ decision: named,
556
+ kind: called($, kindOf, row, key, (k) => k, East.value(variant("planned", null), FlowchartLinkKindType)),
557
+ evidence: called($, evidenceOf, row, key, (e) => e, none),
558
+ }, FlowchartTransitionRolesType);
559
+ });
560
+ // The row with a gesture's ends and decision written over `source`, each where given (R8): a decision cleared is
561
+ // an empty String field, or an Option field holding none.
562
+ const written = (source, w) => ({
563
+ [fromField]: kept(w.from, source, fromField, (k) => k),
564
+ [toField]: kept(w.to, source, toField, (k) => k),
565
+ ...(decision === undefined ? {} : {
566
+ [decision.field]: kept(w.decision, source, decision.field, (d) => decision.optional ? d
567
+ : d.match({ none: (_$) => East.value("", StringType), some: (_$, k) => k })),
568
+ }),
569
+ });
570
+ const write = East.function([BlobType, FlowchartTransitionWriteType], OptionType(BlobType), ($, bytes, w) => {
571
+ const row = $.const(bytes.decodeBeast(rowType, "v2"));
572
+ return East.value(some(East.Blob.encodeBeast(rowWith(rowType, row, written(row, w)), "v2")), OptionType(BlobType));
573
+ });
574
+ // A new transition — Connect — its ends over a card's values, or its type's defaults.
575
+ const source = sourceOf(rowType, ValuesType, placed);
576
+ const create = East.function([FlowchartTransitionWriteType, OptionType(BlobType)], OptionType(BlobType), ($, w, values) => {
577
+ const from = $.const(source);
578
+ const row = $.const(from(values));
579
+ return East.value(some(East.Blob.encodeBeast(rowWith(rowType, row, written(row, w)), "v2")), OptionType(BlobType));
580
+ });
581
+ return {
582
+ [FLOWCHART_DEF]: "transitions",
583
+ rowType,
584
+ name,
585
+ form: bound.form,
586
+ decision: decision !== undefined,
587
+ inspectorReads: details?.inspectorReads ?? false,
588
+ weighedBy: details?.source === undefined ? undefined : { source: details.source, rowType: details.rowType },
589
+ hasTemplates: templates !== undefined,
590
+ templatesSource: templates?.source,
591
+ build(part, every) {
592
+ const { rows, byKey } = readsOf(bound, entries, part, where, "transitions", every);
593
+ const side = recordSide(bound, entries, byKey, spec, [fromField, toField, decision?.field], where);
594
+ return East.value({
595
+ ...side,
596
+ name,
597
+ icon,
598
+ rows: storedRows(rows, rolesOf, FlowchartTransitionEntryType),
599
+ read: readOf(rowType, rolesOf, FlowchartTransitionRolesType),
600
+ write,
601
+ create,
602
+ templates: templates?.items ?? East.value([], ArrayType(FlowchartTemplateType)),
603
+ templatesSource: templates?.source === undefined ? none : some(templates.source),
604
+ // The fields naming its ends and its decision: a conflict on one named by its state's label, or the decision's (#1503).
605
+ fromField,
606
+ toField,
607
+ decisionField: decision === undefined ? none : some(decision.field),
608
+ // Its details, read as the transitions are: whole, or by the drawn rows' keys (#1507, R19).
609
+ details: details === undefined ? none : some(details.build("transitions", where, part !== undefined)),
610
+ }, FlowchartTransitionKindType);
611
+ },
612
+ };
613
+ }
614
+ /**
615
+ * Declares the lanes (see the module docs, R1–R3, D5).
616
+ *
617
+ * @typeParam R - The record's row type
618
+ * @typeParam O - The `order` field
619
+ * @param binding - The app's record of lanes: `Record.bind(record)`, its record declaring `patch: mutation.patch()`, to edit
620
+ * them, or `Data.bind(record)` to read them — each read whole
621
+ * @param spec - What one is called, the fields its header and its order are, and its cards, form and Details
622
+ * @returns The lanes, for the Flowchart's `lanes`
623
+ * @throws {Error} Naming the role or the binding, as `Flowchart.states` does: a paged read, and `entries`, among them —
624
+ * the lanes are read whole
625
+ */
626
+ export function flowchartLanes(binding, spec) {
627
+ const where = "Flowchart.lanes";
628
+ const bound = boundOf(binding, where, "lanes", true);
629
+ const rowType = bound.rowType;
630
+ if (spec.entries !== undefined)
631
+ throw new Error(`${where}: the lanes are read whole — leave entries out`);
632
+ const name = wordOf(where, "name", spec.name, "Lane");
633
+ const label = textField(rowType, where, "label", spec.label);
634
+ // The order: a Float field, or an Integer one, which takes a whole order alone.
635
+ let orderField;
636
+ let integer = false;
637
+ if (spec.order !== undefined) {
638
+ if (typeof spec.order !== "string")
639
+ throw new Error(`${where}: \`order\` names the Integer or Float field placing a lane among the lanes`);
640
+ const type = fieldTypeOf(rowType, where)("order", spec.order);
641
+ integer = isTypeEqual(type, IntegerType);
642
+ if (!integer && !isTypeEqual(type, FloatType)) {
643
+ throw new Error(`${where}: \`order\` names an Integer or a Float field, the lane's place among the lanes — "${spec.order}" holds ${typeText(type)}`);
644
+ }
645
+ orderField = spec.order;
646
+ }
647
+ // The cards: every field but the order.
648
+ const placed = orderField === undefined ? [] : [orderField];
649
+ const ValuesType = valuesTypeOf(rowType, placed);
650
+ const templates = checkedFlowchartTemplates(spec.templates, ValuesType, placed, where);
651
+ // One lane's roles, from its row and its key: an Integer order read as a Float.
652
+ const rolesOf = East.function([rowType, StringType], FlowchartLaneRolesType, ($, row, _key) => {
653
+ let order = none;
654
+ if (orderField !== undefined) {
655
+ const held = $.const(fieldOf(row, orderField));
656
+ order = some(integer ? held.toFloat() : held);
657
+ }
658
+ return East.value({ label: textOf(row, label), order }, FlowchartLaneRolesType);
659
+ });
660
+ // The row with a gesture's label and order written over `source`, each where given (R8); `none` for an order an
661
+ // Integer field can't hold, between two whole numbers — the renderer moves the lanes after it on.
662
+ const laned = ($, source, w) => {
663
+ const result = $.let(East.value(none, OptionType(BlobType)), OptionType(BlobType));
664
+ const fits = orderField === undefined || !integer ? East.value(true)
665
+ : w.order.match({ none: (_$2) => East.value(true), some: (_$2, o) => East.equal(o.remainder(1.0).abs(), 0.0) });
666
+ $.if(fits, ($2) => {
667
+ const set = {
668
+ [label.field]: kept(w.label, source, label.field, (t) => textValue(label, t)),
669
+ ...(orderField === undefined ? {} : {
670
+ [orderField]: kept(w.order, source, orderField, (o) => (integer ? o.toInteger() : o)),
671
+ }),
672
+ };
673
+ $2.assign(result, East.value(some(East.Blob.encodeBeast(rowWith(rowType, source, set), "v2")), OptionType(BlobType)));
674
+ });
675
+ return result;
676
+ };
677
+ const write = East.function([BlobType, FlowchartLaneWriteType], OptionType(BlobType), ($, bytes, w) => {
678
+ const row = $.const(bytes.decodeBeast(rowType, "v2"));
679
+ return laned($, row, w);
680
+ });
681
+ // A new lane — + LANE, or a card dropped between two lanes — over a card's values, or its type's defaults.
682
+ const source = sourceOf(rowType, ValuesType, placed);
683
+ const create = East.function([FlowchartLaneWriteType, OptionType(BlobType)], OptionType(BlobType), ($, w, values) => {
684
+ const from = $.const(source);
685
+ const row = $.const(from(values));
686
+ return laned($, row, w);
687
+ });
688
+ return {
689
+ [FLOWCHART_DEF]: "lanes",
690
+ rowType,
691
+ name,
692
+ form: bound.form,
693
+ hasTemplates: templates !== undefined,
694
+ templatesSource: templates?.source,
695
+ build(_part, _every) {
696
+ const side = recordSide(bound, undefined, undefined, spec, [label.field, orderField], where);
697
+ return East.value({
698
+ ...side,
699
+ name,
700
+ icon: "table-columns",
701
+ rows: storedRows(kindWholeRows(bound.handle, rowType), rolesOf, FlowchartLaneEntryType),
702
+ read: readOf(rowType, rolesOf, FlowchartLaneRolesType),
703
+ write,
704
+ create,
705
+ templates: templates?.items ?? East.value([], ArrayType(FlowchartTemplateType)),
706
+ templatesSource: templates?.source === undefined ? none : some(templates.source),
707
+ }, FlowchartLaneKindType);
708
+ },
709
+ };
710
+ }
711
+ /**
712
+ * Declares the decisions (see the module docs, R1–R3).
713
+ *
714
+ * @typeParam R - The record's row type
715
+ * @param binding - The app's record of decisions, bound as `Flowchart.lanes`' is
716
+ * @param spec - What one is called, its accessors, its queue, and its form and Details
717
+ * @returns The decisions, for the Flowchart's `decisions`
718
+ * @throws {Error} Naming the role or the binding, as `Flowchart.lanes` does, and a `label` that is no accessor
719
+ */
720
+ export function flowchartDecisions(binding, spec) {
721
+ const where = "Flowchart.decisions";
722
+ const bound = boundOf(binding, where, "decisions", true);
723
+ const rowType = bound.rowType;
724
+ if (spec.entries !== undefined)
725
+ throw new Error(`${where}: the decisions are read whole — leave entries out`);
726
+ const name = wordOf(where, "name", spec.name, "Decision");
727
+ if (typeof spec.label !== "function")
728
+ throw new Error(`${where}: \`label\` is an accessor giving a decision's name, (row, key) => …`);
729
+ const labelOf = accessorRole(rowType, where, "label", StringType, "a String", spec.label);
730
+ const letterOf = accessorRole(rowType, where, "letter", OptionType(StringType), "an Option of a String", spec.letter);
731
+ const ownerOf = accessorRole(rowType, where, "owner", OptionType(StringType), "an Option of a String", spec.owner);
732
+ const outcomesOf = accessorRole(rowType, where, "outcomes", OptionType(StringType), "an Option of a String", spec.outcomes);
733
+ // The queue: an Array or a Set of String keys.
734
+ let queue;
735
+ if (spec.queue !== undefined) {
736
+ if (typeof spec.queue !== "string")
737
+ throw new Error(`${where}: \`queue\` names the Array or Set of String field holding the states queued at it, by key`);
738
+ const type = fieldTypeOf(rowType, where)("queue", spec.queue);
739
+ const set = isTypeEqual(type, SetType(StringType));
740
+ if (!set && !isTypeEqual(type, ArrayType(StringType))) {
741
+ throw new Error(`${where}: \`queue\` names an Array or a Set of String field, the states queued at it by key — "${spec.queue}" holds ${typeText(type)}`);
742
+ }
743
+ queue = { field: spec.queue, set };
744
+ }
745
+ // One decision's roles, from its row and its key: a Set queue in its order.
746
+ const rolesOf = East.function([rowType, StringType], FlowchartDecisionRolesType, ($, row, key) => {
747
+ let queued = East.value([], ArrayType(StringType));
748
+ if (queue !== undefined) {
749
+ const held = $.const(fieldOf(row, queue.field));
750
+ queued = queue.set ? held.toArray((_$2, k) => k) : held;
751
+ }
752
+ return East.value({
753
+ label: called($, labelOf, row, key, (l) => l, ""),
754
+ letter: called($, letterOf, row, key, (l) => l, none),
755
+ owner: called($, ownerOf, row, key, (o) => o, none),
756
+ outcomes: called($, outcomesOf, row, key, (o) => o, none),
757
+ queue: queued,
758
+ }, FlowchartDecisionRolesType);
759
+ });
760
+ // A state's key taken out of the queue — a state's Del (R10): the row, or `none` where the key is not queued.
761
+ const unqueue = queue === undefined ? undefined : East.function([BlobType, StringType], OptionType(BlobType), ($, bytes, key) => {
762
+ const row = $.const(bytes.decodeBeast(rowType, "v2"));
763
+ const result = $.let(East.value(none, OptionType(BlobType)), OptionType(BlobType));
764
+ if (queue.set) {
765
+ const held = $.let(fieldOf(row, queue.field));
766
+ $.if(held.tryDelete(key), ($2) => {
767
+ $2.assign(result, East.value(some(East.Blob.encodeBeast(rowWith(rowType, row, { [queue.field]: held }), "v2")), OptionType(BlobType)));
768
+ });
769
+ }
770
+ else {
771
+ const held = $.const(fieldOf(row, queue.field));
772
+ const left = $.const(held.filter((_$2, k) => East.equal(k, key).not()));
773
+ $.if(left.size().equal(held.size()).not(), ($2) => {
774
+ $2.assign(result, East.value(some(East.Blob.encodeBeast(rowWith(rowType, row, { [queue.field]: left }), "v2")), OptionType(BlobType)));
775
+ });
776
+ }
777
+ return result;
778
+ });
779
+ return {
780
+ [FLOWCHART_DEF]: "decisions",
781
+ rowType,
782
+ name,
783
+ form: bound.form,
784
+ hasTemplates: false,
785
+ templatesSource: undefined,
786
+ build(_part, _every) {
787
+ const side = recordSide(bound, undefined, undefined, spec, [queue?.field], where);
788
+ return East.value({
789
+ ...side,
790
+ name,
791
+ icon: "diamond",
792
+ rows: storedRows(kindWholeRows(bound.handle, rowType), rolesOf, FlowchartDecisionEntryType),
793
+ read: readOf(rowType, rolesOf, FlowchartDecisionRolesType),
794
+ unqueue: unqueue === undefined ? none : some(unqueue),
795
+ }, FlowchartDecisionKindType);
796
+ },
797
+ };
798
+ }
799
+ //# sourceMappingURL=kinds.js.map