@elaraai/east-ui 1.0.80 → 1.0.82
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.
- package/dist/src/charts/chart/index.d.ts +4 -0
- package/dist/src/charts/chart/index.d.ts.map +1 -1
- package/dist/src/charts/spec/index.d.ts +8 -0
- package/dist/src/charts/spec/index.d.ts.map +1 -1
- package/dist/src/collections/deck/index.d.ts +8 -0
- package/dist/src/collections/deck/index.d.ts.map +1 -1
- package/dist/src/collections/index.d.ts +2 -2
- package/dist/src/collections/index.d.ts.map +1 -1
- package/dist/src/collections/index.js.map +1 -1
- package/dist/src/collections/library/index.d.ts +4 -0
- package/dist/src/collections/library/index.d.ts.map +1 -1
- package/dist/src/collections/library/types.d.ts +4 -0
- package/dist/src/collections/library/types.d.ts.map +1 -1
- package/dist/src/collections/matrix/index.d.ts +56 -19
- package/dist/src/collections/matrix/index.d.ts.map +1 -1
- package/dist/src/collections/matrix/index.js +38 -24
- package/dist/src/collections/matrix/index.js.map +1 -1
- package/dist/src/collections/plan/assemble.d.ts +655 -2113
- package/dist/src/collections/plan/assemble.d.ts.map +1 -1
- package/dist/src/collections/plan/assemble.js +159 -136
- package/dist/src/collections/plan/assemble.js.map +1 -1
- package/dist/src/collections/plan/builders.d.ts +193 -40
- package/dist/src/collections/plan/builders.d.ts.map +1 -1
- package/dist/src/collections/plan/builders.js +162 -32
- package/dist/src/collections/plan/builders.js.map +1 -1
- package/dist/src/collections/plan/factories.d.ts +290 -116
- package/dist/src/collections/plan/factories.d.ts.map +1 -1
- package/dist/src/collections/plan/factories.js +281 -156
- package/dist/src/collections/plan/factories.js.map +1 -1
- package/dist/src/collections/plan/index.d.ts +111 -58
- package/dist/src/collections/plan/index.d.ts.map +1 -1
- package/dist/src/collections/plan/index.js +62 -31
- package/dist/src/collections/plan/index.js.map +1 -1
- package/dist/src/collections/plan/ir.d.ts +759 -1769
- package/dist/src/collections/plan/ir.d.ts.map +1 -1
- package/dist/src/collections/plan/ir.js +51 -27
- package/dist/src/collections/plan/ir.js.map +1 -1
- package/dist/src/collections/plan/pick.d.ts +89 -71
- package/dist/src/collections/plan/pick.d.ts.map +1 -1
- package/dist/src/collections/plan/pick.js +101 -86
- package/dist/src/collections/plan/pick.js.map +1 -1
- package/dist/src/collections/plan/root.d.ts +164 -77
- package/dist/src/collections/plan/root.d.ts.map +1 -1
- package/dist/src/collections/plan/root.js +350 -42
- package/dist/src/collections/plan/root.js.map +1 -1
- package/dist/src/collections/plan/series.d.ts +12524 -10527
- package/dist/src/collections/plan/series.d.ts.map +1 -1
- package/dist/src/collections/plan/series.js +1596 -298
- package/dist/src/collections/plan/series.js.map +1 -1
- package/dist/src/collections/plan/types.d.ts +6115 -2802
- package/dist/src/collections/plan/types.d.ts.map +1 -1
- package/dist/src/collections/plan/types.js +575 -170
- package/dist/src/collections/plan/types.js.map +1 -1
- package/dist/src/collections/sheet/bridge.d.ts +154 -43
- package/dist/src/collections/sheet/bridge.d.ts.map +1 -1
- package/dist/src/collections/sheet/bridge.js +383 -240
- package/dist/src/collections/sheet/bridge.js.map +1 -1
- package/dist/src/collections/sheet/columns.d.ts +66 -16
- package/dist/src/collections/sheet/columns.d.ts.map +1 -1
- package/dist/src/collections/sheet/columns.js +25 -25
- package/dist/src/collections/sheet/columns.js.map +1 -1
- package/dist/src/collections/sheet/context-bridge.d.ts +48 -0
- package/dist/src/collections/sheet/context-bridge.d.ts.map +1 -0
- package/dist/src/collections/sheet/context-bridge.js +216 -0
- package/dist/src/collections/sheet/context-bridge.js.map +1 -0
- package/dist/src/collections/sheet/draft-bridge.d.ts +37 -0
- package/dist/src/collections/sheet/draft-bridge.d.ts.map +1 -0
- package/dist/src/collections/sheet/draft-bridge.js +153 -0
- package/dist/src/collections/sheet/draft-bridge.js.map +1 -0
- package/dist/src/collections/sheet/drafts.d.ts +14 -0
- package/dist/src/collections/sheet/drafts.d.ts.map +1 -0
- package/dist/src/collections/sheet/drafts.js +14 -0
- package/dist/src/collections/sheet/drafts.js.map +1 -0
- package/dist/src/collections/sheet/editing-bridge.d.ts +36 -0
- package/dist/src/collections/sheet/editing-bridge.d.ts.map +1 -0
- package/dist/src/collections/sheet/editing-bridge.js +196 -0
- package/dist/src/collections/sheet/editing-bridge.js.map +1 -0
- package/dist/src/collections/sheet/editing-types.d.ts +268 -0
- package/dist/src/collections/sheet/editing-types.d.ts.map +1 -0
- package/dist/src/collections/sheet/editing-types.js +34 -0
- package/dist/src/collections/sheet/editing-types.js.map +1 -0
- package/dist/src/collections/sheet/edits.d.ts +37 -0
- package/dist/src/collections/sheet/edits.d.ts.map +1 -0
- package/dist/src/collections/sheet/edits.js +31 -0
- package/dist/src/collections/sheet/edits.js.map +1 -0
- package/dist/src/collections/sheet/group.d.ts +165 -0
- package/dist/src/collections/sheet/group.d.ts.map +1 -0
- package/dist/src/collections/sheet/group.js +52 -0
- package/dist/src/collections/sheet/group.js.map +1 -0
- package/dist/src/collections/sheet/index.d.ts +171 -27
- package/dist/src/collections/sheet/index.d.ts.map +1 -1
- package/dist/src/collections/sheet/index.js +99 -17
- package/dist/src/collections/sheet/index.js.map +1 -1
- package/dist/src/collections/sheet/link.d.ts +22 -16
- package/dist/src/collections/sheet/link.d.ts.map +1 -1
- package/dist/src/collections/sheet/link.js +18 -12
- package/dist/src/collections/sheet/link.js.map +1 -1
- package/dist/src/collections/sheet/registers.d.ts +152 -5
- package/dist/src/collections/sheet/registers.d.ts.map +1 -1
- package/dist/src/collections/sheet/registers.js +154 -5
- package/dist/src/collections/sheet/registers.js.map +1 -1
- package/dist/src/collections/sheet/root.d.ts +175 -26
- package/dist/src/collections/sheet/root.d.ts.map +1 -1
- package/dist/src/collections/sheet/root.js +150 -26
- package/dist/src/collections/sheet/root.js.map +1 -1
- package/dist/src/collections/sheet/seed-bridge.d.ts +14 -0
- package/dist/src/collections/sheet/seed-bridge.d.ts.map +1 -0
- package/dist/src/collections/sheet/seed-bridge.js +51 -0
- package/dist/src/collections/sheet/seed-bridge.js.map +1 -0
- package/dist/src/collections/sheet/sub-rows.d.ts +249 -0
- package/dist/src/collections/sheet/sub-rows.d.ts.map +1 -0
- package/dist/src/collections/sheet/sub-rows.js +222 -0
- package/dist/src/collections/sheet/sub-rows.js.map +1 -0
- package/dist/src/collections/sheet/transactions.d.ts +76 -0
- package/dist/src/collections/sheet/transactions.d.ts.map +1 -0
- package/dist/src/collections/sheet/transactions.js +40 -0
- package/dist/src/collections/sheet/transactions.js.map +1 -0
- package/dist/src/collections/sheet/types.d.ts +12034 -3651
- package/dist/src/collections/sheet/types.d.ts.map +1 -1
- package/dist/src/collections/sheet/types.js +365 -48
- package/dist/src/collections/sheet/types.js.map +1 -1
- package/dist/src/collections/table/index.d.ts +98 -123
- package/dist/src/collections/table/index.d.ts.map +1 -1
- package/dist/src/collections/table/index.js +97 -111
- package/dist/src/collections/table/index.js.map +1 -1
- package/dist/src/collections/table/types.d.ts +87 -31
- package/dist/src/collections/table/types.d.ts.map +1 -1
- package/dist/src/collections/table/types.js +51 -26
- package/dist/src/collections/table/types.js.map +1 -1
- package/dist/src/collections/value-tree/flatten.d.ts.map +1 -1
- package/dist/src/collections/value-tree/flatten.js +4 -1
- package/dist/src/collections/value-tree/flatten.js.map +1 -1
- package/dist/src/component.d.ts +5075 -4079
- package/dist/src/component.d.ts.map +1 -1
- package/dist/src/component.js +46 -46
- package/dist/src/component.js.map +1 -1
- package/dist/src/contracts/approval.d.ts +10 -8
- package/dist/src/contracts/approval.d.ts.map +1 -1
- package/dist/src/contracts/approval.js +10 -8
- package/dist/src/contracts/approval.js.map +1 -1
- package/dist/src/contracts/drag.d.ts +11 -9
- package/dist/src/contracts/drag.d.ts.map +1 -1
- package/dist/src/contracts/drag.js +28 -21
- package/dist/src/contracts/drag.js.map +1 -1
- package/dist/src/contracts/editing.d.ts +1283 -0
- package/dist/src/contracts/editing.d.ts.map +1 -0
- package/dist/src/contracts/editing.js +711 -0
- package/dist/src/contracts/editing.js.map +1 -0
- package/dist/src/contracts/index.d.ts +2 -1
- package/dist/src/contracts/index.d.ts.map +1 -1
- package/dist/src/contracts/index.js +2 -1
- package/dist/src/contracts/index.js.map +1 -1
- package/dist/src/contracts/pick.d.ts +6 -7
- package/dist/src/contracts/pick.d.ts.map +1 -1
- package/dist/src/contracts/pick.js +6 -7
- package/dist/src/contracts/pick.js.map +1 -1
- package/dist/src/contracts/review.d.ts +3 -1
- package/dist/src/contracts/review.d.ts.map +1 -1
- package/dist/src/contracts/review.js +3 -1
- package/dist/src/contracts/review.js.map +1 -1
- package/dist/src/contracts/source.d.ts +270 -80
- package/dist/src/contracts/source.d.ts.map +1 -1
- package/dist/src/contracts/source.js +357 -58
- package/dist/src/contracts/source.js.map +1 -1
- package/dist/src/display/chip-rail/index.d.ts.map +1 -1
- package/dist/src/display/chip-rail/index.js +10 -10
- package/dist/src/display/chip-rail/index.js.map +1 -1
- package/dist/src/extension.d.ts +2 -1
- package/dist/src/extension.d.ts.map +1 -1
- package/dist/src/extension.js +2 -1
- package/dist/src/extension.js.map +1 -1
- package/dist/src/format/index.d.ts +1 -154
- package/dist/src/format/index.d.ts.map +1 -1
- package/dist/src/format/types.d.ts +35 -23
- package/dist/src/format/types.d.ts.map +1 -1
- package/dist/src/format/types.js +16 -14
- package/dist/src/format/types.js.map +1 -1
- package/dist/src/forms/field/index.js +4 -4
- package/dist/src/forms/field/index.js.map +1 -1
- package/dist/src/forms/file-upload/index.js +16 -16
- package/dist/src/forms/file-upload/index.js.map +1 -1
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal.d.ts +8 -3
- package/dist/src/internal.d.ts.map +1 -1
- package/dist/src/internal.js +11 -3
- package/dist/src/internal.js.map +1 -1
- package/dist/src/layout/box/index.d.ts.map +1 -1
- package/dist/src/layout/box/index.js +47 -47
- package/dist/src/layout/box/index.js.map +1 -1
- package/dist/src/layout/flex/index.d.ts.map +1 -1
- package/dist/src/layout/flex/index.js +47 -47
- package/dist/src/layout/flex/index.js.map +1 -1
- package/dist/src/layout/grid/index.js +11 -11
- package/dist/src/layout/grid/index.js.map +1 -1
- package/dist/src/layout/scroll-area/index.d.ts.map +1 -1
- package/dist/src/layout/scroll-area/index.js +8 -8
- package/dist/src/layout/scroll-area/index.js.map +1 -1
- package/dist/src/layout/separator/index.d.ts.map +1 -1
- package/dist/src/layout/separator/index.js +6 -6
- package/dist/src/layout/separator/index.js.map +1 -1
- package/dist/src/layout/stack/index.d.ts.map +1 -1
- package/dist/src/layout/stack/index.js +46 -46
- package/dist/src/layout/stack/index.js.map +1 -1
- package/dist/src/layout/sticky/index.d.ts.map +1 -1
- package/dist/src/layout/sticky/index.js +8 -8
- package/dist/src/layout/sticky/index.js.map +1 -1
- package/dist/src/overlays/action-bar/index.d.ts.map +1 -1
- package/dist/src/overlays/action-bar/index.js +8 -8
- package/dist/src/overlays/action-bar/index.js.map +1 -1
- package/dist/src/platform/index.d.ts +1 -1
- package/dist/src/platform/index.d.ts.map +1 -1
- package/dist/src/platform/index.js +1 -1
- package/dist/src/platform/index.js.map +1 -1
- package/dist/src/platform/slice/impl.d.ts +62 -51
- package/dist/src/platform/slice/impl.d.ts.map +1 -1
- package/dist/src/platform/slice/impl.js +155 -72
- package/dist/src/platform/slice/impl.js.map +1 -1
- package/dist/src/platform/slice/index.d.ts +3744 -2226
- package/dist/src/platform/slice/index.d.ts.map +1 -1
- package/dist/src/platform/slice/index.js +43 -1
- package/dist/src/platform/slice/index.js.map +1 -1
- package/dist/src/runtime/collections/deck.d.ts +4 -0
- package/dist/src/runtime/collections/deck.d.ts.map +1 -1
- package/dist/src/runtime/collections/matrix.d.ts +10 -9
- package/dist/src/runtime/collections/matrix.d.ts.map +1 -1
- package/dist/src/runtime/collections/matrix.js +11 -6
- package/dist/src/runtime/collections/matrix.js.map +1 -1
- package/dist/src/runtime/collections/plan.d.ts +148 -65
- package/dist/src/runtime/collections/plan.d.ts.map +1 -1
- package/dist/src/runtime/collections/plan.js +155 -67
- package/dist/src/runtime/collections/plan.js.map +1 -1
- package/dist/src/runtime/collections/sheet.d.ts +56 -23
- package/dist/src/runtime/collections/sheet.d.ts.map +1 -1
- package/dist/src/runtime/collections/sheet.js +30 -22
- package/dist/src/runtime/collections/sheet.js.map +1 -1
- package/dist/src/runtime/collections/table.d.ts +18 -11
- package/dist/src/runtime/collections/table.d.ts.map +1 -1
- package/dist/src/runtime/collections/table.js +7 -4
- package/dist/src/runtime/collections/table.js.map +1 -1
- package/dist/src/shared/reify.d.ts +4 -46
- package/dist/src/shared/reify.d.ts.map +1 -1
- package/dist/src/shared/reify.js +4 -61
- package/dist/src/shared/reify.js.map +1 -1
- package/dist/src/shared/tree.d.ts +88 -0
- package/dist/src/shared/tree.d.ts.map +1 -0
- package/dist/src/shared/tree.js +134 -0
- package/dist/src/shared/tree.js.map +1 -0
- package/dist/src/slice/breakdown/index.d.ts +4 -0
- package/dist/src/slice/breakdown/index.d.ts.map +1 -1
- package/dist/src/slice/breakdown/types.d.ts +4 -0
- package/dist/src/slice/breakdown/types.d.ts.map +1 -1
- package/dist/src/slice/cohort/index.d.ts +24 -4
- package/dist/src/slice/cohort/index.d.ts.map +1 -1
- package/dist/src/slice/cohort/index.js +8 -4
- package/dist/src/slice/cohort/index.js.map +1 -1
- package/dist/src/slice/cohort/types.d.ts +11 -0
- package/dist/src/slice/cohort/types.d.ts.map +1 -1
- package/dist/src/slice/cohort/types.js +7 -0
- package/dist/src/slice/cohort/types.js.map +1 -1
- package/dist/src/slice/filter/index.d.ts +4 -0
- package/dist/src/slice/filter/index.d.ts.map +1 -1
- package/dist/src/slice/filter/types.d.ts +4 -0
- package/dist/src/slice/filter/types.d.ts.map +1 -1
- package/dist/src/slice/index.d.ts +736 -0
- package/dist/src/slice/index.d.ts.map +1 -1
- package/dist/src/slice/legend/index.d.ts +4 -0
- package/dist/src/slice/legend/index.d.ts.map +1 -1
- package/dist/src/slice/legend/types.d.ts +4 -0
- package/dist/src/slice/legend/types.d.ts.map +1 -1
- package/dist/src/slice/rail/index.d.ts +8 -4
- package/dist/src/slice/rail/index.d.ts.map +1 -1
- package/dist/src/slice/rail/index.js.map +1 -1
- package/dist/src/slice/range/index.d.ts +4 -0
- package/dist/src/slice/range/index.d.ts.map +1 -1
- package/dist/src/slice/range/types.d.ts +4 -0
- package/dist/src/slice/range/types.d.ts.map +1 -1
- package/dist/src/slice/search/index.d.ts +4 -0
- package/dist/src/slice/search/index.d.ts.map +1 -1
- package/dist/src/slice/search/types.d.ts +4 -0
- package/dist/src/slice/search/types.d.ts.map +1 -1
- package/dist/src/slice/summary/index.d.ts +4 -0
- package/dist/src/slice/summary/index.d.ts.map +1 -1
- package/dist/src/slice/summary/types.d.ts +4 -0
- package/dist/src/slice/summary/types.d.ts.map +1 -1
- package/dist/src/typography/code/index.js +1 -1
- package/dist/src/typography/code/index.js.map +1 -1
- package/dist/src/typography/code-block/index.js +7 -7
- package/dist/src/typography/code-block/index.js.map +1 -1
- package/dist/src/typography/heading/index.js +2 -2
- package/dist/src/typography/heading/index.js.map +1 -1
- package/dist/src/typography/list/index.js +1 -1
- package/dist/src/typography/list/index.js.map +1 -1
- package/dist/src/typography/mark/index.js +1 -1
- package/dist/src/typography/mark/index.js.map +1 -1
- package/dist/src/typography/note/index.js +1 -1
- package/dist/src/typography/note/index.js.map +1 -1
- package/dist/src/typography/numeric/index.d.ts +3 -308
- package/dist/src/typography/numeric/index.d.ts.map +1 -1
- package/dist/src/typography/numeric/index.js +4 -4
- package/dist/src/typography/numeric/index.js.map +1 -1
- package/dist/src/typography/numeric/types.d.ts +1 -154
- package/dist/src/typography/numeric/types.d.ts.map +1 -1
- package/dist/src/typography/text/index.js +1 -1
- package/dist/src/typography/text/index.js.map +1 -1
- package/dist/test/collections/matrix.examples.d.ts +7 -3
- package/dist/test/collections/matrix.examples.d.ts.map +1 -1
- package/dist/test/collections/matrix.examples.js +55 -24
- package/dist/test/collections/matrix.examples.js.map +1 -1
- package/dist/test/collections/paged-source.examples.d.ts +4 -0
- package/dist/test/collections/paged-source.examples.d.ts.map +1 -1
- package/dist/test/collections/paged-source.examples.js +98 -13
- package/dist/test/collections/paged-source.examples.js.map +1 -1
- package/dist/test/collections/plan.examples.d.ts +101 -26
- package/dist/test/collections/plan.examples.d.ts.map +1 -1
- package/dist/test/collections/plan.examples.js +1481 -755
- package/dist/test/collections/plan.examples.js.map +1 -1
- package/dist/test/collections/sheet-link.examples.d.ts +7 -0
- package/dist/test/collections/sheet-link.examples.d.ts.map +1 -0
- package/dist/test/collections/sheet-link.examples.js +41 -0
- package/dist/test/collections/sheet-link.examples.js.map +1 -0
- package/dist/test/collections/sheet-transactions.examples.d.ts +7 -0
- package/dist/test/collections/sheet-transactions.examples.d.ts.map +1 -0
- package/dist/test/collections/sheet-transactions.examples.js +58 -0
- package/dist/test/collections/sheet-transactions.examples.js.map +1 -0
- package/dist/test/collections/sheet.examples.d.ts +52 -5
- package/dist/test/collections/sheet.examples.d.ts.map +1 -1
- package/dist/test/collections/sheet.examples.js +500 -158
- package/dist/test/collections/sheet.examples.js.map +1 -1
- package/dist/test/collections/table.examples.d.ts +31 -3
- package/dist/test/collections/table.examples.d.ts.map +1 -1
- package/dist/test/collections/table.examples.js +188 -28
- package/dist/test/collections/table.examples.js.map +1 -1
- package/dist/test/contracts/editing.examples.d.ts +7 -0
- package/dist/test/contracts/editing.examples.d.ts.map +1 -0
- package/dist/test/contracts/editing.examples.js +58 -0
- package/dist/test/contracts/editing.examples.js.map +1 -0
- package/dist/test/layout/splitter.examples.d.ts.map +1 -1
- package/dist/test/layout/splitter.examples.js +3 -1
- package/dist/test/layout/splitter.examples.js.map +1 -1
- package/dist/test/platform/slice.examples.d.ts.map +1 -1
- package/dist/test/platform/slice.examples.js +1 -0
- package/dist/test/platform/slice.examples.js.map +1 -1
- package/dist/test/slice/slice.examples.d.ts.map +1 -1
- package/dist/test/slice/slice.examples.js +5 -2
- package/dist/test/slice/slice.examples.js.map +1 -1
- package/package.json +4 -3
- package/dist/src/collections/plan/data-forms.d.ts +0 -332
- package/dist/src/collections/plan/data-forms.d.ts.map +0 -1
- package/dist/src/collections/plan/data-forms.js +0 -212
- package/dist/src/collections/plan/data-forms.js.map +0 -1
|
@@ -15,22 +15,42 @@
|
|
|
15
15
|
* - `rowById` — the REAL source row by id: the captured collection or bind
|
|
16
16
|
* handle on the inline arm, the source's `page` at the row's offset on the
|
|
17
17
|
* paged arm. Built ONCE per sheet and shared by every wrapper;
|
|
18
|
-
* - `
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* - `
|
|
18
|
+
* - `draftDecode` — current cells over the existing field draft, preserving
|
|
19
|
+
* hidden values and retaining missing/invalid input without domain defaults;
|
|
20
|
+
* - `bridgeCtx` — the wire context to `Sheet.Types.DraftContext(R, D)`;
|
|
21
|
+
* - `bridgeReady` — a readiness batch to one `DraftContext` per check, its
|
|
22
|
+
* rows built once (#882);
|
|
22
23
|
* - the wrappers — a fill provider, a proposer, an arity rule, a member
|
|
23
|
-
* check, a custom kind's parse / print
|
|
24
|
-
* function inside its closed wire twin
|
|
24
|
+
* check, an options rule, a custom kind's parse / print — each the
|
|
25
|
+
* author's typed function inside its closed wire twin;
|
|
26
|
+
* - the rule cells and sub rows (#844) — a column's `level` / `actual` /
|
|
27
|
+
* `detail` accessors and the `subRows` mappers, each compiled once and
|
|
28
|
+
* called inside the row projection.
|
|
29
|
+
*
|
|
30
|
+
* On a GROUPED sheet (#740) the source row is the group `P` and the columns
|
|
31
|
+
* are declared over the line `L` its lines field holds: `projectRow` /
|
|
32
|
+
* `draftRow` / the patch run over `L`, `rowById` returns the group, and the
|
|
33
|
+
* group half of the bridge ({@link SheetGroupBridge}) projects the group's
|
|
34
|
+
* summary cells and ordered children. Internal child keys preserve identity
|
|
35
|
+
* during local editing; the author's child arrays remain positional. A
|
|
36
|
+
* source with LOOSE rows between its groups (#846) holds entries
|
|
37
|
+
* `Sheet.Types.Entry(P, "lines")`: `rowById` returns the entry, a draft is
|
|
38
|
+
* the entry's draft, and a loose row decodes as a row of `L` whose id is its
|
|
39
|
+
* own.
|
|
25
40
|
*
|
|
26
41
|
* The bridge is the one place a string ever names a field: inside the
|
|
27
42
|
* factory, against the column list it has already validated.
|
|
28
43
|
*
|
|
29
44
|
* @packageDocumentation
|
|
30
45
|
*/
|
|
31
|
-
import { East, Expr, ArrayType, AsyncFunctionType, BooleanType, DateTimeType, DictType, FloatType, FunctionType, IntegerType, NullType, OptionType, StringType, StructType,
|
|
32
|
-
import { SheetCellType, SheetLinkType, SheetContextType, SheetFillType, SheetProposalType, SheetProviderType, SheetProposerType, SheetCheckContextType, SheetCheckType, SheetCountedType,
|
|
33
|
-
import {
|
|
46
|
+
import { East, Expr, ArrayType, AsyncFunctionType, BooleanType, DateTimeType, DictType, FloatType, FunctionType, IntegerType, NullType, OptionType, StringType, StructType, isTypeEqual, variant, some, none, } from "@elaraai/east";
|
|
47
|
+
import { SheetCellType, SheetLinkType, SheetRowType, SheetLineType, SheetContextType, SheetReadyBatchType, SheetFillType, SheetProposalType, SheetProviderType, SheetProposerType, SheetCheckContextType, SheetCheckType, SheetCountedType, SheetHalfType, SheetContextTypeFor, SheetCheckContextTypeFor, SheetPatchTypeFor, SheetProposalTypeFor, SheetGroupContextTypeFor, SheetGroupCheckContextTypeFor, SheetDateLevelType, SheetSubRowType, SheetOptionsRuleType, sheetLinesOf, sheetRuleCell, } from "./types.js";
|
|
48
|
+
import { resolveTag } from "../plan/builders.js";
|
|
49
|
+
import { SheetMembersType, SheetRegisterMembersType, parseLink, EMPTY_LINK } from "./link.js";
|
|
50
|
+
import { buildDraftRowDecoder, buildDraftGroupDecoder, buildDraftEntryDecoder } from "./draft-bridge.js";
|
|
51
|
+
import { buildDraftContextBridge, buildDraftBase, buildReadyContexts } from "./context-bridge.js";
|
|
52
|
+
import { SheetDraftEntryTypeFor, SheetDraftGroupTypeFor } from "./drafts.js";
|
|
53
|
+
import { SheetDraftTypeFor } from "./transactions.js";
|
|
34
54
|
/** The wire cells dictionary type. */
|
|
35
55
|
export const SheetCellsType = DictType(StringType, SheetCellType);
|
|
36
56
|
/** The East type of an erased expression (`Expr.type` cannot infer through `ExprType<EastType>`). */
|
|
@@ -51,7 +71,7 @@ export function optionPayload(t) {
|
|
|
51
71
|
}
|
|
52
72
|
/** The cell arm a primitive payload lands in, or `undefined` for a type no cell holds. */
|
|
53
73
|
export function cellTagOf(t) {
|
|
54
|
-
if (t
|
|
74
|
+
if (isTypeEqual(t, SheetLinkType))
|
|
55
75
|
return "Link";
|
|
56
76
|
switch (t.type) {
|
|
57
77
|
case "String": return "String";
|
|
@@ -66,6 +86,45 @@ const SCALAR_PAYLOAD = {
|
|
|
66
86
|
text: StringType, lookup: StringType, reference: StringType, enum: StringType, stamped: StringType,
|
|
67
87
|
date: DateTimeType, quantity: FloatType, integer: IntegerType,
|
|
68
88
|
};
|
|
89
|
+
/** Compile one rule accessor and check its payload — `String` or `DateTime`, or its Option. */
|
|
90
|
+
function ruleCell(key, rule, rowType, accessor, tag) {
|
|
91
|
+
const fn = East.function([rowType], undefined, (_$, r) => accessor(r));
|
|
92
|
+
const out = Expr.type(fn).output;
|
|
93
|
+
const payload = optionPayload(out);
|
|
94
|
+
const unwrapped = payload ?? out;
|
|
95
|
+
if (cellTagOf(unwrapped) !== tag) {
|
|
96
|
+
throw new Error(`Sheet: column "${key}" has a \`${rule}\` rule returning ${describeType(out)} — it must return ${tag} or Option<${tag}>`);
|
|
97
|
+
}
|
|
98
|
+
return { key: sheetRuleCell(rule, key), fn, tag, optional: payload !== undefined };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The unrendered cells a column's rules project (#844) — `detail` on any
|
|
102
|
+
* column, `level` and `actual` on a date column.
|
|
103
|
+
*/
|
|
104
|
+
function ruleCellsOf(key, kind, cfg, rowType) {
|
|
105
|
+
const out = [];
|
|
106
|
+
if (cfg.detail !== undefined)
|
|
107
|
+
out.push(ruleCell(key, "detail", rowType, cfg.detail, "String"));
|
|
108
|
+
if (kind !== "date") {
|
|
109
|
+
if (cfg.level !== undefined || cfg.actual !== undefined) {
|
|
110
|
+
throw new Error(`Sheet: column "${key}" is a ${kind} column — \`level\` and \`actual\` are date-column rules`);
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
if (cfg.level !== undefined) {
|
|
115
|
+
const level = cfg.level;
|
|
116
|
+
const fn = East.function([rowType], StringType, (_$, r) => resolveTag(level(r), SheetDateLevelType).match({
|
|
117
|
+
week: (_$2) => "week",
|
|
118
|
+
day: (_$2) => "day",
|
|
119
|
+
range: (_$2) => "range",
|
|
120
|
+
time: (_$2) => "time",
|
|
121
|
+
}));
|
|
122
|
+
out.push({ key: sheetRuleCell("level", key), fn, tag: "String", optional: false });
|
|
123
|
+
}
|
|
124
|
+
if (cfg.actual !== undefined)
|
|
125
|
+
out.push(ruleCell(key, "actual", rowType, cfg.actual, "DateTime"));
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
69
128
|
/**
|
|
70
129
|
* Describe one column against the row type — the build-time refusals of
|
|
71
130
|
* §3.12 live here, every one naming the column and the remedy.
|
|
@@ -77,6 +136,15 @@ const SCALAR_PAYLOAD = {
|
|
|
77
136
|
* @throws Error naming the column when the kind cannot sit on the field
|
|
78
137
|
*/
|
|
79
138
|
export function describeColumn(key, col, rowType) {
|
|
139
|
+
const meta = describeKind(key, col, rowType);
|
|
140
|
+
const ruleCells = ruleCellsOf(key, col.kind, col.config, rowType);
|
|
141
|
+
if (col.config.options !== undefined && col.kind !== "enum" && col.kind !== "lookup" && col.kind !== "link") {
|
|
142
|
+
throw new Error(`Sheet: column "${key}" is a ${col.kind} column — an \`options\` rule narrows an enum, lookup or link column's members`);
|
|
143
|
+
}
|
|
144
|
+
return ruleCells.length > 0 ? { ...meta, ruleCells } : meta;
|
|
145
|
+
}
|
|
146
|
+
/** {@link describeColumn}'s kind-by-kind half. */
|
|
147
|
+
function describeKind(key, col, rowType) {
|
|
80
148
|
const fields = rowType.fields;
|
|
81
149
|
const fieldType = fields[key];
|
|
82
150
|
if (fieldType === undefined) {
|
|
@@ -94,11 +162,11 @@ export function describeColumn(key, col, rowType) {
|
|
|
94
162
|
const out = Expr.type(derived).output;
|
|
95
163
|
const outPayload = optionPayload(out);
|
|
96
164
|
const outUnwrapped = outPayload ?? out;
|
|
97
|
-
if (outUnwrapped
|
|
165
|
+
if (!isTypeEqual(outUnwrapped, payloadType)) {
|
|
98
166
|
throw new Error(`Sheet: column "${key}" is a ${kind} column whose \`value\` projection returns ${outUnwrapped.type} — a ${kind} column's projection must return ${payloadType.type} or its Option`);
|
|
99
167
|
}
|
|
100
168
|
return {
|
|
101
|
-
key, kind, config: cfg, fieldType, optional, payloadType,
|
|
169
|
+
key, field: key, kind, config: cfg, fieldType, optional, payloadType,
|
|
102
170
|
cellTag: cellTagOf(payloadType), editable: false,
|
|
103
171
|
derived, derivedOptional: outPayload !== undefined,
|
|
104
172
|
...(col.register !== undefined ? { register: col.register } : {}),
|
|
@@ -109,10 +177,10 @@ export function describeColumn(key, col, rowType) {
|
|
|
109
177
|
let form;
|
|
110
178
|
let ownHalf;
|
|
111
179
|
let otherField;
|
|
112
|
-
if (fieldType
|
|
180
|
+
if (isTypeEqual(fieldType, SheetLinkType) || isTypeEqual(unwrapped, SheetLinkType)) {
|
|
113
181
|
form = "link";
|
|
114
182
|
}
|
|
115
|
-
else if (fieldType
|
|
183
|
+
else if (isTypeEqual(fieldType, SheetMembersType)) {
|
|
116
184
|
form = "array";
|
|
117
185
|
if (kind === "set") {
|
|
118
186
|
ownHalf = "to";
|
|
@@ -128,7 +196,8 @@ export function describeColumn(key, col, rowType) {
|
|
|
128
196
|
else {
|
|
129
197
|
throw new Error(`Sheet: link column "${key}" sits on an Array<Member> field, so it must name the OTHER half's field — \`to: "…"\` when this field holds the from members, \`from: "…"\` when it holds the to members`);
|
|
130
198
|
}
|
|
131
|
-
|
|
199
|
+
const otherType = otherField !== undefined ? fields[otherField] : undefined;
|
|
200
|
+
if (otherField !== undefined && (otherType === undefined || !isTypeEqual(otherType, SheetMembersType))) {
|
|
132
201
|
throw new Error(`Sheet: link column "${key}" names "${otherField}" as its other half, but that is not an Array<Sheet.Types.Member> field of the row`);
|
|
133
202
|
}
|
|
134
203
|
}
|
|
@@ -139,7 +208,7 @@ export function describeColumn(key, col, rowType) {
|
|
|
139
208
|
throw new Error(`Sheet: ${kind} column "${key}" must sit on a Sheet.Types.Link, Array<Sheet.Types.Member> or String field — got ${fieldType.type}`);
|
|
140
209
|
}
|
|
141
210
|
return {
|
|
142
|
-
key, kind, config: cfg, fieldType, optional: form === "link" ? unwrapped
|
|
211
|
+
key, field: key, kind, config: cfg, fieldType, optional: form === "link" ? isTypeEqual(unwrapped, SheetLinkType) && optional : optional,
|
|
143
212
|
payloadType: SheetLinkType, cellTag: "Link", editable: cfg.editable !== false,
|
|
144
213
|
form,
|
|
145
214
|
...(ownHalf !== undefined ? { ownHalf } : {}),
|
|
@@ -155,27 +224,50 @@ export function describeColumn(key, col, rowType) {
|
|
|
155
224
|
if (parsed === undefined) {
|
|
156
225
|
throw new Error(`Sheet: custom column "${key}" has a \`parse\` whose output is not an Option — it must return Option<payload>, \`none\` meaning unrecognised`);
|
|
157
226
|
}
|
|
158
|
-
if (parsed
|
|
227
|
+
if (!isTypeEqual(parsed, unwrapped)) {
|
|
159
228
|
throw new Error(`Sheet: custom column "${key}" parses to ${parsed.type} but sits on a ${unwrapped.type} field — the payload must be the field's type (or its Option's)`);
|
|
160
229
|
}
|
|
161
230
|
const tag = cellTagOf(parsed);
|
|
162
231
|
if (tag === undefined) {
|
|
163
232
|
throw new Error(`Sheet: custom column "${key}" has payload ${parsed.type}, which no cell holds — use String, Integer, Float, DateTime, Boolean or Sheet.Types.Link`);
|
|
164
233
|
}
|
|
165
|
-
return { key, kind, config: cfg, fieldType, optional, payloadType: parsed, cellTag: tag, editable: cfg.editable !== false };
|
|
234
|
+
return { key, field: key, kind, config: cfg, fieldType, optional, payloadType: parsed, cellTag: tag, editable: cfg.editable !== false };
|
|
166
235
|
}
|
|
167
236
|
const payloadType = SCALAR_PAYLOAD[kind];
|
|
168
|
-
if (unwrapped
|
|
237
|
+
if (!isTypeEqual(unwrapped, payloadType)) {
|
|
169
238
|
throw new Error(`Sheet: ${kind} column "${key}" must sit on a ${payloadType.type} or Option<${payloadType.type}> field — got ${fieldType.type}`);
|
|
170
239
|
}
|
|
171
240
|
return {
|
|
172
|
-
key, kind, config: cfg, fieldType, optional, payloadType,
|
|
241
|
+
key, field: key, kind, config: cfg, fieldType, optional, payloadType,
|
|
173
242
|
cellTag: cellTagOf(payloadType),
|
|
174
243
|
editable: kind !== "stamped" && cfg.editable !== false,
|
|
175
244
|
...(col.register !== undefined ? { register: col.register } : {}),
|
|
176
245
|
...(col.driverType !== undefined ? { driverType: col.driverType } : {}),
|
|
177
246
|
};
|
|
178
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Describe one band cell against the GROUP's row type (#740) — a column
|
|
250
|
+
* declared over the group's field, keyed by the line column it sits under.
|
|
251
|
+
*
|
|
252
|
+
* @param cellKey - The line column the cell sits under, or `$title`
|
|
253
|
+
* @param cell - The built band cell
|
|
254
|
+
* @param groupType - The group's row type
|
|
255
|
+
* @returns The cell's metadata
|
|
256
|
+
* @throws Error naming the band cell when the kind cannot sit on the field, or is not a band kind
|
|
257
|
+
*/
|
|
258
|
+
export function describeGroupCell(cellKey, cell, groupType) {
|
|
259
|
+
if (cell.kind === "lookup" || cell.kind === "set" || cell.kind === "link" || cell.kind === "custom") {
|
|
260
|
+
throw new Error(`Sheet: band cell "${cellKey}" is a ${cell.kind} cell — a band draws text, date, quantity, integer, reference, enum and stamped cells only`);
|
|
261
|
+
}
|
|
262
|
+
let meta;
|
|
263
|
+
try {
|
|
264
|
+
meta = describeColumn(cell.field, { kind: cell.kind, config: cell.config, ...(cell.register !== undefined ? { register: cell.register } : {}) }, groupType);
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
throw new Error(`Sheet: band cell "${cellKey}" — ${e.message.replace(/^Sheet: /, "")}`);
|
|
268
|
+
}
|
|
269
|
+
return { ...meta, key: cellKey, field: cell.field };
|
|
270
|
+
}
|
|
179
271
|
// ============================================================================
|
|
180
272
|
// Cells — payload ↔ cell (the static-tag moves)
|
|
181
273
|
// ============================================================================
|
|
@@ -186,11 +278,11 @@ export function cellOfPayload(tag, v) {
|
|
|
186
278
|
/** The blank cell. */
|
|
187
279
|
export const NULL_CELL = East.value(variant("Null", null), SheetCellType);
|
|
188
280
|
/** A field VALUE (the payload or its Option) as a cell, by the column's static shape. */
|
|
189
|
-
function cellOfFieldValue(
|
|
281
|
+
function cellOfFieldValue(tag, v, optional) {
|
|
190
282
|
if (!optional)
|
|
191
|
-
return cellOfPayload(
|
|
283
|
+
return cellOfPayload(tag, v);
|
|
192
284
|
return v.match({
|
|
193
|
-
some: (_$, x) => cellOfPayload(
|
|
285
|
+
some: (_$, x) => cellOfPayload(tag, x),
|
|
194
286
|
none: (_$) => NULL_CELL,
|
|
195
287
|
});
|
|
196
288
|
}
|
|
@@ -202,13 +294,13 @@ function cellOfFieldValue(meta, v, optional) {
|
|
|
202
294
|
function projectCell(meta, r, members) {
|
|
203
295
|
const row = r;
|
|
204
296
|
if (meta.derived !== undefined) {
|
|
205
|
-
return cellOfFieldValue(meta, meta.derived(r), meta.derivedOptional === true);
|
|
297
|
+
return cellOfFieldValue(meta.cellTag, meta.derived(r), meta.derivedOptional === true);
|
|
206
298
|
}
|
|
207
|
-
const fv = row[meta.
|
|
299
|
+
const fv = row[meta.field];
|
|
208
300
|
if (meta.form === undefined)
|
|
209
|
-
return cellOfFieldValue(meta, fv, meta.optional);
|
|
301
|
+
return cellOfFieldValue(meta.cellTag, fv, meta.optional);
|
|
210
302
|
if (meta.form === "link")
|
|
211
|
-
return cellOfFieldValue(meta, fv, meta.optional);
|
|
303
|
+
return cellOfFieldValue(meta.cellTag, fv, meta.optional);
|
|
212
304
|
if (meta.form === "array") {
|
|
213
305
|
const half = fv;
|
|
214
306
|
const empty = East.value([], SheetMembersType);
|
|
@@ -227,54 +319,19 @@ function projectCell(meta, r, members) {
|
|
|
227
319
|
none: (_$) => NULL_CELL,
|
|
228
320
|
});
|
|
229
321
|
}
|
|
230
|
-
/** The field value a cell decodes to — the payload or its Option, by the column's static shape. */
|
|
231
|
-
function fieldValueOfCell(meta, cell, optional, payloadType) {
|
|
232
|
-
if (optional) {
|
|
233
|
-
return cell.match({ [meta.cellTag]: (_$, v) => East.value(some(v), OptionType(payloadType)) }, (_$) => East.value(none, OptionType(payloadType)));
|
|
234
|
-
}
|
|
235
|
-
return cell.match({ [meta.cellTag]: (_$, v) => v }, (_$) => East.value(defaultValue(payloadType), payloadType));
|
|
236
|
-
}
|
|
237
322
|
/**
|
|
238
|
-
* The
|
|
239
|
-
*
|
|
240
|
-
* bound in the caller's block, for the String link form's canonical print.
|
|
323
|
+
* The id of a row — the id field; on a source with loose rows (#846) the id
|
|
324
|
+
* field of whichever arm the entry holds.
|
|
241
325
|
*/
|
|
242
|
-
function decodeOwnField(meta, cellOpt, base, members) {
|
|
243
|
-
if (!meta.editable)
|
|
244
|
-
return base;
|
|
245
|
-
// The String form prints the link back through the grammar — the keys as
|
|
246
|
-
// typed, or the register's labels under `store: "canonical"` (B§4.2).
|
|
247
|
-
const print = (l) => meta.config.store === "canonical" && members !== undefined ? printLinkWith(l, members) : printLink(l);
|
|
248
|
-
return cellOpt.match({
|
|
249
|
-
none: (_$) => base,
|
|
250
|
-
some: (_$, cell) => {
|
|
251
|
-
if (meta.form === undefined)
|
|
252
|
-
return fieldValueOfCell(meta, cell, meta.optional, meta.payloadType);
|
|
253
|
-
if (meta.form === "link")
|
|
254
|
-
return fieldValueOfCell(meta, cell, meta.optional, SheetLinkType);
|
|
255
|
-
if (meta.form === "array") {
|
|
256
|
-
return cell.match({ Link: (_$2, l) => meta.ownHalf === "from" ? l.from : l.to }, (_$2) => East.value([], SheetMembersType));
|
|
257
|
-
}
|
|
258
|
-
if (meta.optional) {
|
|
259
|
-
return cell.match({ Link: (_$2, l) => East.value(some(print(l)), OptionType(StringType)) }, (_$2) => East.value(none, OptionType(StringType)));
|
|
260
|
-
}
|
|
261
|
-
return cell.match({ Link: (_$2, l) => print(l) }, (_$2) => East.value("", StringType));
|
|
262
|
-
},
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
/** The OTHER half's field of an `array`-form link column, from that column's cell. */
|
|
266
|
-
function decodeOtherHalf(meta, cellOpt, base) {
|
|
267
|
-
if (!meta.editable)
|
|
268
|
-
return base;
|
|
269
|
-
return cellOpt.match({
|
|
270
|
-
none: (_$) => base,
|
|
271
|
-
some: (_$, cell) => cell.match({ Link: (_$2, l) => meta.ownHalf === "from" ? l.to : l.from }, (_$2) => East.value([], SheetMembersType)),
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
/** The id of a row — the id field, or the key of a keyed window. */
|
|
275
326
|
function idOf(r, idField) {
|
|
276
327
|
if (idField === undefined)
|
|
277
328
|
throw new Error("Sheet: a positional source needs `id` — the String field that identifies a row");
|
|
329
|
+
if (Expr.type(r).type === "Variant") {
|
|
330
|
+
return r.match({
|
|
331
|
+
group: (_$, g) => g[idField],
|
|
332
|
+
row: (_$, l) => l[idField],
|
|
333
|
+
});
|
|
334
|
+
}
|
|
278
335
|
return r[idField];
|
|
279
336
|
}
|
|
280
337
|
/**
|
|
@@ -284,23 +341,28 @@ function idOf(r, idField) {
|
|
|
284
341
|
* @returns The bridge
|
|
285
342
|
*/
|
|
286
343
|
export function buildBridge(input) {
|
|
287
|
-
const { rowType, idField, metas, registers, driver, source } = input;
|
|
344
|
+
const { rowType, idField, metas, registers, driver, source, group: groupInput, subRows } = input;
|
|
288
345
|
const driverType = driver !== undefined ? driver.rowType : NullType;
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
346
|
+
// A grouped sheet's columns are declared over the LINE type; its source
|
|
347
|
+
// rows are groups — or, with loose rows between them (#846), entries of a
|
|
348
|
+
// group or a row of the line type. A flat sheet's line type is its row type.
|
|
349
|
+
const loose = rowType.type === "Variant";
|
|
350
|
+
const groupType = loose ? rowType.cases.group : rowType;
|
|
351
|
+
const shape = groupInput !== undefined ? sheetLinesOf(groupType, groupInput.linesField) : undefined;
|
|
352
|
+
const lineType = shape?.lineType ?? groupType;
|
|
353
|
+
const lineIdField = shape === undefined ? idField : undefined;
|
|
354
|
+
const ctxType = (groupInput !== undefined
|
|
355
|
+
? SheetGroupContextTypeFor(groupType, groupInput.linesField, driverType)
|
|
356
|
+
: SheetContextTypeFor(lineType, driverType));
|
|
357
|
+
const checkCtxType = (groupInput !== undefined
|
|
358
|
+
? SheetGroupCheckContextTypeFor(groupType, groupInput.linesField)
|
|
359
|
+
: SheetCheckContextTypeFor(lineType));
|
|
360
|
+
const patchType = SheetPatchTypeFor(lineType);
|
|
361
|
+
const proposalType = SheetProposalTypeFor(lineType);
|
|
362
|
+
// L → the wire cells. Registers are bound ONCE per body for the String
|
|
301
363
|
// link form (the capture rule: data, never a spliced expression).
|
|
302
364
|
const stringFormRegisters = [...new Set(metas.filter((m) => m.form === "string" && m.register !== undefined).map((m) => m.register))];
|
|
303
|
-
const projectRow = East.function([
|
|
365
|
+
const projectRow = East.function([lineType], SheetCellsType, ($, r) => {
|
|
304
366
|
const cells = $.let(new Map(), SheetCellsType);
|
|
305
367
|
const bound = new Map();
|
|
306
368
|
for (const name of stringFormRegisters) {
|
|
@@ -308,47 +370,41 @@ export function buildBridge(input) {
|
|
|
308
370
|
}
|
|
309
371
|
for (const m of metas) {
|
|
310
372
|
$(cells.insert(m.key, projectCell(m, r, m.register !== undefined ? bound.get(m.register) : undefined)));
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
// (id, cells, base) → R: the base row (the type's default when absent),
|
|
315
|
-
// every column's field from its cell, the id field from the wire id.
|
|
316
|
-
const decode = East.function([StringType, SheetCellsType, OptionType(rowType)], rowType, ($, id, cells, base) => {
|
|
317
|
-
const b = $.let(base.match({
|
|
318
|
-
some: (_$, x) => x,
|
|
319
|
-
none: (_$) => East.value(defaultValue(rowType), rowType),
|
|
320
|
-
}), rowType);
|
|
321
|
-
// The String link form's registers, bound once per body (the capture rule).
|
|
322
|
-
const bound = new Map();
|
|
323
|
-
for (const name of stringFormRegisters) {
|
|
324
|
-
bound.set(name, $.const(registers[name], SheetRegisterMembersType));
|
|
325
|
-
}
|
|
326
|
-
const out = {};
|
|
327
|
-
for (const f of Object.keys(fields)) {
|
|
328
|
-
const baseField = $.let(b[f], fields[f]);
|
|
329
|
-
if (f === idField) {
|
|
330
|
-
out[f] = id;
|
|
331
|
-
continue;
|
|
373
|
+
for (const rc of m.ruleCells ?? []) {
|
|
374
|
+
const rule = $.const(rc.fn);
|
|
375
|
+
$(cells.insert(rc.key, cellOfFieldValue(rc.tag, rule(r), rc.optional)));
|
|
332
376
|
}
|
|
333
|
-
const own = byField.get(f);
|
|
334
|
-
if (own !== undefined) {
|
|
335
|
-
out[f] = decodeOwnField(own, cells.tryGet(own.key), baseField, own.register !== undefined ? bound.get(own.register) : undefined);
|
|
336
|
-
continue;
|
|
337
|
-
}
|
|
338
|
-
const other = otherHalfBy.get(f);
|
|
339
|
-
if (other !== undefined) {
|
|
340
|
-
out[f] = decodeOtherHalf(other, cells.tryGet(other.key), baseField);
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
out[f] = baseField;
|
|
344
377
|
}
|
|
345
|
-
return
|
|
378
|
+
return cells;
|
|
346
379
|
});
|
|
347
|
-
|
|
380
|
+
const projectSubRows = buildSubRowProjection(lineType, subRows);
|
|
381
|
+
// (id, offset) → the real source row. Inline, the row at its offset
|
|
382
|
+
// answers first — the renderer reads a resident row where it sits — and
|
|
383
|
+
// otherwise the nearest match outward from there, so a row that a local
|
|
384
|
+
// edit shifted is found in the steps it moved: a read is never a scan of
|
|
385
|
+
// the collection, which made every context and every readiness check
|
|
386
|
+
// quadratic in the rows (#859). The search starts inside the rows, so a
|
|
387
|
+
// stale offset still finds the row.
|
|
348
388
|
const rowById = source.kind === "inline"
|
|
349
|
-
? East.function([StringType, IntegerType], OptionType(rowType), ($, id,
|
|
389
|
+
? East.function([StringType, IntegerType], OptionType(rowType), ($, id, offset) => {
|
|
350
390
|
const rows = $.const(source.rows, ArrayType(rowType));
|
|
351
|
-
|
|
391
|
+
const size = $.let(rows.size());
|
|
392
|
+
const start = $.let(offset.less(0n).ifElse(() => 0n, () => offset.greaterEqual(size).ifElse(() => size.subtract(1n), () => offset)));
|
|
393
|
+
const step = $.let(0n);
|
|
394
|
+
$.while(start.subtract(step).greaterEqual(0n).or(() => start.add(step).less(size)), ($2) => {
|
|
395
|
+
const below = $2.let(start.subtract(step));
|
|
396
|
+
$2.if(below.greaterEqual(0n), ($3) => {
|
|
397
|
+
const r = $3.let(rows.get(below));
|
|
398
|
+
$3.if(idOf(r, idField).equal(id), ($4) => { $4.return(East.value(some(r), OptionType(rowType))); });
|
|
399
|
+
});
|
|
400
|
+
const above = $2.let(start.add(step));
|
|
401
|
+
$2.if(step.greater(0n).and(() => above.less(size)), ($3) => {
|
|
402
|
+
const r = $3.let(rows.get(above));
|
|
403
|
+
$3.if(idOf(r, idField).equal(id), ($4) => { $4.return(East.value(some(r), OptionType(rowType))); });
|
|
404
|
+
});
|
|
405
|
+
$2.assign(step, step.add(1n));
|
|
406
|
+
});
|
|
407
|
+
return East.value(none, OptionType(rowType));
|
|
352
408
|
})
|
|
353
409
|
: East.function([StringType, IntegerType], OptionType(rowType), ($, id, offset) => {
|
|
354
410
|
const src = $.const(source.source);
|
|
@@ -368,28 +424,46 @@ export function buildBridge(input) {
|
|
|
368
424
|
return dict.tryGet(k);
|
|
369
425
|
})
|
|
370
426
|
: East.function([StringType], OptionType(driverType), ($, _k) => $.const(none, OptionType(driverType)));
|
|
371
|
-
// The
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const
|
|
427
|
+
// The drafts: a line's cells over its draft (no id — a line's identity is
|
|
428
|
+
// its place), and on a source with loose rows (#846) a loose row's, whose
|
|
429
|
+
// id field is its own.
|
|
430
|
+
const draftRow = buildDraftRowDecoder(lineType, metas, registers, lineIdField);
|
|
431
|
+
const looseRow = loose ? buildDraftRowDecoder(lineType, metas, registers, idField) : undefined;
|
|
432
|
+
const decodeGroup = groupInput !== undefined
|
|
433
|
+
? buildDraftGroupDecoder(groupType, groupInput.linesField, groupInput.cellMetas, draftRow, registers, idField)
|
|
434
|
+
: undefined;
|
|
435
|
+
const flatDraft = SheetDraftTypeFor(groupType);
|
|
436
|
+
const draftDecode = (decodeGroup === undefined
|
|
437
|
+
? East.function([SheetRowType, OptionType(flatDraft), OptionType(SheetRowType)], flatDraft, ($, row, base, _previous) => {
|
|
438
|
+
const decode = $.const(draftRow);
|
|
439
|
+
return decode(row.id, row.cells, base);
|
|
440
|
+
})
|
|
441
|
+
: looseRow !== undefined && groupInput !== undefined
|
|
442
|
+
? buildDraftEntryDecoder(rowType, groupInput.linesField, decodeGroup, looseRow)
|
|
443
|
+
: decodeGroup);
|
|
444
|
+
// The group half (#740).
|
|
445
|
+
const group = groupInput !== undefined && shape !== undefined && decodeGroup !== undefined
|
|
446
|
+
? { ...buildGroupBridge(groupType, groupInput, projectRow, projectSubRows), groupType, loose, decodeGroup, decodeLoose: looseRow }
|
|
447
|
+
: undefined;
|
|
448
|
+
const bridgeCtx = buildDraftContextBridge(rowType, lineType, groupInput?.linesField, ctxType, driverType, rowById, draftDecode, draftRow, lookupDriver, looseRow);
|
|
449
|
+
const bridgeReady = buildReadyContexts(rowType, groupInput?.linesField, ctxType, driverType, rowById, draftDecode, lookupDriver, loose);
|
|
450
|
+
const encodePatch = buildPatchCells(lineType, metas, registers);
|
|
451
|
+
return {
|
|
452
|
+
rowType, lineType, driverType, ctxType, checkCtxType, patchType, proposalType,
|
|
453
|
+
projectRow, projectSubRows, draftDecode, draftRow,
|
|
454
|
+
rowById: rowById,
|
|
455
|
+
bridgeCtx: bridgeCtx,
|
|
456
|
+
bridgeReady,
|
|
457
|
+
encodePatch, seedCells: buildPatchCells(lineType, metas, registers, false),
|
|
458
|
+
...(group !== undefined ? { group } : {}),
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
/** Project supplied constructor/proposal fields without inventing a complete row. @internal */
|
|
462
|
+
export function buildPatchCells(rowType, metas, registers, editableOnly = true) {
|
|
463
|
+
const patchType = SheetPatchTypeFor(rowType);
|
|
464
|
+
const fields = rowType.fields;
|
|
465
|
+
const stringFormRegisters = [...new Set(metas.filter(m => m.form === "string" && m.register !== undefined).map(m => m.register))];
|
|
466
|
+
return East.function([patchType], SheetCellsType, ($, patch) => {
|
|
393
467
|
const cells = $.let(new Map(), SheetCellsType);
|
|
394
468
|
const p = patch;
|
|
395
469
|
const bound = new Map();
|
|
@@ -397,12 +471,12 @@ export function buildBridge(input) {
|
|
|
397
471
|
bound.set(name, $.const(registers[name], SheetRegisterMembersType));
|
|
398
472
|
}
|
|
399
473
|
for (const m of metas) {
|
|
400
|
-
if (!m.editable || m.derived !== undefined)
|
|
474
|
+
if ((editableOnly && !m.editable) || m.derived !== undefined)
|
|
401
475
|
continue;
|
|
402
476
|
if (m.form === "array") {
|
|
403
477
|
// The other half is `none` when the column names no other field.
|
|
404
478
|
const otherKey = m.otherField;
|
|
405
|
-
const own = $.let(p[m.
|
|
479
|
+
const own = $.let(p[m.field], OptionType(SheetMembersType));
|
|
406
480
|
const other = $.let((otherKey !== undefined ? p[otherKey] : none), OptionType(SheetMembersType));
|
|
407
481
|
$.if(own.hasTag("some").or(() => other.hasTag("some")), ($2) => {
|
|
408
482
|
const empty = $2.const([], SheetMembersType);
|
|
@@ -415,21 +489,85 @@ export function buildBridge(input) {
|
|
|
415
489
|
});
|
|
416
490
|
continue;
|
|
417
491
|
}
|
|
418
|
-
const field = $.let(p[m.
|
|
492
|
+
const field = $.let(p[m.field], OptionType(fields[m.field]));
|
|
419
493
|
$.if(field.hasTag("some"), ($2) => {
|
|
420
|
-
const v = $2.let(field.unwrap("some"), fields[m.
|
|
421
|
-
const asRow = { [m.
|
|
494
|
+
const v = $2.let(field.unwrap("some"), fields[m.field]);
|
|
495
|
+
const asRow = { [m.field]: v };
|
|
422
496
|
$2(cells.insert(m.key, projectCell(m, asRow, m.register !== undefined ? bound.get(m.register) : undefined)));
|
|
423
497
|
});
|
|
424
498
|
}
|
|
425
499
|
return cells;
|
|
426
500
|
});
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
501
|
+
}
|
|
502
|
+
// ============================================================================
|
|
503
|
+
// Sub rows (#844)
|
|
504
|
+
// ============================================================================
|
|
505
|
+
/**
|
|
506
|
+
* Compile the sub-row sources into one projection over the line type: each
|
|
507
|
+
* mapper is compiled ONCE as `East.function([L, T], SubRow)` and called in
|
|
508
|
+
* an eager map over its field; the sources concatenate in declaration order.
|
|
509
|
+
*
|
|
510
|
+
* @param lineType - The type the columns are built over
|
|
511
|
+
* @param subRows - The `subRows` declaration, if any
|
|
512
|
+
* @returns `L` → its sub rows
|
|
513
|
+
* @throws Error when the declaration was built over another type, or a key is not an array field
|
|
514
|
+
*/
|
|
515
|
+
export function buildSubRowProjection(lineType, subRows) {
|
|
516
|
+
const fields = lineType.fields;
|
|
517
|
+
const mappers = [];
|
|
518
|
+
if (subRows !== undefined) {
|
|
519
|
+
if (!isTypeEqual(subRows.rowType, lineType)) {
|
|
520
|
+
throw new Error("Sheet: `subRows` was built over a different type than the columns — pass the columns' type (a grouped sheet: the line type) to `Sheet.subRows(…)`");
|
|
521
|
+
}
|
|
522
|
+
for (const [field, map] of Object.entries(subRows.sources)) {
|
|
523
|
+
if (map === undefined)
|
|
524
|
+
continue;
|
|
525
|
+
const t = fields[field];
|
|
526
|
+
if (t === undefined || t.type !== "Array" || t.value === undefined) {
|
|
527
|
+
throw new Error(`Sheet: \`subRows\` names "${field}", which is ${t === undefined ? "not a field of the row type" : `a ${t.type} field`} — a sub-row source must be an Array field`);
|
|
528
|
+
}
|
|
529
|
+
mappers.push({ field, fn: East.function([lineType, t.value], SheetSubRowType, (_$, row, item) => map(item, row)) });
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
return East.function([lineType], ArrayType(SheetSubRowType), ($, r) => {
|
|
533
|
+
const row = r;
|
|
534
|
+
let all = $.const([], ArrayType(SheetSubRowType));
|
|
535
|
+
for (const m of mappers) {
|
|
536
|
+
const map = $.const(m.fn);
|
|
537
|
+
const part = $.let(row[m.field].map((_$2, x) => map(r, x)), ArrayType(SheetSubRowType));
|
|
538
|
+
all = mappers[0] === m ? part : $.let(all.concat(part), ArrayType(SheetSubRowType));
|
|
539
|
+
}
|
|
540
|
+
return all;
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
// ============================================================================
|
|
544
|
+
// The group half (#740)
|
|
545
|
+
// ============================================================================
|
|
546
|
+
/**
|
|
547
|
+
* Compile a group's summary cells and ordered children into wire rows.
|
|
548
|
+
*
|
|
549
|
+
* @param rowType - The group's row type
|
|
550
|
+
* @param input - The child field and summary cell metadata
|
|
551
|
+
* @param projectRow - Child row to wire cells
|
|
552
|
+
* @param projectSubRows - Child row to its sub rows
|
|
553
|
+
* @returns The group half
|
|
554
|
+
*/
|
|
555
|
+
function buildGroupBridge(rowType, input, projectRow, projectSubRows) {
|
|
556
|
+
const { linesField, cellMetas } = input;
|
|
557
|
+
const linesType = rowType.fields[linesField];
|
|
558
|
+
const projectGroupCells = East.function([rowType], SheetCellsType, ($, p) => {
|
|
559
|
+
const cells = $.let(new Map(), SheetCellsType);
|
|
560
|
+
for (const m of cellMetas)
|
|
561
|
+
$(cells.insert(m.key, projectCell(m, p, undefined)));
|
|
562
|
+
return cells;
|
|
563
|
+
});
|
|
564
|
+
const projectLines = East.function([rowType], ArrayType(SheetLineType), ($, p) => {
|
|
565
|
+
const project = $.const(projectRow);
|
|
566
|
+
const subRowsOf = $.const(projectSubRows);
|
|
567
|
+
const lines = $.const(p[linesField], linesType);
|
|
568
|
+
return lines.map((_$, line, index) => East.value({ key: East.print(index), cells: project(line), subRows: subRowsOf(line) }, SheetLineType));
|
|
569
|
+
});
|
|
570
|
+
return { linesField, cellMetas, projectGroupCells, projectLines };
|
|
433
571
|
}
|
|
434
572
|
// ============================================================================
|
|
435
573
|
// Wrappers — the author's typed functions inside their wire twins
|
|
@@ -446,27 +584,34 @@ function pinProvider(bridge, fn, where, expectedOutput) {
|
|
|
446
584
|
throw new Error(`Sheet: ${where} must be an East.function or East.asyncFunction — got a ${t.type}`);
|
|
447
585
|
}
|
|
448
586
|
const inputs = t.inputs ?? [];
|
|
449
|
-
if (inputs.length !== 1 || inputs[0]
|
|
450
|
-
throw new Error(`Sheet: ${where} must take exactly this sheet's context —
|
|
587
|
+
if (inputs.length !== 1 || !isTypeEqual(inputs[0], bridge.ctxType)) {
|
|
588
|
+
throw new Error(`Sheet: ${where} must take exactly this sheet's context — ${contextName(bridge)} — as its one argument; a function written over another row or driver type cannot run here`);
|
|
451
589
|
}
|
|
452
|
-
if (t.output
|
|
590
|
+
if (t.output === undefined || !isTypeEqual(t.output, expectedOutput)) {
|
|
453
591
|
throw new Error(`Sheet: ${where} returns the wrong type — it must return ${describeType(expectedOutput)}`);
|
|
454
592
|
}
|
|
455
593
|
return { fn: expr, async: t.type === "AsyncFunction" };
|
|
456
594
|
}
|
|
595
|
+
/** How this sheet's context is spelt, for a refusal message. */
|
|
596
|
+
function contextName(bridge) {
|
|
597
|
+
const driver = isTypeEqual(bridge.driverType, NullType) ? "" : ", DriverType";
|
|
598
|
+
return bridge.group !== undefined
|
|
599
|
+
? `Sheet.Types.DraftContext(GroupType, "${bridge.group.linesField}"${driver})`
|
|
600
|
+
: `Sheet.Types.DraftContext(RowType${driver})`;
|
|
601
|
+
}
|
|
457
602
|
/** A short description of an East type for a refusal message. */
|
|
458
603
|
function describeType(t) {
|
|
459
|
-
const
|
|
460
|
-
if (
|
|
461
|
-
return `Option<${describeType(
|
|
462
|
-
if (
|
|
463
|
-
return `{ ${Object.entries(
|
|
464
|
-
if (
|
|
465
|
-
return `Array<${describeType(
|
|
466
|
-
return
|
|
604
|
+
const payload = optionPayload(t);
|
|
605
|
+
if (payload !== undefined)
|
|
606
|
+
return `Option<${describeType(payload)}>`;
|
|
607
|
+
if (t.type === "Struct")
|
|
608
|
+
return `{ ${Object.entries(t.fields).map(([k, f]) => `${k}: ${describeType(f)}`).join(", ")} }`;
|
|
609
|
+
if (t.type === "Array")
|
|
610
|
+
return `Array<${describeType(t.value)}>`;
|
|
611
|
+
return t.type;
|
|
467
612
|
}
|
|
468
613
|
/**
|
|
469
|
-
* Wrap a fill provider — `Sheet.Types.
|
|
614
|
+
* Wrap a fill provider — `Sheet.Types.DraftContext(R, D)` → `Option<Fill(T)>` —
|
|
470
615
|
* into the wire provider variant (sync or async by the function's type).
|
|
471
616
|
*/
|
|
472
617
|
export function wrapProvider(bridge, meta, fn, index) {
|
|
@@ -487,7 +632,7 @@ export function wrapProvider(bridge, meta, fn, index) {
|
|
|
487
632
|
return East.value(variant(async ? "async" : "sync", wire), SheetProviderType);
|
|
488
633
|
}
|
|
489
634
|
/**
|
|
490
|
-
* Wrap a row proposer — `Sheet.Types.
|
|
635
|
+
* Wrap a row proposer — `Sheet.Types.DraftContext(R, D)` → `Array<Proposal(R)>` —
|
|
491
636
|
* into the wire proposer variant.
|
|
492
637
|
*/
|
|
493
638
|
export function wrapProposer(bridge, fn, index) {
|
|
@@ -504,7 +649,7 @@ export function wrapProposer(bridge, fn, index) {
|
|
|
504
649
|
: East.function([SheetContextType], ArrayType(SheetProposalType), body);
|
|
505
650
|
return East.value(variant(async ? "async" : "sync", wire), SheetProposerType);
|
|
506
651
|
}
|
|
507
|
-
/** Wrap an arity rule — `Sheet.Types.
|
|
652
|
+
/** Wrap an arity rule — `Sheet.Types.DraftContext(R, D)` → `Option<Counted>`. */
|
|
508
653
|
export function wrapArity(bridge, meta, fn) {
|
|
509
654
|
const { fn: author, async } = pinProvider(bridge, fn, `column "${meta.key}" arity rule`, OptionType(SheetCountedType));
|
|
510
655
|
if (async)
|
|
@@ -515,19 +660,80 @@ export function wrapArity(bridge, meta, fn) {
|
|
|
515
660
|
return a(bc(ctx));
|
|
516
661
|
});
|
|
517
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* Wrap an options rule (#844) — `Sheet.Types.DraftContext(R, D)` →
|
|
665
|
+
* `Option<Array<String>>` — into the wire rule. Synchronous: the menu reads
|
|
666
|
+
* it as the cell opens.
|
|
667
|
+
*/
|
|
668
|
+
export function wrapOptions(bridge, meta, fn) {
|
|
669
|
+
const { fn: author, async } = pinProvider(bridge, fn, `column "${meta.key}" options rule`, OptionType(ArrayType(StringType)));
|
|
670
|
+
if (async)
|
|
671
|
+
throw new Error(`Sheet: column "${meta.key}" options rule must be synchronous — the menu reads it as the cell opens`);
|
|
672
|
+
return East.function([SheetContextType], OptionType(ArrayType(StringType)), ($, ctx) => {
|
|
673
|
+
const a = $.const(author);
|
|
674
|
+
const bc = $.const(bridge.bridgeCtx);
|
|
675
|
+
return a(bc(ctx));
|
|
676
|
+
});
|
|
677
|
+
}
|
|
518
678
|
/** Wrap an author member check — `Sheet.Types.CheckContext(R)` → `Option<String>` — into the `custom` check arm. */
|
|
519
679
|
export function wrapCheck(bridge, meta, fn, index) {
|
|
520
680
|
const expr = East.value(fn);
|
|
521
681
|
const t = typeOf(expr);
|
|
522
|
-
if (t.type !== "Function" || (t.inputs ?? []).length !== 1 || t.inputs[0]
|
|
523
|
-
|
|
682
|
+
if (t.type !== "Function" || (t.inputs ?? []).length !== 1 || !isTypeEqual(t.inputs[0], bridge.checkCtxType) ||
|
|
683
|
+
t.output === undefined || !isTypeEqual(t.output, OptionType(StringType))) {
|
|
684
|
+
const spelt = bridge.group !== undefined ? `Sheet.Types.CheckContext(GroupType, "${bridge.group.linesField}")` : "Sheet.Types.CheckContext(RowType)";
|
|
685
|
+
throw new Error(`Sheet: column "${meta.key}" check #${index + 1} must be an East.function over ${spelt} returning Option<String>`);
|
|
524
686
|
}
|
|
687
|
+
const groupHalf = bridge.group;
|
|
688
|
+
const field = groupHalf?.linesField;
|
|
689
|
+
const entryDraft = SheetDraftEntryTypeFor(bridge.rowType, field);
|
|
690
|
+
const draftType = (groupHalf === undefined ? entryDraft : SheetDraftGroupTypeFor(groupHalf.groupType, groupHalf.linesField));
|
|
691
|
+
const rowDraft = SheetDraftTypeFor(bridge.lineType);
|
|
692
|
+
const base = buildDraftBase(bridge.rowType, field, bridge.rowById);
|
|
525
693
|
const wire = East.function([SheetCheckContextType], OptionType(StringType), ($, c) => {
|
|
526
694
|
const a = $.const(expr);
|
|
527
|
-
const
|
|
528
|
-
const dec = $.const(bridge.
|
|
529
|
-
const
|
|
530
|
-
|
|
695
|
+
const read = $.const(base);
|
|
696
|
+
const dec = $.const(bridge.draftRow);
|
|
697
|
+
const original = $.const(read(c.drafts, c.rowId, c.offset), OptionType(entryDraft));
|
|
698
|
+
if (field === undefined || groupHalf === undefined) {
|
|
699
|
+
const row = $.const(dec(c.rowId, c.row, original));
|
|
700
|
+
return a($.const({ rowIndex: c.rowIndex, row, group: none, half: c.half, member: c.member }, bridge.checkCtxType));
|
|
701
|
+
}
|
|
702
|
+
const decGroup = $.const(groupHalf.decodeGroup);
|
|
703
|
+
/** A line's check: the line over its prior draft in its group, the group decoded over the wire group row. */
|
|
704
|
+
const lineCheck = ($2, own) => {
|
|
705
|
+
const group = $2.const(c.group.match({
|
|
706
|
+
none: () => own,
|
|
707
|
+
some: (_$, wire) => some(decGroup(wire, own, some(wire))),
|
|
708
|
+
}), OptionType(draftType));
|
|
709
|
+
const prior = $2.const(group.match({
|
|
710
|
+
none: () => none,
|
|
711
|
+
some: (_$, value) => {
|
|
712
|
+
const children = value[field];
|
|
713
|
+
return c.rowIndex.greaterEqual(0n).and(() => c.rowIndex.less(children.size())).ifElse(() => some(children.get(c.rowIndex)), () => none);
|
|
714
|
+
},
|
|
715
|
+
}), OptionType(rowDraft));
|
|
716
|
+
const row = $2.const(dec("", c.row, prior));
|
|
717
|
+
return a($2.const({ rowIndex: c.rowIndex, row, group, half: c.half, member: c.member }, bridge.checkCtxType));
|
|
718
|
+
};
|
|
719
|
+
const decLoose = groupHalf.decodeLoose;
|
|
720
|
+
if (decLoose === undefined)
|
|
721
|
+
return lineCheck($, original);
|
|
722
|
+
// A source with loose rows (#846): the entry's arms. A loose row has
|
|
723
|
+
// no line address — its own cells over its own draft, and no group.
|
|
724
|
+
const entry = original;
|
|
725
|
+
const decodeLoose = $.const(decLoose);
|
|
726
|
+
return c.line.match({
|
|
727
|
+
some: ($2) => {
|
|
728
|
+
const own = $2.const(entry.match({ none: () => none, some: (_$, e) => e.match({ group: (_$3, g) => some(g), row: () => none }) }), OptionType(draftType));
|
|
729
|
+
return lineCheck($2, own);
|
|
730
|
+
},
|
|
731
|
+
none: ($2) => {
|
|
732
|
+
const own = $2.const(entry.match({ none: () => none, some: (_$, e) => e.match({ row: (_$3, r) => some(r), group: () => none }) }), OptionType(rowDraft));
|
|
733
|
+
const row = $2.const(decodeLoose(c.rowId, c.row, own));
|
|
734
|
+
return a($2.const({ rowIndex: c.rowIndex, row, group: none, half: c.half, member: c.member }, bridge.checkCtxType));
|
|
735
|
+
},
|
|
736
|
+
});
|
|
531
737
|
});
|
|
532
738
|
return East.value(variant("custom", wire), SheetCheckType);
|
|
533
739
|
}
|
|
@@ -536,8 +742,8 @@ export function wrapCustomParse(bridge, meta, fn) {
|
|
|
536
742
|
const expr = East.value(fn);
|
|
537
743
|
const t = typeOf(expr);
|
|
538
744
|
const inputs = t.inputs ?? [];
|
|
539
|
-
if (t.type !== "Function" || inputs.length !== 2 || inputs[0]
|
|
540
|
-
throw new Error(`Sheet: custom column "${meta.key}" \`parse\` must be an East.function over (String,
|
|
745
|
+
if (t.type !== "Function" || inputs.length !== 2 || !isTypeEqual(inputs[0], StringType) || !isTypeEqual(inputs[1], bridge.ctxType)) {
|
|
746
|
+
throw new Error(`Sheet: custom column "${meta.key}" \`parse\` must be an East.function over (String, ${contextName(bridge)}) returning Option<payload>`);
|
|
541
747
|
}
|
|
542
748
|
return East.function([StringType, SheetContextType], OptionType(SheetCellType), ($, text, ctx) => {
|
|
543
749
|
const a = $.const(expr);
|
|
@@ -553,7 +759,8 @@ export function wrapCustomPrint(meta, fn) {
|
|
|
553
759
|
const expr = East.value(fn);
|
|
554
760
|
const t = typeOf(expr);
|
|
555
761
|
const inputs = t.inputs ?? [];
|
|
556
|
-
if (t.type !== "Function" || inputs.length !== 1 || inputs[0]
|
|
762
|
+
if (t.type !== "Function" || inputs.length !== 1 || !isTypeEqual(inputs[0], meta.payloadType) ||
|
|
763
|
+
t.output === undefined || !isTypeEqual(t.output, StringType)) {
|
|
557
764
|
throw new Error(`Sheet: custom column "${meta.key}" \`print\` must be an East.function over the payload (${describeType(meta.payloadType)}) returning String`);
|
|
558
765
|
}
|
|
559
766
|
return East.function([SheetCellType], StringType, ($, cell) => {
|
|
@@ -561,70 +768,6 @@ export function wrapCustomPrint(meta, fn) {
|
|
|
561
768
|
return cell.match({ [meta.cellTag]: (_$, v) => a(v) }, (_$) => East.value("", StringType));
|
|
562
769
|
});
|
|
563
770
|
}
|
|
564
|
-
/** Wrap a typed `onEdit` — `Sheet.Types.Edit(R)` → `Null` — into the wire edit handler. */
|
|
565
|
-
export function wrapOnEdit(bridge, fn) {
|
|
566
|
-
const expr = East.value(fn, FunctionType([bridge.editType], NullType));
|
|
567
|
-
return East.function([SheetEditType], NullType, ($, e) => {
|
|
568
|
-
const a = $.const(expr);
|
|
569
|
-
const byId = $.const(bridge.rowById);
|
|
570
|
-
const dec = $.const(bridge.decode);
|
|
571
|
-
const noRow = $.const(none, OptionType(bridge.rowType));
|
|
572
|
-
const et = bridge.editType;
|
|
573
|
-
$(e.match({
|
|
574
|
-
commit: (_$, c) => a(East.value(variant("commit", {
|
|
575
|
-
rowId: c.rowId, key: c.key, row: dec(c.rowId, c.row.cells, byId(c.rowId, c.offset)), source: c.source,
|
|
576
|
-
}), et)),
|
|
577
|
-
insert: (_$, i) => a(East.value(variant("insert", {
|
|
578
|
-
afterRowId: i.afterRowId, row: dec(i.row.id, i.row.cells, noRow), source: i.source,
|
|
579
|
-
}), et)),
|
|
580
|
-
remove: (_$, r) => a(East.value(variant("remove", { rowIds: r.rowIds }), et)),
|
|
581
|
-
}));
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* Compile `onUpdate` into the wire edit handler (§4.7) — the whole-value
|
|
586
|
-
* rebuild: a commit rewrites one row, an insert appends a fresh row after
|
|
587
|
-
* `afterRowId`, a remove filters ids; then the author's `onUpdate` receives
|
|
588
|
-
* the collection.
|
|
589
|
-
*/
|
|
590
|
-
export function compileOnUpdate(bridge, rows, idField, fn) {
|
|
591
|
-
const rowsType = ArrayType(bridge.rowType);
|
|
592
|
-
const expr = East.value(fn, FunctionType([rowsType], NullType));
|
|
593
|
-
return East.function([SheetEditType], NullType, ($, ev) => {
|
|
594
|
-
const current = $.let(rows, rowsType);
|
|
595
|
-
const upd = $.const(expr);
|
|
596
|
-
const dec = $.const(bridge.decode);
|
|
597
|
-
const noRow = $.const(none, OptionType(bridge.rowType));
|
|
598
|
-
const next = $.let(ev.match({
|
|
599
|
-
commit: (_$, c) => current.map((_$2, r) => idOf(r, idField).equal(c.rowId).ifElse((_$3) => dec(c.rowId, c.row.cells, East.value(some(r), OptionType(bridge.rowType))), (_$3) => r)),
|
|
600
|
-
insert: ($2, i) => {
|
|
601
|
-
const fresh = $2.let(dec(i.row.id, i.row.cells, noRow), bridge.rowType);
|
|
602
|
-
return i.afterRowId.match({
|
|
603
|
-
none: (_$3) => current.concat(East.value([fresh], rowsType)),
|
|
604
|
-
some: (_$3, after) => current.flatMap((_$4, r) => idOf(r, idField).equal(after).ifElse((_$5) => East.value([r, fresh], rowsType), (_$5) => East.value([r], rowsType))),
|
|
605
|
-
});
|
|
606
|
-
},
|
|
607
|
-
remove: ($2, rm) => {
|
|
608
|
-
const ids = $2.let(rm.rowIds.toSet());
|
|
609
|
-
return current.filter((_$3, r) => ids.has(idOf(r, idField)).not());
|
|
610
|
-
},
|
|
611
|
-
}), rowsType);
|
|
612
|
-
$(upd(next));
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
/** Both channels at once — `onEdit` observes, then `onUpdate` writes. */
|
|
616
|
-
export function composeEditHandlers(observe, write) {
|
|
617
|
-
if (observe === undefined)
|
|
618
|
-
return write;
|
|
619
|
-
if (write === undefined)
|
|
620
|
-
return observe;
|
|
621
|
-
return East.function([SheetEditType], NullType, ($, e) => {
|
|
622
|
-
const o = $.const(observe);
|
|
623
|
-
const w = $.const(write);
|
|
624
|
-
$(o(e));
|
|
625
|
-
$(w(e));
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
771
|
/** Re-exported for the root's driver-typed refusals. */
|
|
629
772
|
export { SheetHalfType, BooleanType, AsyncFunctionType, EMPTY_LINK };
|
|
630
773
|
//# sourceMappingURL=bridge.js.map
|