@elaraai/e3-ui 1.0.97 → 1.0.99
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/README.md +0 -2
- package/dist/src/allocation/adapters.d.ts +1 -1
- package/dist/src/allocation/adapters.js +1 -1
- package/dist/src/allocation/index.d.ts +232 -25
- package/dist/src/allocation/index.d.ts.map +1 -1
- package/dist/src/allocation/index.js +35 -6
- package/dist/src/allocation/index.js.map +1 -1
- package/dist/src/allocation/types.d.ts +41 -0
- package/dist/src/allocation/types.d.ts.map +1 -1
- package/dist/src/allocation/types.js +35 -0
- package/dist/src/allocation/types.js.map +1 -1
- package/dist/src/bind/data-indexed.d.ts +286 -37
- package/dist/src/bind/data-indexed.d.ts.map +1 -1
- package/dist/src/bind/data-indexed.js +259 -38
- package/dist/src/bind/data-indexed.js.map +1 -1
- package/dist/src/bind/data.d.ts +48 -9
- package/dist/src/bind/data.d.ts.map +1 -1
- package/dist/src/bind/data.js +48 -3
- package/dist/src/bind/data.js.map +1 -1
- package/dist/src/bind/record.d.ts +61 -24
- package/dist/src/bind/record.d.ts.map +1 -1
- package/dist/src/bind/record.js +17 -57
- package/dist/src/bind/record.js.map +1 -1
- package/dist/src/calendar/index.d.ts +522 -36
- package/dist/src/calendar/index.d.ts.map +1 -1
- package/dist/src/calendar/index.js +53 -13
- package/dist/src/calendar/index.js.map +1 -1
- package/dist/src/calendar/paged.d.ts +89 -0
- package/dist/src/calendar/paged.d.ts.map +1 -0
- package/dist/src/calendar/paged.js +148 -0
- package/dist/src/calendar/paged.js.map +1 -0
- package/dist/src/flowchart/index.d.ts +35 -31
- package/dist/src/flowchart/index.d.ts.map +1 -1
- package/dist/src/flowchart/index.js +35 -31
- package/dist/src/flowchart/index.js.map +1 -1
- package/dist/src/flowchart/library.d.ts +108 -84
- package/dist/src/flowchart/library.d.ts.map +1 -1
- package/dist/src/flowchart/library.js +108 -84
- package/dist/src/flowchart/library.js.map +1 -1
- package/dist/src/flowchart/payload.d.ts +105 -17
- package/dist/src/flowchart/payload.d.ts.map +1 -1
- package/dist/src/flowchart/payload.js +3 -3
- package/dist/src/flowchart/payload.js.map +1 -1
- package/dist/src/flowchart/values.d.ts +35 -31
- package/dist/src/flowchart/values.d.ts.map +1 -1
- package/dist/src/flowchart/values.js +35 -31
- package/dist/src/flowchart/values.js.map +1 -1
- package/dist/src/flowchart/window.d.ts.map +1 -1
- package/dist/src/flowchart/window.js +3 -2
- package/dist/src/flowchart/window.js.map +1 -1
- package/dist/src/index.d.ts +13 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +20 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal.d.ts +18 -8
- package/dist/src/internal.d.ts.map +1 -1
- package/dist/src/internal.js +40 -10
- package/dist/src/internal.js.map +1 -1
- package/dist/src/plan/assemble.d.ts +8 -0
- package/dist/src/plan/assemble.d.ts.map +1 -1
- package/dist/src/plan/assemble.js +1 -1
- package/dist/src/plan/assemble.js.map +1 -1
- package/dist/src/plan/builders.d.ts +1530 -10
- package/dist/src/plan/builders.d.ts.map +1 -1
- package/dist/src/plan/builders.js +260 -122
- package/dist/src/plan/builders.js.map +1 -1
- package/dist/src/plan/event-rows.d.ts +224 -157
- package/dist/src/plan/event-rows.d.ts.map +1 -1
- package/dist/src/plan/event-rows.js +201 -56
- package/dist/src/plan/event-rows.js.map +1 -1
- package/dist/src/plan/factories.d.ts +72 -4
- package/dist/src/plan/factories.d.ts.map +1 -1
- package/dist/src/plan/factories.js +147 -1
- package/dist/src/plan/factories.js.map +1 -1
- package/dist/src/plan/index.d.ts +152 -125
- package/dist/src/plan/index.d.ts.map +1 -1
- package/dist/src/plan/index.js +138 -122
- package/dist/src/plan/index.js.map +1 -1
- package/dist/src/plan/ir.d.ts +1139 -8
- package/dist/src/plan/ir.d.ts.map +1 -1
- package/dist/src/plan/ir.js +5 -0
- package/dist/src/plan/ir.js.map +1 -1
- package/dist/src/plan/library.d.ts +65 -42
- package/dist/src/plan/library.d.ts.map +1 -1
- package/dist/src/plan/library.js +65 -42
- package/dist/src/plan/library.js.map +1 -1
- package/dist/src/plan/nested-checks.d.ts +146 -0
- package/dist/src/plan/nested-checks.d.ts.map +1 -0
- package/dist/src/plan/nested-checks.js +468 -0
- package/dist/src/plan/nested-checks.js.map +1 -0
- package/dist/src/plan/nested-patch.d.ts +35 -0
- package/dist/src/plan/nested-patch.d.ts.map +1 -0
- package/dist/src/plan/nested-patch.js +143 -0
- package/dist/src/plan/nested-patch.js.map +1 -0
- package/dist/src/plan/nested-read.d.ts +3250 -0
- package/dist/src/plan/nested-read.d.ts.map +1 -0
- package/dist/src/plan/nested-read.js +163 -0
- package/dist/src/plan/nested-read.js.map +1 -0
- package/dist/src/plan/nested.d.ts +280 -0
- package/dist/src/plan/nested.d.ts.map +1 -0
- package/dist/src/plan/nested.js +6 -0
- package/dist/src/plan/nested.js.map +1 -0
- package/dist/src/plan/ordered-source.d.ts +3067 -1
- package/dist/src/plan/ordered-source.d.ts.map +1 -1
- package/dist/src/plan/ordered-source.js +67 -17
- package/dist/src/plan/ordered-source.js.map +1 -1
- package/dist/src/plan/over.d.ts +111 -75
- package/dist/src/plan/over.d.ts.map +1 -1
- package/dist/src/plan/over.js +111 -75
- package/dist/src/plan/over.js.map +1 -1
- package/dist/src/plan/pick.d.ts +15 -3
- package/dist/src/plan/pick.d.ts.map +1 -1
- package/dist/src/plan/pick.js +75 -36
- package/dist/src/plan/pick.js.map +1 -1
- package/dist/src/plan/plan.d.ts +3143 -501
- package/dist/src/plan/plan.d.ts.map +1 -1
- package/dist/src/plan/plan.js +133 -34
- package/dist/src/plan/plan.js.map +1 -1
- package/dist/src/plan/reads.d.ts +421 -0
- package/dist/src/plan/reads.d.ts.map +1 -0
- package/dist/src/plan/reads.js +143 -0
- package/dist/src/plan/reads.js.map +1 -0
- package/dist/src/plan/refs.d.ts +111 -75
- package/dist/src/plan/refs.d.ts.map +1 -1
- package/dist/src/plan/refs.js +111 -75
- package/dist/src/plan/refs.js.map +1 -1
- package/dist/src/plan/root.d.ts +14 -7
- package/dist/src/plan/root.d.ts.map +1 -1
- package/dist/src/plan/root.js +82 -17
- package/dist/src/plan/root.js.map +1 -1
- package/dist/src/plan/series.d.ts +5153 -4331
- package/dist/src/plan/series.d.ts.map +1 -1
- package/dist/src/plan/series.js +1082 -266
- package/dist/src/plan/series.js.map +1 -1
- package/dist/src/plan/shade.d.ts +981 -0
- package/dist/src/plan/shade.d.ts.map +1 -0
- package/dist/src/plan/shade.js +60 -0
- package/dist/src/plan/shade.js.map +1 -0
- package/dist/src/plan/types.d.ts +192 -18
- package/dist/src/plan/types.d.ts.map +1 -1
- package/dist/src/plan/types.js +77 -19
- package/dist/src/plan/types.js.map +1 -1
- package/dist/src/query/builder.d.ts +3 -3
- package/dist/src/query/builder.d.ts.map +1 -1
- package/dist/src/query/builder.js +1 -1
- package/dist/src/query/library.d.ts +3 -3
- package/dist/src/query/library.d.ts.map +1 -1
- package/dist/src/query/library.js +1 -1
- package/dist/src/query/queries.d.ts +2 -2
- package/dist/src/query/queries.js +1 -1
- package/dist/src/query/saved.d.ts +8 -4
- package/dist/src/query/saved.d.ts.map +1 -1
- package/dist/src/query/saved.js +8 -4
- package/dist/src/query/saved.js.map +1 -1
- package/dist/src/query/types.d.ts +8 -3
- package/dist/src/query/types.d.ts.map +1 -1
- package/dist/src/query/types.js +8 -3
- package/dist/src/query/types.js.map +1 -1
- package/dist/src/roster/index.d.ts +583 -39
- package/dist/src/roster/index.d.ts.map +1 -1
- package/dist/src/roster/index.js +109 -35
- package/dist/src/roster/index.js.map +1 -1
- package/dist/src/roster/library.d.ts +12 -2
- package/dist/src/roster/library.d.ts.map +1 -1
- package/dist/src/roster/library.js +8 -0
- package/dist/src/roster/library.js.map +1 -1
- package/dist/src/roster/lists.d.ts +59 -12
- package/dist/src/roster/lists.d.ts.map +1 -1
- package/dist/src/roster/lists.js +51 -58
- package/dist/src/roster/lists.js.map +1 -1
- package/dist/src/roster/targets.d.ts +8 -4
- package/dist/src/roster/targets.d.ts.map +1 -1
- package/dist/src/roster/targets.js +9 -5
- package/dist/src/roster/targets.js.map +1 -1
- package/dist/src/roster/times.d.ts +402 -0
- package/dist/src/roster/times.d.ts.map +1 -1
- package/dist/src/roster/types.d.ts +913 -1
- package/dist/src/roster/types.d.ts.map +1 -1
- package/dist/src/roster/types.js +43 -3
- package/dist/src/roster/types.js.map +1 -1
- package/dist/src/schedule/cell-checks.d.ts +85 -0
- package/dist/src/schedule/cell-checks.d.ts.map +1 -0
- package/dist/src/schedule/cell-checks.js +211 -0
- package/dist/src/schedule/cell-checks.js.map +1 -0
- package/dist/src/schedule/days.d.ts +1 -1
- package/dist/src/schedule/days.js +1 -1
- package/dist/src/schedule/events.d.ts +52 -16
- package/dist/src/schedule/events.d.ts.map +1 -1
- package/dist/src/schedule/events.js +574 -356
- package/dist/src/schedule/events.js.map +1 -1
- package/dist/src/schedule/fields.d.ts +134 -0
- package/dist/src/schedule/fields.d.ts.map +1 -0
- package/dist/src/schedule/fields.js +207 -0
- package/dist/src/schedule/fields.js.map +1 -0
- package/dist/src/schedule/library.d.ts +11 -3
- package/dist/src/schedule/library.d.ts.map +1 -1
- package/dist/src/schedule/library.js +9 -6
- package/dist/src/schedule/library.js.map +1 -1
- package/dist/src/schedule/optimise.d.ts +124 -0
- package/dist/src/schedule/optimise.d.ts.map +1 -0
- package/dist/src/schedule/optimise.js +140 -0
- package/dist/src/schedule/optimise.js.map +1 -0
- package/dist/src/schedule/pages.d.ts +76 -0
- package/dist/src/schedule/pages.d.ts.map +1 -0
- package/dist/src/schedule/pages.js +86 -0
- package/dist/src/schedule/pages.js.map +1 -0
- package/dist/src/schedule/patch.d.ts +1 -1
- package/dist/src/schedule/patch.js +1 -1
- package/dist/src/schedule/periods.d.ts +8 -4
- package/dist/src/schedule/periods.d.ts.map +1 -1
- package/dist/src/schedule/periods.js +1 -1
- package/dist/src/schedule/periods.js.map +1 -1
- package/dist/src/schedule/record-window.d.ts +115 -22
- package/dist/src/schedule/record-window.d.ts.map +1 -1
- package/dist/src/schedule/record-window.js +140 -62
- package/dist/src/schedule/record-window.js.map +1 -1
- package/dist/src/schedule/resources.d.ts +9 -5
- package/dist/src/schedule/resources.d.ts.map +1 -1
- package/dist/src/schedule/resources.js +35 -15
- package/dist/src/schedule/resources.js.map +1 -1
- package/dist/src/schedule/session.d.ts +15 -1
- package/dist/src/schedule/session.d.ts.map +1 -1
- package/dist/src/schedule/session.js +30 -18
- package/dist/src/schedule/session.js.map +1 -1
- package/dist/src/schedule/types.d.ts +455 -37
- package/dist/src/schedule/types.d.ts.map +1 -1
- package/dist/src/schedule/types.js +79 -18
- package/dist/src/schedule/types.js.map +1 -1
- package/dist/src/schedule/window.d.ts +30 -9
- package/dist/src/schedule/window.d.ts.map +1 -1
- package/dist/src/schedule/window.js +101 -49
- package/dist/src/schedule/window.js.map +1 -1
- package/dist/src/schematic/index.d.ts +287 -0
- package/dist/src/schematic/index.d.ts.map +1 -0
- package/dist/src/schematic/index.js +216 -0
- package/dist/src/schematic/index.js.map +1 -0
- package/dist/src/schematic/kinds.d.ts +501 -0
- package/dist/src/schematic/kinds.d.ts.map +1 -0
- package/dist/src/schematic/kinds.js +1027 -0
- package/dist/src/schematic/kinds.js.map +1 -0
- package/dist/src/schematic/layers.d.ts +74 -0
- package/dist/src/schematic/layers.d.ts.map +1 -0
- package/dist/src/schematic/layers.js +99 -0
- package/dist/src/schematic/layers.js.map +1 -0
- package/dist/src/schematic/library.d.ts +202 -0
- package/dist/src/schematic/library.d.ts.map +1 -0
- package/dist/src/schematic/library.js +244 -0
- package/dist/src/schematic/library.js.map +1 -0
- package/dist/src/schematic/payload.d.ts +8310 -0
- package/dist/src/schematic/payload.d.ts.map +1 -0
- package/dist/src/schematic/payload.js +446 -0
- package/dist/src/schematic/payload.js.map +1 -0
- package/dist/src/schematic/schematic.d.ts +27 -0
- package/dist/src/schematic/schematic.d.ts.map +1 -0
- package/dist/src/schematic/schematic.js +17 -0
- package/dist/src/schematic/schematic.js.map +1 -0
- package/dist/src/schematic/shapes.d.ts +150 -0
- package/dist/src/schematic/shapes.d.ts.map +1 -0
- package/dist/src/schematic/shapes.js +171 -0
- package/dist/src/schematic/shapes.js.map +1 -0
- package/dist/src/schematic/templates.d.ts +96 -0
- package/dist/src/schematic/templates.d.ts.map +1 -0
- package/dist/src/schematic/templates.js +91 -0
- package/dist/src/schematic/templates.js.map +1 -0
- package/dist/src/schematic/types.d.ts +5766 -0
- package/dist/src/schematic/types.d.ts.map +1 -0
- package/dist/src/schematic/types.js +688 -0
- package/dist/src/schematic/types.js.map +1 -0
- package/dist/src/schematic/window.d.ts +213 -0
- package/dist/src/schematic/window.d.ts.map +1 -0
- package/dist/src/schematic/window.js +340 -0
- package/dist/src/schematic/window.js.map +1 -0
- package/dist/src/sheet/bridge.d.ts +19 -0
- package/dist/src/sheet/bridge.d.ts.map +1 -1
- package/dist/src/sheet/bridge.js +28 -21
- package/dist/src/sheet/bridge.js.map +1 -1
- package/dist/src/sheet/editing-bridge.d.ts +4 -2
- package/dist/src/sheet/editing-bridge.d.ts.map +1 -1
- package/dist/src/sheet/editing-bridge.js +8 -2
- package/dist/src/sheet/editing-bridge.js.map +1 -1
- package/dist/src/sheet/editing-types.d.ts +9 -5
- package/dist/src/sheet/editing-types.d.ts.map +1 -1
- package/dist/src/sheet/editing-types.js +9 -5
- package/dist/src/sheet/editing-types.js.map +1 -1
- package/dist/src/sheet/index.d.ts +84 -54
- package/dist/src/sheet/index.d.ts.map +1 -1
- package/dist/src/sheet/index.js +81 -53
- package/dist/src/sheet/index.js.map +1 -1
- package/dist/src/sheet/library.d.ts +13 -8
- package/dist/src/sheet/library.d.ts.map +1 -1
- package/dist/src/sheet/library.js +13 -8
- package/dist/src/sheet/library.js.map +1 -1
- package/dist/src/sheet/optimise.d.ts +69 -0
- package/dist/src/sheet/optimise.d.ts.map +1 -0
- package/dist/src/sheet/optimise.js +81 -0
- package/dist/src/sheet/optimise.js.map +1 -0
- package/dist/src/sheet/record.d.ts +1 -1
- package/dist/src/sheet/record.js +2 -2
- package/dist/src/sheet/record.js.map +1 -1
- package/dist/src/sheet/registers.d.ts +157 -133
- package/dist/src/sheet/registers.d.ts.map +1 -1
- package/dist/src/sheet/registers.js +157 -133
- package/dist/src/sheet/registers.js.map +1 -1
- package/dist/src/sheet/root.d.ts +6 -1
- package/dist/src/sheet/root.d.ts.map +1 -1
- package/dist/src/sheet/root.js +17 -5
- package/dist/src/sheet/root.js.map +1 -1
- package/dist/src/sheet/sheet.d.ts +696 -590
- package/dist/src/sheet/sheet.d.ts.map +1 -1
- package/dist/src/sheet/sheet.js +49 -15
- package/dist/src/sheet/sheet.js.map +1 -1
- package/dist/src/sheet/sub-rows.d.ts +106 -76
- package/dist/src/sheet/sub-rows.d.ts.map +1 -1
- package/dist/src/sheet/sub-rows.js +106 -76
- package/dist/src/sheet/sub-rows.js.map +1 -1
- package/dist/src/sheet/types.d.ts +57 -20
- package/dist/src/sheet/types.d.ts.map +1 -1
- package/dist/src/sheet/types.js +4 -8
- package/dist/src/sheet/types.js.map +1 -1
- package/dist/src/studio/builder.d.ts +3 -153
- package/dist/src/studio/builder.d.ts.map +1 -1
- package/dist/src/studio/builder.js +1 -1
- package/dist/src/studio/canvas.d.ts +5 -4
- package/dist/src/studio/canvas.d.ts.map +1 -1
- package/dist/src/studio/canvas.js +8 -7
- package/dist/src/studio/canvas.js.map +1 -1
- package/dist/src/studio/component.d.ts +30 -20
- package/dist/src/studio/component.d.ts.map +1 -1
- package/dist/src/studio/component.js +26 -61
- package/dist/src/studio/component.js.map +1 -1
- package/dist/src/studio/index.d.ts +2 -2
- package/dist/src/studio/index.d.ts.map +1 -1
- package/dist/src/studio/index.js +1 -1
- package/dist/src/studio/index.js.map +1 -1
- package/dist/src/studio/inspector.d.ts +10 -39
- package/dist/src/studio/inspector.d.ts.map +1 -1
- package/dist/src/studio/inspector.js +11 -31
- package/dist/src/studio/inspector.js.map +1 -1
- package/dist/src/studio/library.d.ts +3 -169
- package/dist/src/studio/library.d.ts.map +1 -1
- package/dist/src/studio/library.js +1 -1
- package/dist/src/studio/page.d.ts +0 -8
- package/dist/src/studio/page.d.ts.map +1 -1
- package/dist/src/studio/pages.d.ts +17 -591
- package/dist/src/studio/pages.d.ts.map +1 -1
- package/dist/src/studio/pages.js +17 -44
- package/dist/src/studio/pages.js.map +1 -1
- package/dist/src/studio/palette.d.ts +2 -7
- package/dist/src/studio/palette.d.ts.map +1 -1
- package/dist/src/studio/palette.js +4 -5
- package/dist/src/studio/palette.js.map +1 -1
- package/dist/src/studio/publish.d.ts +8 -18
- package/dist/src/studio/publish.d.ts.map +1 -1
- package/dist/src/studio/publish.js +10 -36
- package/dist/src/studio/publish.js.map +1 -1
- package/dist/src/utils/derive.d.ts +12 -12
- package/dist/src/utils/derive.d.ts.map +1 -1
- package/dist/src/utils/derive.js +5 -2
- package/dist/src/utils/derive.js.map +1 -1
- package/dist/src/utils/keyed-rows.d.ts +41 -0
- package/dist/src/utils/keyed-rows.d.ts.map +1 -0
- package/dist/src/utils/keyed-rows.js +64 -0
- package/dist/src/utils/keyed-rows.js.map +1 -0
- package/dist/src/utils/optimise.d.ts +79 -0
- package/dist/src/utils/optimise.d.ts.map +1 -0
- package/dist/src/utils/optimise.js +46 -0
- package/dist/src/utils/optimise.js.map +1 -0
- package/dist/src/utils/ordered-source.d.ts.map +1 -1
- package/dist/src/utils/ordered-source.js +14 -5
- package/dist/src/utils/ordered-source.js.map +1 -1
- package/dist/test/allocation/allocation.examples.d.ts +1900 -1610
- package/dist/test/allocation/allocation.examples.d.ts.map +1 -1
- package/dist/test/allocation/allocation.examples.js +179 -89
- package/dist/test/allocation/allocation.examples.js.map +1 -1
- package/dist/test/allocation/optimise.examples.d.ts +109 -0
- package/dist/test/allocation/optimise.examples.d.ts.map +1 -0
- package/dist/test/allocation/optimise.examples.js +223 -0
- package/dist/test/allocation/optimise.examples.js.map +1 -0
- package/dist/test/bind/data/data.examples.d.ts +1172 -514
- package/dist/test/bind/data/data.examples.d.ts.map +1 -1
- package/dist/test/bind/data/data.examples.js +284 -164
- package/dist/test/bind/data/data.examples.js.map +1 -1
- package/dist/test/bind/record/record.examples.d.ts +457 -428
- package/dist/test/bind/record/record.examples.d.ts.map +1 -1
- package/dist/test/bind/record/record.examples.js +41 -21
- package/dist/test/bind/record/record.examples.js.map +1 -1
- package/dist/test/calendar/calendar-records.examples.d.ts +162 -170
- package/dist/test/calendar/calendar-records.examples.d.ts.map +1 -1
- package/dist/test/calendar/calendar-records.examples.js +20 -12
- package/dist/test/calendar/calendar-records.examples.js.map +1 -1
- package/dist/test/calendar/calendar-windows.examples.d.ts +9 -0
- package/dist/test/calendar/calendar-windows.examples.d.ts.map +1 -0
- package/dist/test/calendar/calendar-windows.examples.js +111 -0
- package/dist/test/calendar/calendar-windows.examples.js.map +1 -0
- package/dist/test/calendar/calendar.examples.d.ts +1172 -915
- package/dist/test/calendar/calendar.examples.d.ts.map +1 -1
- package/dist/test/calendar/calendar.examples.js +211 -124
- package/dist/test/calendar/calendar.examples.js.map +1 -1
- package/dist/test/calendar/optimise.examples.d.ts +132 -0
- package/dist/test/calendar/optimise.examples.d.ts.map +1 -0
- package/dist/test/calendar/optimise.examples.js +75 -0
- package/dist/test/calendar/optimise.examples.js.map +1 -0
- package/dist/test/examples-package.d.ts +49 -16
- package/dist/test/examples-package.d.ts.map +1 -1
- package/dist/test/examples-package.js +138 -49
- package/dist/test/examples-package.js.map +1 -1
- package/dist/test/flowchart/flowchart.examples.d.ts +3841 -2840
- package/dist/test/flowchart/flowchart.examples.d.ts.map +1 -1
- package/dist/test/flowchart/flowchart.examples.js +211 -121
- package/dist/test/flowchart/flowchart.examples.js.map +1 -1
- package/dist/test/plan/optimise.examples.d.ts +207 -0
- package/dist/test/plan/optimise.examples.d.ts.map +1 -0
- package/dist/test/plan/optimise.examples.js +98 -0
- package/dist/test/plan/optimise.examples.js.map +1 -0
- package/dist/test/plan/plan-events.examples.d.ts +4055 -3279
- package/dist/test/plan/plan-events.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-events.examples.js +492 -319
- package/dist/test/plan/plan-events.examples.js.map +1 -1
- package/dist/test/plan/plan-nested.examples.d.ts +1829 -0
- package/dist/test/plan/plan-nested.examples.d.ts.map +1 -0
- package/dist/test/plan/plan-nested.examples.js +321 -0
- package/dist/test/plan/plan-nested.examples.js.map +1 -0
- package/dist/test/plan/plan-records.examples.d.ts +391 -244
- package/dist/test/plan/plan-records.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-records.examples.js +186 -65
- package/dist/test/plan/plan-records.examples.js.map +1 -1
- package/dist/test/plan/plan-windows.examples.d.ts +1978 -803
- package/dist/test/plan/plan-windows.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-windows.examples.js +269 -99
- package/dist/test/plan/plan-windows.examples.js.map +1 -1
- package/dist/test/plan/plan.examples.d.ts +2238 -5726
- package/dist/test/plan/plan.examples.d.ts.map +1 -1
- package/dist/test/plan/plan.examples.js +846 -973
- package/dist/test/plan/plan.examples.js.map +1 -1
- package/dist/test/query/query.examples.d.ts +5221 -3005
- package/dist/test/query/query.examples.d.ts.map +1 -1
- package/dist/test/query/query.examples.js +169 -118
- package/dist/test/query/query.examples.js.map +1 -1
- package/dist/test/roster/domain.examples.d.ts +804 -0
- package/dist/test/roster/domain.examples.d.ts.map +1 -1
- package/dist/test/roster/domain.examples.js +3 -3
- package/dist/test/roster/domain.examples.js.map +1 -1
- package/dist/test/roster/optimise.examples.d.ts +485 -0
- package/dist/test/roster/optimise.examples.d.ts.map +1 -0
- package/dist/test/roster/optimise.examples.js +155 -0
- package/dist/test/roster/optimise.examples.js.map +1 -0
- package/dist/test/roster/roster-records.examples.d.ts +364 -404
- package/dist/test/roster/roster-records.examples.d.ts.map +1 -1
- package/dist/test/roster/roster-records.examples.js +40 -26
- package/dist/test/roster/roster-records.examples.js.map +1 -1
- package/dist/test/roster/roster.examples.d.ts +5091 -1424
- package/dist/test/roster/roster.examples.d.ts.map +1 -1
- package/dist/test/roster/roster.examples.js +255 -109
- package/dist/test/roster/roster.examples.js.map +1 -1
- package/dist/test/roster/warehouse.d.ts +150 -7
- package/dist/test/roster/warehouse.d.ts.map +1 -1
- package/dist/test/roster/warehouse.js +36 -11
- package/dist/test/roster/warehouse.js.map +1 -1
- package/dist/test/schedule/schedule.examples.d.ts +2646 -2473
- package/dist/test/schedule/schedule.examples.d.ts.map +1 -1
- package/dist/test/schedule/schedule.examples.js +144 -88
- package/dist/test/schedule/schedule.examples.js.map +1 -1
- package/dist/test/schematic/schematic-records.examples.d.ts +454 -0
- package/dist/test/schematic/schematic-records.examples.d.ts.map +1 -0
- package/dist/test/schematic/schematic-records.examples.js +219 -0
- package/dist/test/schematic/schematic-records.examples.js.map +1 -0
- package/dist/test/schematic/schematic.examples.d.ts +2640 -0
- package/dist/test/schematic/schematic.examples.d.ts.map +1 -0
- package/dist/test/schematic/schematic.examples.js +559 -0
- package/dist/test/schematic/schematic.examples.js.map +1 -0
- package/dist/test/sheet/optimise.examples.d.ts +184 -0
- package/dist/test/sheet/optimise.examples.d.ts.map +1 -0
- package/dist/test/sheet/optimise.examples.js +79 -0
- package/dist/test/sheet/optimise.examples.js.map +1 -0
- package/dist/test/sheet/sheet-records.examples.d.ts +208 -356
- package/dist/test/sheet/sheet-records.examples.d.ts.map +1 -1
- package/dist/test/sheet/sheet-records.examples.js +66 -29
- package/dist/test/sheet/sheet-records.examples.js.map +1 -1
- package/dist/test/sheet/sheet.examples.d.ts +3650 -3377
- package/dist/test/sheet/sheet.examples.d.ts.map +1 -1
- package/dist/test/sheet/sheet.examples.js +406 -296
- package/dist/test/sheet/sheet.examples.js.map +1 -1
- package/dist/test/studio/component.examples.js +2 -2
- package/dist/test/studio/component.examples.js.map +1 -1
- package/dist/test/studio/page.examples.js +6 -6
- package/dist/test/studio/page.examples.js.map +1 -1
- package/dist/test/studio/studio.examples.d.ts +2329 -873
- package/dist/test/studio/studio.examples.d.ts.map +1 -1
- package/dist/test/studio/studio.examples.js +155 -107
- package/dist/test/studio/studio.examples.js.map +1 -1
- package/package.json +15 -11
package/dist/src/plan/series.js
CHANGED
|
@@ -34,11 +34,12 @@
|
|
|
34
34
|
*
|
|
35
35
|
* @packageDocumentation
|
|
36
36
|
*/
|
|
37
|
-
import { East, Expr, ArrayType, BlobType, BooleanType, DateTimeType, DictType, EastTypeType, FloatType, FunctionType, IntegerType, OptionType, RefType, StringType, StructType, VariantType, isTypeEqual, printFor, toEastTypeValue, variant, some, none, } from "@elaraai/east";
|
|
37
|
+
import { East, Expr, ArrayType, BlobType, BooleanType, DateTimeType, DictType, EastTypeType, FloatType, FunctionType, IntegerType, NullType, OptionType, RefType, StringType, StructType, VariantType, isTypeEqual, isVariant, printFor, printTypeSummary, toEastTypeValue, variant, some, none, } from "@elaraai/east";
|
|
38
38
|
import { IconType, StatusValueType } from "@elaraai/east-ui";
|
|
39
39
|
import { TableAggregateType, TickFormatType, reifyAccessor, resolveTag } from "@elaraai/east-ui/internal";
|
|
40
|
-
import { PlanAggregateType, PlanExpandType, PlanGroupSummaryType, PlanHeatCellsType, PlanLaneType, PlanBucketEventType, PlanCellMarkerType, PlanChipType, PlanEventMarkType, PlanRunType, PlanDecisionMarkType, PlanPortType, PlanRollupType, PlanRowIdType, PlanRowKindType, PlanRowType, PlanRowsCollectionType, PlanBlockType, PlanBlocksType, PlanGestureType, PlanDropType, PlanInstantType, } from "./types.js";
|
|
41
|
-
import { resolveIcon } from "./builders.js";
|
|
40
|
+
import { PlanAggregateType, PlanExpandType, PlanGroupSummaryType, PlanHeatCellsType, PlanLaneType, PlanBucketEventType, PlanCellMarkerType, PlanChipType, PlanEventMarkType, PlanRunType, PlanDecisionMarkType, PlanPortType, PlanRollupType, PlanRowIdType, PlanRowKindType, PlanRowType, PlanRowsCollectionType, PlanBlockType, PlanBlocksType, PlanGestureType, PlanDropType, PlanInstantType, PlanFoldType, } from "./types.js";
|
|
41
|
+
import { PLAN_LOOKS, resolveIcon, resolveInstant, } from "./builders.js";
|
|
42
|
+
import { PlanReadsBrand, PlanUseBrand, planReadOf, planUseOf, } from "./reads.js";
|
|
42
43
|
import { planRow, planGutter, normalizeRows, REBASE_ROWS } from "./assemble.js";
|
|
43
44
|
import { spanKind, bucketsKind, chartKind, heatKind, tableKind, cardsKind, eventsKind, groupKind, groupSummary, } from "./factories.js";
|
|
44
45
|
// ============================================================================
|
|
@@ -106,15 +107,35 @@ export const PlanSeriesType = seriesShape;
|
|
|
106
107
|
/** Marks a {@link PlanChildren} step-down. */
|
|
107
108
|
const PLAN_CHILDREN = Symbol("PlanChildren");
|
|
108
109
|
/**
|
|
109
|
-
* Step down from an entry to
|
|
110
|
+
* Step down from an entry to its child rows (#822, #1436): a `Dict` field of
|
|
111
|
+
* the entry, keyed by an id, its rows laid out by `series` like a top-level
|
|
112
|
+
* list.
|
|
110
113
|
*
|
|
111
114
|
* @typeParam R - The parent entry type (inferred from where the step-down is used)
|
|
112
|
-
* @typeParam
|
|
113
|
-
* @
|
|
114
|
-
* @param
|
|
115
|
+
* @typeParam F - The field holding the child rows
|
|
116
|
+
* @typeParam S - The series over them, as written
|
|
117
|
+
* @param field - A Dict field of the entry holding the child rows, keyed by an id
|
|
118
|
+
* @param series - The series over the child rows
|
|
115
119
|
* @returns The step-down, for a series' `children`
|
|
116
120
|
*/
|
|
117
|
-
export function createChildren(
|
|
121
|
+
export function createChildren(field, series) {
|
|
122
|
+
if (typeof field !== "string") {
|
|
123
|
+
throw new Error("Plan.children: name the field holding the child rows — a Dict of the row, keyed by an id: Plan.children(\"members\", [series…])");
|
|
124
|
+
}
|
|
125
|
+
return { [PLAN_CHILDREN]: true, field, series };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Step down from an entry to a collection an accessor computes (#1194) — the
|
|
129
|
+
* event kinds' own: a resource's events come from another record, so its
|
|
130
|
+
* child rows are no field of it. An author's step-down names its field
|
|
131
|
+
* ({@link createChildren}).
|
|
132
|
+
*
|
|
133
|
+
* @internal
|
|
134
|
+
* @param of - The child collection, from the parent entry's value and key
|
|
135
|
+
* @param series - The series over the child entries
|
|
136
|
+
* @returns The step-down
|
|
137
|
+
*/
|
|
138
|
+
export function createChildrenOf(of, series) {
|
|
118
139
|
return { [PLAN_CHILDREN]: true, of, series };
|
|
119
140
|
}
|
|
120
141
|
function isStepDown(x) {
|
|
@@ -127,6 +148,36 @@ const PathType = ArrayType(StringType);
|
|
|
127
148
|
const IdOptType = OptionType(PlanRowIdType);
|
|
128
149
|
/** Every series value a builder made, with its build spec. */
|
|
129
150
|
const SPECS = new WeakMap();
|
|
151
|
+
/** A spec's facts for the nested checks (#1435). */
|
|
152
|
+
function nestFactsOf(spec) {
|
|
153
|
+
return { key: spec.key, arm: spec.arm, reads: spec.reads, nest: spec.nest };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The facts a Plan holds to its rows' nested series index (#1435), of a
|
|
157
|
+
* series value a `Plan.series.*` builder made, and of each series its spec
|
|
158
|
+
* nests: `facts(spec)` for any of them.
|
|
159
|
+
*
|
|
160
|
+
* @param series - The series value
|
|
161
|
+
* @returns Its facts; `undefined` for a value no builder made in place (a bound, picked or stored one)
|
|
162
|
+
* @internal
|
|
163
|
+
*/
|
|
164
|
+
export function planSeriesNestOf(series) {
|
|
165
|
+
const spec = specOf(series);
|
|
166
|
+
return spec === undefined ? undefined : nestFactsOf(spec);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The facts of the series a spec nests (#1435), as {@link planSeriesNestOf} gives them.
|
|
170
|
+
*
|
|
171
|
+
* @param nest - A series' nest
|
|
172
|
+
* @returns Its step-downs' series and its members, each with its facts
|
|
173
|
+
* @internal
|
|
174
|
+
*/
|
|
175
|
+
export function planNestedSeriesFacts(nest) {
|
|
176
|
+
return {
|
|
177
|
+
steps: nest.steps.map((step) => ({ field: step.field, of: step.of, series: step.series.map(nestFactsOf) })),
|
|
178
|
+
members: nest.members.map(nestFactsOf),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
130
181
|
/** The spec of a series value a `Plan.series.*` builder made, if it was one. */
|
|
131
182
|
function specOf(s) {
|
|
132
183
|
return typeof s === "object" && s !== null ? SPECS.get(s) : undefined;
|
|
@@ -173,14 +224,49 @@ function segmentOf(keyType) {
|
|
|
173
224
|
* @param collection - The collection type the rows are built for
|
|
174
225
|
* @param rows - The series' rows emitter for that collection
|
|
175
226
|
* @param fixed - Whether no entry produces the rows
|
|
227
|
+
* @param charts - How many chart rows each entry makes, when every entry makes as many (#1398) — a fixed block's none
|
|
176
228
|
* @returns The block list's emitter
|
|
177
229
|
*/
|
|
178
|
-
function oneBlock(collection, rows, fixed) {
|
|
230
|
+
function oneBlock(collection, rows, fixed, charts) {
|
|
231
|
+
const each = fixed || charts === undefined ? none : some(BigInt(charts));
|
|
179
232
|
return East.function([collection, PathType, IdOptType], PlanBlocksType, ($, coll, prefix, parent) => {
|
|
180
|
-
const block = $.let(East.value({ fixed, parent, rows: rows(coll, prefix, parent) }, PlanBlockType), PlanBlockType);
|
|
233
|
+
const block = $.let(East.value({ fixed, parent, charts: each, rows: rows(coll, prefix, parent) }, PlanBlockType), PlanBlockType);
|
|
181
234
|
return East.value([block], PlanBlocksType);
|
|
182
235
|
});
|
|
183
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* The chart rows an entry makes across a list of series, when each makes a fixed number (#1398).
|
|
239
|
+
*
|
|
240
|
+
* @param specs - The series
|
|
241
|
+
* @returns Their sum; `undefined` where one of them varies by entry
|
|
242
|
+
*/
|
|
243
|
+
function chartsOf(specs) {
|
|
244
|
+
let sum = 0;
|
|
245
|
+
for (const spec of specs) {
|
|
246
|
+
if (spec.charts === undefined)
|
|
247
|
+
return undefined;
|
|
248
|
+
sum += spec.charts;
|
|
249
|
+
}
|
|
250
|
+
return sum;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* How many chart rows each entry of a series makes (#1398): its own rows' and those below them — where the rows
|
|
254
|
+
* below hold any, as many as the data's children, which no definition fixes — and a `match` deciding by entry
|
|
255
|
+
* whether it makes them.
|
|
256
|
+
*
|
|
257
|
+
* @param own - The chart rows its entry's own rows make: `undefined` where they vary by entry
|
|
258
|
+
* @param below - The chart rows its children's rows hold for each child: `0` where they hold none, else how many
|
|
259
|
+
* (`undefined` where that varies)
|
|
260
|
+
* @param matched - Whether a `match` decides which entries it takes
|
|
261
|
+
* @returns The entry's chart rows; `undefined` where they vary by entry
|
|
262
|
+
*/
|
|
263
|
+
function entryCharts(own, below, matched) {
|
|
264
|
+
// Rows below an entry come one set a child, and the data decides how many children an entry has.
|
|
265
|
+
if (own === undefined || below !== 0)
|
|
266
|
+
return undefined;
|
|
267
|
+
// A match makes an entry's rows or none — as many either way only when they hold no chart.
|
|
268
|
+
return matched && own > 0 ? undefined : own;
|
|
269
|
+
}
|
|
184
270
|
/** A cache of built functions by East type. */
|
|
185
271
|
class ByType {
|
|
186
272
|
entries = [];
|
|
@@ -273,85 +359,34 @@ function collectionOps(collection) {
|
|
|
273
359
|
put: (c, k, v) => array(c).update(index(k), v),
|
|
274
360
|
};
|
|
275
361
|
}
|
|
276
|
-
/** The
|
|
277
|
-
|
|
278
|
-
return arm === "span" || arm === "cards" ? "span" : "point";
|
|
279
|
-
}
|
|
280
|
-
/** The item field types a move can write an instant into (#825). */
|
|
281
|
-
const INSTANT_FIELD_TYPES = [DateTimeType, FloatType, IntegerType, StringType, PlanInstantType];
|
|
362
|
+
/** The item field types a move can write an instant into (#825, #1436). */
|
|
363
|
+
const INSTANT_FIELD_TYPES = [DateTimeType, FloatType, IntegerType, StringType, PlanInstantType, OptionType(DateTimeType)];
|
|
282
364
|
/** Print an item type as the text rows of one item type share (#825) — East's own printer over its type value. */
|
|
283
365
|
const printType = printFor(EastTypeType);
|
|
284
366
|
/**
|
|
285
|
-
*
|
|
286
|
-
*
|
|
367
|
+
* What a move writes, from the read that names the collection (#1436) — its
|
|
368
|
+
* times, checked against the item type by the read's build.
|
|
287
369
|
*
|
|
288
|
-
* @param
|
|
289
|
-
* @param
|
|
290
|
-
* @param arm - The series' kind
|
|
291
|
-
* @param where - The series, for the message
|
|
370
|
+
* @param read - The elements' read
|
|
371
|
+
* @param item - The collection's item type
|
|
292
372
|
* @returns The move's fields
|
|
293
|
-
* @throws {Error} Naming the field and what is wrong with it
|
|
294
373
|
*/
|
|
295
|
-
function moveFieldsOf(
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
const start = shape === "span" ? edit.start : edit.at;
|
|
304
|
-
const end = shape === "span" ? edit.end : undefined;
|
|
305
|
-
if (shape === "span" && (start === undefined) !== (end === undefined)) {
|
|
306
|
-
throw new Error(`${where}: a move writes both ends of a ${arm} element — give \`edit.start\` and \`edit.end\` together`);
|
|
307
|
-
}
|
|
308
|
-
if (start === undefined) {
|
|
309
|
-
if (edit.create === undefined) {
|
|
310
|
-
throw new Error(`${where}: \`edit\` declares neither \`create\` (what a dropped card becomes) nor the item fields a move ` +
|
|
311
|
-
`writes (\`key\` and ${shape === "span" ? "`start` / `end`" : "`at`"}) — declare one or both`);
|
|
312
|
-
}
|
|
313
|
-
return undefined;
|
|
314
|
-
}
|
|
315
|
-
const item = itemType;
|
|
316
|
-
if (item.type !== "Struct") {
|
|
317
|
-
throw new Error(`${where}: a move writes fields of the item — the items in "${edit.items}" must be structs`);
|
|
318
|
-
}
|
|
319
|
-
if (edit.key === undefined) {
|
|
320
|
-
throw new Error(`${where}: a move finds its element's item by key — name the item's String key field with \`edit.key\``);
|
|
321
|
-
}
|
|
322
|
-
const keyType = item.fields[edit.key];
|
|
323
|
-
if (keyType === undefined || !isTypeEqual(keyType, StringType)) {
|
|
324
|
-
throw new Error(`${where}: \`edit.key\` names "${edit.key}", which is not a String field of the item`);
|
|
325
|
-
}
|
|
326
|
-
const instant = (name, what) => {
|
|
327
|
-
const type = item.fields[name];
|
|
328
|
-
if (type === undefined || !INSTANT_FIELD_TYPES.some((t) => isTypeEqual(t, type))) {
|
|
329
|
-
throw new Error(`${where}: \`edit.${what}\` names "${name}", which is not an instant field of the item — a DateTime, a Float or ` +
|
|
330
|
-
"an Integer, a String, or a Plan.Types.Instant");
|
|
331
|
-
}
|
|
332
|
-
if (name === edit.key) {
|
|
333
|
-
throw new Error(`${where}: \`edit.${what}\` names the key field "${name}" — a move would change the item's identity; name its instant field`);
|
|
334
|
-
}
|
|
335
|
-
return { name, type };
|
|
336
|
-
};
|
|
337
|
-
if (end !== undefined && end === start) {
|
|
338
|
-
throw new Error(`${where}: \`edit.start\` and \`edit.end\` both name "${start}" — a move writes two different fields`);
|
|
339
|
-
}
|
|
340
|
-
return {
|
|
341
|
-
item,
|
|
342
|
-
key: edit.key,
|
|
343
|
-
start: instant(start, shape === "span" ? "start" : "at"),
|
|
344
|
-
end: end !== undefined ? instant(end, "end") : undefined,
|
|
345
|
-
edits: { items: printType(toEastTypeValue(itemType)), resize: shape === "span" },
|
|
346
|
-
};
|
|
374
|
+
function moveFieldsOf(read, item) {
|
|
375
|
+
const field = (name) => ({ name, type: item.fields[name] });
|
|
376
|
+
const times = read.times;
|
|
377
|
+
const edits = { items: printType(toEastTypeValue(item)), resize: !("at" in times) };
|
|
378
|
+
return "at" in times
|
|
379
|
+
? { item, start: field(times.at), end: undefined, edits }
|
|
380
|
+
: { item, start: field(times.from), end: field(times.to), edits };
|
|
347
381
|
}
|
|
348
382
|
/** Each instant field type's converter, built once (#825). */
|
|
349
383
|
const instantConverters = new ByType();
|
|
350
384
|
/**
|
|
351
385
|
* The converter from an axis instant into an item field's type (#825): the
|
|
352
|
-
* instant on the arm the field holds — a time instant's DateTime
|
|
353
|
-
*
|
|
354
|
-
* ordinal instant's String, or the
|
|
386
|
+
* instant on the arm the field holds — a time instant's DateTime (an `Option`
|
|
387
|
+
* of one takes it as `some`, #1436), a number instant's Float (an Integer field
|
|
388
|
+
* takes it rounded, half away from zero), an ordinal instant's String, or the
|
|
389
|
+
* instant itself — else `none`.
|
|
355
390
|
*
|
|
356
391
|
* @param fieldType - The field's type (one of {@link INSTANT_FIELD_TYPES})
|
|
357
392
|
* @returns `(instant) → Option<field>`
|
|
@@ -361,6 +396,7 @@ function instantInto(fieldType) {
|
|
|
361
396
|
const out = OptionType(fieldType);
|
|
362
397
|
const kind = fieldType.type;
|
|
363
398
|
const whole = isTypeEqual(fieldType, PlanInstantType);
|
|
399
|
+
const optional = isTypeEqual(fieldType, OptionType(DateTimeType));
|
|
364
400
|
return East.function([PlanInstantType], out, ($, t) => {
|
|
365
401
|
const result = $.let(none, out);
|
|
366
402
|
if (whole) {
|
|
@@ -371,6 +407,9 @@ function instantInto(fieldType) {
|
|
|
371
407
|
time: ($2, d) => {
|
|
372
408
|
if (kind === "DateTime")
|
|
373
409
|
$2.assign(result, some(d));
|
|
410
|
+
// An Option of a DateTime holds the instant as `some` (#1436).
|
|
411
|
+
if (optional)
|
|
412
|
+
$2.assign(result, some(some(d)));
|
|
374
413
|
},
|
|
375
414
|
number: ($2, n) => {
|
|
376
415
|
if (kind === "Float") {
|
|
@@ -390,6 +429,570 @@ function instantInto(fieldType) {
|
|
|
390
429
|
});
|
|
391
430
|
});
|
|
392
431
|
}
|
|
432
|
+
/** An East type's name as a message reads it: `an Array`, `a Dict`. */
|
|
433
|
+
function anOf(type) {
|
|
434
|
+
const name = type.type;
|
|
435
|
+
return /^[AEIOU]/.test(name) ? `an ${name}` : `a ${name}`;
|
|
436
|
+
}
|
|
437
|
+
/** A row type's shape as a message reads it: its fields, `{ name, load }`, or East's summary of another type. */
|
|
438
|
+
function shapeName(type) {
|
|
439
|
+
const t = type;
|
|
440
|
+
if (t.type === "Recursive" && t.node !== undefined)
|
|
441
|
+
return shapeName(t.node);
|
|
442
|
+
if (t.type === "Struct" && t.fields !== undefined)
|
|
443
|
+
return `{ ${Object.keys(t.fields).join(", ")} }`;
|
|
444
|
+
return printTypeSummary(type);
|
|
445
|
+
}
|
|
446
|
+
/** The fields of an entry type — a struct's own, or a recursive entry's node's. */
|
|
447
|
+
function entryFieldsOf(rowType) {
|
|
448
|
+
const t = rowType;
|
|
449
|
+
if (t.type === "Struct")
|
|
450
|
+
return t.fields;
|
|
451
|
+
if (t.type === "Recursive" && t.node?.type === "Struct")
|
|
452
|
+
return t.node.fields;
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
/** The key types a values collection may be keyed by: its instants. */
|
|
456
|
+
const VALUE_KEY_TYPES = [DateTimeType, FloatType, IntegerType, StringType];
|
|
457
|
+
/**
|
|
458
|
+
* The collection a read names, checked against the entry type (#1436).
|
|
459
|
+
*
|
|
460
|
+
* @param rowType - The entry type
|
|
461
|
+
* @param read - The read
|
|
462
|
+
* @param where - The series, for the messages
|
|
463
|
+
* @returns The collection's shape
|
|
464
|
+
* @throws {Error} In the refusals' words: no Dict field of the row, an items collection keyed by an instant or holding no
|
|
465
|
+
* struct, a time that is no instant field of its items, a values collection keyed by no instant
|
|
466
|
+
*/
|
|
467
|
+
function collectionOfRead(rowType, read, where) {
|
|
468
|
+
const what = read.kind === "items" ? "Plan.items" : "Plan.values";
|
|
469
|
+
const fields = entryFieldsOf(rowType);
|
|
470
|
+
const t = fields?.[read.field];
|
|
471
|
+
if (t === undefined) {
|
|
472
|
+
throw new Error(`${where}: ${what} reads "${read.field}", which is no field of its rows — name a Dict field of the row`);
|
|
473
|
+
}
|
|
474
|
+
if (t.type !== "Dict") {
|
|
475
|
+
throw new Error(`${what}: "${read.field}" is ${anOf(t)} — a collection a series reads by name is a Dict, keyed by an id, ` +
|
|
476
|
+
"or by its instant for values");
|
|
477
|
+
}
|
|
478
|
+
const key = t.key;
|
|
479
|
+
const item = t.value;
|
|
480
|
+
const keyName = key.type;
|
|
481
|
+
if (read.kind === "values") {
|
|
482
|
+
if (!VALUE_KEY_TYPES.some((k) => isTypeEqual(k, key))) {
|
|
483
|
+
throw new Error(`Plan.values: "${read.field}" is keyed by ${keyName} — values are keyed by their instant: a DateTime, a Float, ` +
|
|
484
|
+
"an Integer or a String");
|
|
485
|
+
}
|
|
486
|
+
return { dict: t, key, item };
|
|
487
|
+
}
|
|
488
|
+
if (!isTypeEqual(key, StringType)) {
|
|
489
|
+
throw new Error(`Plan.items: "${read.field}" is keyed by ${keyName} — things people drag are keyed by an id, a String: read values ` +
|
|
490
|
+
`with Plan.values("${read.field}", draw)`);
|
|
491
|
+
}
|
|
492
|
+
const struct = item;
|
|
493
|
+
if (struct.type !== "Struct" || struct.fields === undefined) {
|
|
494
|
+
throw new Error(`Plan.items: "${read.field}" holds ${anOf(item)}, not an item — things people drag are structs, their times fields ` +
|
|
495
|
+
`of them: read values with Plan.values("${read.field}", draw)`);
|
|
496
|
+
}
|
|
497
|
+
const names = "at" in read.times ? [read.times.at] : [read.times.from, read.times.to];
|
|
498
|
+
if (names.length === 2 && names[0] === names[1]) {
|
|
499
|
+
throw new Error(`Plan.items: "${read.field}" names "${names[0]}" as both its from and its to — a run's start and end are two fields of its items`);
|
|
500
|
+
}
|
|
501
|
+
for (const name of names) {
|
|
502
|
+
const ft = struct.fields[name];
|
|
503
|
+
if (ft === undefined) {
|
|
504
|
+
throw new Error(`Plan.items: "${read.field}" names its times by "${name}", which is no field of its items — name a time field of the item`);
|
|
505
|
+
}
|
|
506
|
+
if (!INSTANT_FIELD_TYPES.some((k) => isTypeEqual(k, ft))) {
|
|
507
|
+
throw new Error(`Plan.items: "${read.field}" names "${name}", ${anOf(ft)} field of its items, as a time — a time is a DateTime or an ` +
|
|
508
|
+
"Option of one, a Float, an Integer, a String, or a Plan.Types.Instant");
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return { dict: t, key, item };
|
|
512
|
+
}
|
|
513
|
+
/** Each element's look type: its type without its key and its instants. */
|
|
514
|
+
const lookTypes = new Map();
|
|
515
|
+
/** What `draw` gives for an element of `kind`, as an East struct: the element without its key and its instants. */
|
|
516
|
+
function lookTypeOf(kind) {
|
|
517
|
+
let type = lookTypes.get(kind);
|
|
518
|
+
if (type === undefined) {
|
|
519
|
+
const spec = PLAN_LOOKS[kind];
|
|
520
|
+
const omit = [...(spec.key !== undefined ? [spec.key] : []), ...spec.instants];
|
|
521
|
+
type = StructType(Object.fromEntries(Object.entries(spec.type.fields).filter(([f]) => !omit.includes(f))));
|
|
522
|
+
lookTypes.set(kind, type);
|
|
523
|
+
}
|
|
524
|
+
return type;
|
|
525
|
+
}
|
|
526
|
+
/** What each element kind is called where a refusal names it. */
|
|
527
|
+
const ELEMENT_NAMES = {
|
|
528
|
+
run: "runs", decision: "decisions", port: "ports", event: "events", marker: "markers", chip: "chips", mark: "marks",
|
|
529
|
+
heat: "heat cells", weight: "weight cells", segment: "segment cells", table: "table cells", point: "points", band: "band points",
|
|
530
|
+
};
|
|
531
|
+
/** Each read's builds, by what it completes and the entry type. */
|
|
532
|
+
const readBuilds = new WeakMap();
|
|
533
|
+
/**
|
|
534
|
+
* A read built for one entry type (#1436): `(collection, entry) → elements` —
|
|
535
|
+
* each item an element at its times, keyed by its id, or each value one at its
|
|
536
|
+
* instant, its look `draw`'s. The collection is an argument, so the same build
|
|
537
|
+
* draws an inline row's own collection and one read a cell at a time.
|
|
538
|
+
*
|
|
539
|
+
* @param rowType - The entry type
|
|
540
|
+
* @param read - The read
|
|
541
|
+
* @param kind - What each item or value completes to
|
|
542
|
+
* @param where - The series, for messages
|
|
543
|
+
* @returns The built function
|
|
544
|
+
* @throws {Error} When the read does not build for the entry type, in the refusals' words
|
|
545
|
+
*/
|
|
546
|
+
function buildRead(rowType, read, kind, where) {
|
|
547
|
+
let byKind = readBuilds.get(read);
|
|
548
|
+
if (byKind === undefined) {
|
|
549
|
+
byKind = new Map();
|
|
550
|
+
readBuilds.set(read, byKind);
|
|
551
|
+
}
|
|
552
|
+
let byType = byKind.get(kind);
|
|
553
|
+
if (byType === undefined) {
|
|
554
|
+
byType = new ByType();
|
|
555
|
+
byKind.set(kind, byType);
|
|
556
|
+
}
|
|
557
|
+
return byType.get(rowType, () => {
|
|
558
|
+
const shape = collectionOfRead(rowType, read, where);
|
|
559
|
+
const spec = PLAN_LOOKS[kind];
|
|
560
|
+
const elemType = spec.type;
|
|
561
|
+
const lookType = lookTypeOf(kind);
|
|
562
|
+
const recursive = rowType.type === "Recursive";
|
|
563
|
+
const what = read.kind === "items" ? `Plan.items("${read.field}", …)` : `Plan.values("${read.field}", …)`;
|
|
564
|
+
// The look, reified once: `(item or value, id or instant, entry) → look`.
|
|
565
|
+
const look = (() => {
|
|
566
|
+
try {
|
|
567
|
+
return East.function([shape.item, shape.key, rowType], lookType, ($, item, key, row) => {
|
|
568
|
+
const node = recursive ? $.let(row.unwrap()) : row;
|
|
569
|
+
const given = read.draw(item, key, node);
|
|
570
|
+
if (given === null || typeof given !== "object" || given instanceof Expr) {
|
|
571
|
+
throw new Error(`its draw gives the look of each of its ${ELEMENT_NAMES[kind]}, an object of their fields`);
|
|
572
|
+
}
|
|
573
|
+
return East.value(spec.look(given), lookType);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
catch (err) {
|
|
577
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
578
|
+
throw new Error(`${where}: ${what} does not build for its rows (${reason})`);
|
|
579
|
+
}
|
|
580
|
+
})();
|
|
581
|
+
const fieldsOf = (l) => Object.fromEntries(Object.keys(lookType.fields).map((f) => [f, l[f]]));
|
|
582
|
+
const out = ArrayType(elemType);
|
|
583
|
+
if (read.kind === "values") {
|
|
584
|
+
const at = spec.instants[0];
|
|
585
|
+
return East.function([shape.dict, rowType], out, ($, coll, row) => {
|
|
586
|
+
const draw = $.const(look);
|
|
587
|
+
return coll.toArray(($2, value, key) => {
|
|
588
|
+
const l = $2.let(draw(value, key, row));
|
|
589
|
+
return East.value({ [at]: resolveInstant(key, `${what} key`), ...fieldsOf(l) }, elemType);
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
// Things people drag: each at its named times, keyed by its id. An item whose
|
|
594
|
+
// start is an Option holding none is drawn nowhere; one whose end holds none is
|
|
595
|
+
// an instant (#1434's filing).
|
|
596
|
+
const item = shape.item;
|
|
597
|
+
const times = read.times;
|
|
598
|
+
const names = "at" in times ? [times.at] : [times.from, times.to];
|
|
599
|
+
if (names.length !== spec.instants.length) {
|
|
600
|
+
throw new Error(spec.instants.length === 2
|
|
601
|
+
? `${where}: its ${ELEMENT_NAMES[kind]} run from a start to an end — read them with Plan.items("${read.field}", { from, to }, draw)`
|
|
602
|
+
: `${where}: its ${ELEMENT_NAMES[kind]} sit at an instant — read them with Plan.items("${read.field}", { at }, draw)`);
|
|
603
|
+
}
|
|
604
|
+
const optional = (name) => isTypeEqual(item.fields[name], OptionType(DateTimeType));
|
|
605
|
+
const instantOf = (v) => resolveInstant(v, `${what} times`);
|
|
606
|
+
const keyField = spec.key;
|
|
607
|
+
return East.function([shape.dict, rowType], out, ($, coll, row) => {
|
|
608
|
+
const draw = $.const(look);
|
|
609
|
+
const result = $.let([], out);
|
|
610
|
+
$.for(coll, ($2, value, key) => {
|
|
611
|
+
const fields = value;
|
|
612
|
+
const id = key;
|
|
613
|
+
const emit = ($3, instants) => {
|
|
614
|
+
const l = $3.let(draw(value, id, row));
|
|
615
|
+
$3(result.pushLast(East.value({
|
|
616
|
+
[keyField]: id,
|
|
617
|
+
...Object.fromEntries(spec.instants.map((name, i) => [name, instants[i]])),
|
|
618
|
+
...fieldsOf(l),
|
|
619
|
+
}, elemType)));
|
|
620
|
+
};
|
|
621
|
+
const withStart = ($3, start) => {
|
|
622
|
+
if (names.length === 1) {
|
|
623
|
+
emit($3, [start]);
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
const to = names[1];
|
|
627
|
+
if (!optional(to)) {
|
|
628
|
+
emit($3, [start, instantOf(fields[to])]);
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
const end = $3.let(fields[to].match({
|
|
632
|
+
some: (_$4, d) => East.value(variant("time", d), PlanInstantType),
|
|
633
|
+
none: () => start,
|
|
634
|
+
}), PlanInstantType);
|
|
635
|
+
emit($3, [start, end]);
|
|
636
|
+
};
|
|
637
|
+
const from = names[0];
|
|
638
|
+
if (!optional(from)) {
|
|
639
|
+
withStart($2, $2.let(instantOf(fields[from]), PlanInstantType));
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
$2.match(fields[from], {
|
|
643
|
+
some: ($3, d) => withStart($3, $3.let(East.value(variant("time", d), PlanInstantType), PlanInstantType)),
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
return result;
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
/** A collection field of the entry, for one row: the field read off its node. */
|
|
651
|
+
function collectionOn(node, field) {
|
|
652
|
+
return node[field];
|
|
653
|
+
}
|
|
654
|
+
/** The record of a read a series makes. */
|
|
655
|
+
function readRecord(rowType, read, via, where) {
|
|
656
|
+
return { field: read.field, read, key: collectionOfRead(rowType, read, where).key, via };
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* An element field of a series config, resolved for its entry type (#1436): a
|
|
660
|
+
* function of the row as before, or a read — of items for the things people
|
|
661
|
+
* drag (runs, decisions, tiles, chips, marks), of values for ports and
|
|
662
|
+
* markers.
|
|
663
|
+
*
|
|
664
|
+
* @param rowType - The entry type
|
|
665
|
+
* @param input - The field as given
|
|
666
|
+
* @param kind - What each element is
|
|
667
|
+
* @param where - The series, for messages
|
|
668
|
+
* @param via - The field's name
|
|
669
|
+
* @returns The field, or `undefined` when it is not given
|
|
670
|
+
* @throws {Error} When a read of the other sort, or a consumer, is given
|
|
671
|
+
*/
|
|
672
|
+
function elementField(rowType, input, kind, where, via) {
|
|
673
|
+
if (input === undefined)
|
|
674
|
+
return undefined;
|
|
675
|
+
if (typeof input === "function") {
|
|
676
|
+
const accessor = input;
|
|
677
|
+
return { at: (node, key) => accessor(node, key), reads: [] };
|
|
678
|
+
}
|
|
679
|
+
const read = planReadOf(input);
|
|
680
|
+
if (read === undefined) {
|
|
681
|
+
throw new Error(`${where}: ${via} is a function of the row, or a read of its collection — ${PLAN_LOOKS[kind].key !== undefined ? "Plan.items(field, times, draw)" : "Plan.values(field, draw)"}`);
|
|
682
|
+
}
|
|
683
|
+
const keyed = PLAN_LOOKS[kind].key !== undefined;
|
|
684
|
+
if (keyed && read.kind !== "items") {
|
|
685
|
+
throw new Error(`${where}: its ${via} are things people drag, keyed by an id — read them with Plan.items(field, ${PLAN_LOOKS[kind].instants.length === 2 ? "{ from, to }" : "{ at }"}, draw)`);
|
|
686
|
+
}
|
|
687
|
+
if (!keyed && read.kind !== "values") {
|
|
688
|
+
throw new Error(`${where}: its ${via} have no id of their own, so each is keyed by its instant — read them with Plan.values(field, draw)`);
|
|
689
|
+
}
|
|
690
|
+
const built = buildRead(rowType, read, kind, where);
|
|
691
|
+
return { at: (node, _key, value) => built(collectionOn(node, read.field), value), reads: [readRecord(rowType, read, via, where)] };
|
|
692
|
+
}
|
|
693
|
+
/** What each consumer is, where a refusal names what a field takes. */
|
|
694
|
+
const CONSUMER_HINTS = {
|
|
695
|
+
heat: "Plan.heatCells, Plan.weightCells or Plan.segmentCells over Plan.values(field, draw)",
|
|
696
|
+
tableCells: "Plan.tableCells(Plan.values(field, draw))",
|
|
697
|
+
tableSeries: "Plan.tableSeries({ cells: Plan.tableCells(Plan.values(field, draw)) })",
|
|
698
|
+
layer: "Plan.line, Plan.area, Plan.column, Plan.scatter or Plan.band over Plan.values(field, draw)",
|
|
699
|
+
};
|
|
700
|
+
/**
|
|
701
|
+
* A consumer of a values read, resolved for the entry type (#1436): the row's
|
|
702
|
+
* values completed into its cells, and what the consumer makes of them.
|
|
703
|
+
*
|
|
704
|
+
* @param rowType - The entry type
|
|
705
|
+
* @param use - The consumer
|
|
706
|
+
* @param makes - What the field takes
|
|
707
|
+
* @param where - The series, for messages
|
|
708
|
+
* @param via - The field's name
|
|
709
|
+
* @returns The field
|
|
710
|
+
*/
|
|
711
|
+
function useField(rowType, use, makes, where, via) {
|
|
712
|
+
if (use.makes !== makes)
|
|
713
|
+
throw new Error(`${where}: ${via} takes ${CONSUMER_HINTS[makes]}`);
|
|
714
|
+
const built = buildRead(rowType, use.read, use.cell, where);
|
|
715
|
+
// The consumer's fold and flag beside the read (#1435): what a parent subtotals its values by.
|
|
716
|
+
const read = { ...readRecord(rowType, use.read, via, where), ...(use.fold !== undefined ? { fold: use.fold } : {}), flagged: use.rollup };
|
|
717
|
+
return {
|
|
718
|
+
at: (node, _key, value) => use.wrap(built(collectionOn(node, use.read.field), value)),
|
|
719
|
+
reads: [read],
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* A field whose value is one consumer's (cells, a group's summary) resolved
|
|
724
|
+
* for the entry type (#1436): a function of the row as before, or a consumer
|
|
725
|
+
* of a values read.
|
|
726
|
+
*
|
|
727
|
+
* @param rowType - The entry type
|
|
728
|
+
* @param input - The field as given
|
|
729
|
+
* @param makes - What it takes
|
|
730
|
+
* @param where - The series, for messages
|
|
731
|
+
* @param via - The field's name
|
|
732
|
+
* @returns The field, or `undefined` when it is not given
|
|
733
|
+
*/
|
|
734
|
+
function consumerField(rowType, input, makes, where, via) {
|
|
735
|
+
if (input === undefined)
|
|
736
|
+
return undefined;
|
|
737
|
+
if (typeof input === "function") {
|
|
738
|
+
const accessor = input;
|
|
739
|
+
return { at: (node, key) => accessor(node, key), reads: [] };
|
|
740
|
+
}
|
|
741
|
+
const use = planUseOf(input);
|
|
742
|
+
if (use !== undefined)
|
|
743
|
+
return useField(rowType, use, makes, where, via);
|
|
744
|
+
const read = planReadOf(input);
|
|
745
|
+
throw new Error(read !== undefined
|
|
746
|
+
? `${where}: ${via} takes ${CONSUMER_HINTS[makes]} — give "${read.field}" to it, as ${via}: ${CONSUMER_HINTS[makes].split(" over ")[0].split(",")[0]}(Plan.values("${read.field}", draw))`
|
|
747
|
+
: `${where}: ${via} is a function of the row, or ${CONSUMER_HINTS[makes]}`);
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* A field whose value is a list (a table's positions, a chart's layers)
|
|
751
|
+
* resolved for the entry type (#1436): a function of the row as before, or a
|
|
752
|
+
* TS array whose consumers are built per row and whose other members pass as
|
|
753
|
+
* they are.
|
|
754
|
+
*
|
|
755
|
+
* @param rowType - The entry type
|
|
756
|
+
* @param input - The field as given
|
|
757
|
+
* @param makes - What its consumers make
|
|
758
|
+
* @param where - The series, for messages
|
|
759
|
+
* @param via - The field's name
|
|
760
|
+
* @returns The field, its value a TS array per row (each consumer's value in its place), or `undefined` when not given
|
|
761
|
+
*/
|
|
762
|
+
function listField(rowType, input, makes, where, via) {
|
|
763
|
+
if (input === undefined)
|
|
764
|
+
return undefined;
|
|
765
|
+
if (typeof input === "function") {
|
|
766
|
+
const accessor = input;
|
|
767
|
+
return { at: (node, key) => accessor(node, key), reads: [] };
|
|
768
|
+
}
|
|
769
|
+
if (!Array.isArray(input))
|
|
770
|
+
throw new Error(`${where}: ${via} is a function of the row, or a list of ${CONSUMER_HINTS[makes]}`);
|
|
771
|
+
const members = input.map((member, i) => {
|
|
772
|
+
const use = planUseOf(member);
|
|
773
|
+
if (use !== undefined)
|
|
774
|
+
return useField(rowType, use, makes, where, `${via}[${i}]`);
|
|
775
|
+
const read = planReadOf(member);
|
|
776
|
+
if (read !== undefined)
|
|
777
|
+
throw new Error(`${where}: ${via}[${i}] takes ${CONSUMER_HINTS[makes]}, not the read "${read.field}" alone`);
|
|
778
|
+
return { at: () => member, reads: [] };
|
|
779
|
+
});
|
|
780
|
+
return {
|
|
781
|
+
at: (node, key, value) => members.map((m) => m.at(node, key, value)),
|
|
782
|
+
reads: members.flatMap((m) => m.reads),
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* A table's positions whose values take typed numbers (#1436): its `cells`
|
|
787
|
+
* when the series declares `edit: true`, and each `Plan.tableSeries` position
|
|
788
|
+
* declaring its own — each drawing every value as it is stored.
|
|
789
|
+
*
|
|
790
|
+
* @param rowType - The entry type
|
|
791
|
+
* @param cfg - The table's `cells`, `series` and `edit`, as given
|
|
792
|
+
* @param where - The series, for messages
|
|
793
|
+
* @returns The typed positions, in order
|
|
794
|
+
* @throws {Error} In the refusals' words: `edit` beside cells given as a function, or over a draw giving another number than each value
|
|
795
|
+
*/
|
|
796
|
+
function tableEditsOf(rowType, cfg, where) {
|
|
797
|
+
const out = [];
|
|
798
|
+
if (cfg.edit !== undefined) {
|
|
799
|
+
if (cfg.edit !== true)
|
|
800
|
+
throw new Error(`${where}: edit is true — its cells' values take typed numbers — or left out`);
|
|
801
|
+
if (cfg.series !== undefined) {
|
|
802
|
+
throw new Error(`${where}: edit is its cells' — with positions, each declares its own: Plan.tableSeries({ cells, edit: true })`);
|
|
803
|
+
}
|
|
804
|
+
const use = planUseOf(cfg.cells);
|
|
805
|
+
if (use === undefined) {
|
|
806
|
+
throw new Error(`${where}: edit writes the values its cells read — give cells as Plan.tableCells(Plan.values(field, draw))`);
|
|
807
|
+
}
|
|
808
|
+
out.push({ position: 0, read: use.read });
|
|
809
|
+
}
|
|
810
|
+
if (Array.isArray(cfg.series)) {
|
|
811
|
+
cfg.series.forEach((member, position) => {
|
|
812
|
+
const use = planUseOf(member);
|
|
813
|
+
if (use?.edit === true)
|
|
814
|
+
out.push({ position, read: use.read });
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
for (const typed of out)
|
|
818
|
+
refuseDrawnOtherwise(rowType, typed.read, where);
|
|
819
|
+
return out;
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Whether a values read's cells draw each value as it is stored (#1436,
|
|
823
|
+
* #1435): a `Float`'s `some(v)` (or `v`), an `Option` of a `Float`'s `v`, an
|
|
824
|
+
* `Integer`'s `some(v.toFloat())` (or `v.toFloat()`) — what a typed number is
|
|
825
|
+
* written as, and what e3 keeps a parent's subtotals of. Read off the draw's
|
|
826
|
+
* expression, as an accessor's field is (`childRefOf`).
|
|
827
|
+
*
|
|
828
|
+
* @param rowType - The entry type
|
|
829
|
+
* @param read - The values read
|
|
830
|
+
* @param where - The series, for messages
|
|
831
|
+
* @returns Whether each value draws as it is stored
|
|
832
|
+
* @internal
|
|
833
|
+
*/
|
|
834
|
+
export function drawsAsStored(rowType, read, where) {
|
|
835
|
+
const shape = collectionOfRead(rowType, read, where);
|
|
836
|
+
const kind = isTypeEqual(shape.item, FloatType) ? "float"
|
|
837
|
+
: isTypeEqual(shape.item, OptionType(FloatType)) ? "option"
|
|
838
|
+
: isTypeEqual(shape.item, IntegerType) ? "integer" : undefined;
|
|
839
|
+
let asStored = false;
|
|
840
|
+
if (kind !== undefined) {
|
|
841
|
+
const recursive = rowType.type === "Recursive";
|
|
842
|
+
East.function([shape.item, shape.key, rowType], NullType, ($, value, at, row) => {
|
|
843
|
+
const node = recursive ? $.let(row.unwrap()) : row;
|
|
844
|
+
const given = read.draw(value, at, node);
|
|
845
|
+
const param = Expr.ast(value);
|
|
846
|
+
const astOf = (x) => (x instanceof Expr ? Expr.ast(x) : undefined);
|
|
847
|
+
const isValue = (x) => astOf(x) === param;
|
|
848
|
+
const isWidened = (x) => {
|
|
849
|
+
const ast = astOf(x);
|
|
850
|
+
return ast !== undefined && ast.ast_type === "Builtin" && ast.builtin === "IntegerToFloat" && ast.arguments?.[0] === param;
|
|
851
|
+
};
|
|
852
|
+
const drawn = given === null || typeof given !== "object" ? undefined : given.value;
|
|
853
|
+
const wrapped = typeof drawn === "object" && drawn !== null && !(drawn instanceof Expr) && drawn.type === "some"
|
|
854
|
+
? drawn.value : undefined;
|
|
855
|
+
asStored = kind === "option" ? isValue(drawn)
|
|
856
|
+
: kind === "float" ? isValue(drawn) || isValue(wrapped)
|
|
857
|
+
: isWidened(drawn) || isWidened(wrapped);
|
|
858
|
+
return null;
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
return asStored;
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Refuse a typed position whose cells draw another number than each value
|
|
865
|
+
* (#1436): a typed number is stored as the value, so each value must draw as
|
|
866
|
+
* it is ({@link drawsAsStored}).
|
|
867
|
+
*
|
|
868
|
+
* @param rowType - The entry type
|
|
869
|
+
* @param read - The position's values read
|
|
870
|
+
* @param where - The series, for the message
|
|
871
|
+
* @throws {Error} In the refusal's words
|
|
872
|
+
*/
|
|
873
|
+
function refuseDrawnOtherwise(rowType, read, where) {
|
|
874
|
+
if (!drawsAsStored(rowType, read, where)) {
|
|
875
|
+
throw new Error(`${where}: edit writes a typed number as its readings, and its cells draw another number than each reading — ` +
|
|
876
|
+
"draw value: some(v), and show it another way through format");
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* A tag given as a literal — its name, or a variant value's case — as the
|
|
881
|
+
* build reads it (#1435); `undefined` for an East expression, known only as
|
|
882
|
+
* the Plan is evaluated.
|
|
883
|
+
*
|
|
884
|
+
* @param given - The tag, as given
|
|
885
|
+
* @param fallback - Its default, where it is not given
|
|
886
|
+
* @returns Its name, or `undefined`
|
|
887
|
+
*/
|
|
888
|
+
function tagOf(given, fallback) {
|
|
889
|
+
if (given === undefined)
|
|
890
|
+
return fallback;
|
|
891
|
+
if (typeof given === "string")
|
|
892
|
+
return given;
|
|
893
|
+
return isVariant(given) ? given.type : undefined;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* A series config's functions of the row (#1435), each by the field it is
|
|
897
|
+
* given as — its accessors, its element fields and its consumers given as
|
|
898
|
+
* functions, and a list's members that are — what a Plan walks for a
|
|
899
|
+
* collection read in a function.
|
|
900
|
+
*
|
|
901
|
+
* @param cfg - The config, as given
|
|
902
|
+
* @returns Its functions of the row
|
|
903
|
+
*/
|
|
904
|
+
function accessorsOf(cfg) {
|
|
905
|
+
const out = [];
|
|
906
|
+
for (const [via, value] of Object.entries(cfg)) {
|
|
907
|
+
if (typeof value === "function")
|
|
908
|
+
out.push({ via, fn: value });
|
|
909
|
+
else if (Array.isArray(value)) {
|
|
910
|
+
value.forEach((member, i) => {
|
|
911
|
+
if (typeof member === "function")
|
|
912
|
+
out.push({ via: `${via}[${i}]`, fn: member });
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
return out;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Refuse a tree's `children` field that is not a Dict of the row's own type,
|
|
920
|
+
* keyed by an id (#1436).
|
|
921
|
+
*
|
|
922
|
+
* @param rowType - The entry type
|
|
923
|
+
* @param field - The field `children` names
|
|
924
|
+
* @param where - The series, for the message
|
|
925
|
+
*/
|
|
926
|
+
function checkTree(rowType, field, where) {
|
|
927
|
+
const t = entryFieldsOf(rowType)?.[field];
|
|
928
|
+
if (t === undefined) {
|
|
929
|
+
throw new Error(`${where}: children names "${field}", which is no field of its rows — name the Dict field holding more of its ` +
|
|
930
|
+
"rows, or step down to rows of another type with Plan.children(field, [series…])");
|
|
931
|
+
}
|
|
932
|
+
if (t.type !== "Dict") {
|
|
933
|
+
throw new Error(`${where}: children names "${field}", ${anOf(t)} — a tree's children are a Dict of the row's own type, keyed by an id`);
|
|
934
|
+
}
|
|
935
|
+
if (!isTypeEqual(t.value, rowType)) {
|
|
936
|
+
throw new Error(`${where}: children "${field}" holds ${shapeName(t.value)}, not ${shapeName(rowType)} — step down to it with Plan.children("${field}", [series…])`);
|
|
937
|
+
}
|
|
938
|
+
if (!isTypeEqual(t.key, StringType)) {
|
|
939
|
+
throw new Error(`${where}: children "${field}" is keyed by ${t.key.type} — child rows are keyed by an id, a String`);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Refuse a step-down's field that is not a Dict of child rows keyed by an id
|
|
944
|
+
* (#1436).
|
|
945
|
+
*
|
|
946
|
+
* @param rowType - The parent entry type
|
|
947
|
+
* @param field - The field `Plan.children` names
|
|
948
|
+
* @param where - The series, for the message
|
|
949
|
+
*/
|
|
950
|
+
function checkStepField(rowType, field, where) {
|
|
951
|
+
const t = entryFieldsOf(rowType)?.[field];
|
|
952
|
+
if (t === undefined) {
|
|
953
|
+
throw new Error(`${where}: Plan.children("${field}", …) steps down to "${field}", which is no field of its rows — name the Dict field holding the child rows`);
|
|
954
|
+
}
|
|
955
|
+
if (t.type !== "Dict") {
|
|
956
|
+
throw new Error(`Plan.children: "${field}" is ${anOf(t)} — child rows are a Dict, keyed by an id`);
|
|
957
|
+
}
|
|
958
|
+
if (!isTypeEqual(t.key, StringType)) {
|
|
959
|
+
throw new Error(`Plan.children: "${field}" is keyed by ${t.key.type} — child rows are keyed by an id, a String`);
|
|
960
|
+
}
|
|
961
|
+
const child = t.value.type;
|
|
962
|
+
if (child !== "Struct" && child !== "Recursive") {
|
|
963
|
+
throw new Error(`Plan.children: "${field}" holds ${anOf(t.value)}, not rows — child rows are structs`);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* A series' `edit`, checked against the element field it writes through
|
|
968
|
+
* (#1436): `true` or `{ create }`, beside a read of items.
|
|
969
|
+
*
|
|
970
|
+
* @param edit - The declaration as given
|
|
971
|
+
* @param elements - The element field: `runs`, `events`, `chips` or `marks`
|
|
972
|
+
* @param times - The times those elements take
|
|
973
|
+
* @param input - The element field as given
|
|
974
|
+
* @param where - The series, for the messages
|
|
975
|
+
* @returns The recipe, or `undefined` when no `edit` is declared
|
|
976
|
+
* @throws {Error} In the refusals' words
|
|
977
|
+
*/
|
|
978
|
+
function editRecipeOf(edit, elements, times, input, where) {
|
|
979
|
+
if (edit === undefined)
|
|
980
|
+
return undefined;
|
|
981
|
+
const create = typeof edit === "object" && edit !== null ? edit.create : undefined;
|
|
982
|
+
if (edit !== true && (typeof create !== "function" || Object.keys(edit).some((k) => k !== "create"))) {
|
|
983
|
+
throw new Error(`${where}: edit names nothing — its ${elements}' read names the collection and its times: give edit: true, or ` +
|
|
984
|
+
"edit: { create } to take dropped cards too");
|
|
985
|
+
}
|
|
986
|
+
const read = planReadOf(input);
|
|
987
|
+
if (read === undefined) {
|
|
988
|
+
throw new Error(`${where}: edit moves the items its ${elements} name — give ${elements} as Plan.items(field, ${times}, draw)`);
|
|
989
|
+
}
|
|
990
|
+
if (read.kind !== "items") {
|
|
991
|
+
throw new Error(`${where}: edit moves the items its ${elements} name, and they read values — what people move is keyed by an id: ` +
|
|
992
|
+
`give ${elements} as Plan.items(field, ${times}, draw)`);
|
|
993
|
+
}
|
|
994
|
+
return { edit: edit, elements, times, input };
|
|
995
|
+
}
|
|
393
996
|
/**
|
|
394
997
|
* The build spec of a data series (span / buckets / chart / heat / table /
|
|
395
998
|
* cards / events / group).
|
|
@@ -399,21 +1002,12 @@ function instantInto(fieldType) {
|
|
|
399
1002
|
* row facts through the one envelope) and the membership, collapse and
|
|
400
1003
|
* children functions, each reified once and CALLED in the block's loop. The
|
|
401
1004
|
* block walks the collection in order; each matched entry's row is followed by
|
|
402
|
-
* its children's rows — a
|
|
1005
|
+
* its children's rows — a tree (`children: field`) walks the entry's subtree
|
|
403
1006
|
* with an explicit pre-order stack (its depth is data), a step-down calls its
|
|
404
1007
|
* child series' blocks on the child collection.
|
|
405
1008
|
*/
|
|
406
1009
|
function dataSpec(rowType, cfg, recipe) {
|
|
407
1010
|
const where = `Plan.series.${recipe.arm} "${cfg.key}"`;
|
|
408
|
-
const children = cfg.children;
|
|
409
|
-
const steps = children === undefined || typeof children === "function"
|
|
410
|
-
? [] : (Array.isArray(children) ? children : [children]);
|
|
411
|
-
for (const step of steps) {
|
|
412
|
-
if (!isStepDown(step)) {
|
|
413
|
-
throw new Error(`${where}: \`children\` is an accessor for more of this series, or \`Plan.children(of, [series…])\` step-downs`);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
const nested = steps.flatMap((s) => s.series.map((x) => nestedSpec(x, `${where} › children`)));
|
|
417
1011
|
// A recursive entry reaches the accessors as its NODE (`PlanEntryExpr`),
|
|
418
1012
|
// so they read its fields directly at every depth.
|
|
419
1013
|
const recursive = rowType.type === "Recursive";
|
|
@@ -422,6 +1016,33 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
422
1016
|
: value;
|
|
423
1017
|
/** An accessor over entries, applied to an entry value (its node, when recursive). */
|
|
424
1018
|
const onEntry = (accessor) => (v, k) => accessor(nodeOf(v), k);
|
|
1019
|
+
const children = cfg.children;
|
|
1020
|
+
// A tree (#1436): a field of the entry holding more of its entries — or, the
|
|
1021
|
+
// event kinds' own (#1194), an accessor computing them.
|
|
1022
|
+
const treeField = typeof children === "string" ? children : undefined;
|
|
1023
|
+
const tree = treeField !== undefined
|
|
1024
|
+
? (v) => collectionOn(v, treeField)
|
|
1025
|
+
: typeof children === "function" ? children : undefined;
|
|
1026
|
+
if (treeField !== undefined)
|
|
1027
|
+
checkTree(rowType, treeField, where);
|
|
1028
|
+
const steps = children === undefined || tree !== undefined
|
|
1029
|
+
? [] : (Array.isArray(children) ? children : [children]);
|
|
1030
|
+
for (const step of steps) {
|
|
1031
|
+
if (!isStepDown(step)) {
|
|
1032
|
+
throw new Error(`${where}: \`children\` is a field of the row holding more of its rows, or Plan.children(field, [series…]) step-downs`);
|
|
1033
|
+
}
|
|
1034
|
+
if (step.field !== undefined)
|
|
1035
|
+
checkStepField(rowType, step.field, where);
|
|
1036
|
+
}
|
|
1037
|
+
/** A step-down's child collection, from the entry (its node). */
|
|
1038
|
+
const stepOf = (step) => (step.field !== undefined
|
|
1039
|
+
? (v) => collectionOn(v, step.field)
|
|
1040
|
+
: step.of);
|
|
1041
|
+
const nested = steps.flatMap((s) => s.series.map((x) => nestedSpec(x, `${where} › children`)));
|
|
1042
|
+
// How many chart rows each entry makes (#1398): a chart series' own row, and below it a tree's walk of more of
|
|
1043
|
+
// this series' rows, or a step-down's series' over the child collection.
|
|
1044
|
+
const ownCharts = recipe.arm === "chart" ? 1 : 0;
|
|
1045
|
+
const charts = entryCharts(ownCharts, children === undefined ? 0 : tree !== undefined ? ownCharts : chartsOf(nested), cfg.match !== undefined);
|
|
425
1046
|
// The removed verdict, named (#1260) — a plain JS caller would otherwise
|
|
426
1047
|
// lose it silently.
|
|
427
1048
|
for (const removed of ["review", "approval"]) {
|
|
@@ -429,30 +1050,25 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
429
1050
|
throw new Error(`${where}: \`${removed}\` is removed (#1260) — a Plan approves and rejects nothing: its changes are drafts of the root's \`editing\` session`);
|
|
430
1051
|
}
|
|
431
1052
|
}
|
|
432
|
-
// What a gesture writes (#880, #825) —
|
|
433
|
-
//
|
|
434
|
-
//
|
|
435
|
-
// fails the build.
|
|
1053
|
+
// What a gesture writes (#880, #825, #1436) — through the collection its
|
|
1054
|
+
// elements' read names: a dropped card's item under its minted id, a moved
|
|
1055
|
+
// element's item re-timed under its id, or taken to another row.
|
|
436
1056
|
const edit = recipe.edit;
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
itemType = t.value;
|
|
450
|
-
move = moveFieldsOf(edit, itemType, recipe.arm, where);
|
|
451
|
-
}
|
|
452
|
-
const edits = edit !== undefined
|
|
1057
|
+
const editRead = edit !== undefined ? planReadOf(edit.input) : undefined;
|
|
1058
|
+
const editShape = editRead !== undefined ? collectionOfRead(rowType, editRead, where) : undefined;
|
|
1059
|
+
const itemType = editShape?.item;
|
|
1060
|
+
const move = editRead !== undefined ? moveFieldsOf(editRead, editShape.item) : undefined;
|
|
1061
|
+
const create = edit !== undefined && edit.edit !== true ? edit.edit.create : undefined;
|
|
1062
|
+
// What a typed number writes (#1436): each typed position's collection, keyed by the bucket's start.
|
|
1063
|
+
const typedWrites = (recipe.values ?? []).map((typed) => {
|
|
1064
|
+
const shape = collectionOfRead(rowType, typed.read, where);
|
|
1065
|
+
return { position: typed.position, field: typed.read.field, key: shape.key, value: shape.item, keyAs: instantInto(shape.key) };
|
|
1066
|
+
});
|
|
1067
|
+
const edits = move !== undefined || typedWrites.length > 0
|
|
453
1068
|
? {
|
|
454
|
-
drop:
|
|
1069
|
+
drop: create !== undefined,
|
|
455
1070
|
move: move !== undefined ? some(move.edits) : none,
|
|
1071
|
+
values: typedWrites.map((typed) => ({ position: BigInt(typed.position), whole: isTypeEqual(typed.value, IntegerType) })),
|
|
456
1072
|
}
|
|
457
1073
|
: undefined;
|
|
458
1074
|
const rows = new ByType();
|
|
@@ -475,7 +1091,7 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
475
1091
|
...(cfg.value !== undefined ? { value: cfg.value(entry, key) } : {}),
|
|
476
1092
|
...(recipe.swatches !== undefined ? { swatches: recipe.swatches } : {}),
|
|
477
1093
|
}),
|
|
478
|
-
kind: recipe.kind(entry, key, hasChildren),
|
|
1094
|
+
kind: recipe.kind(entry, key, hasChildren, value),
|
|
479
1095
|
collapsed,
|
|
480
1096
|
...(recipe.pinned !== undefined ? { pinned: recipe.pinned(entry, key) } : {}),
|
|
481
1097
|
...(cfg.status !== undefined ? { status: cfg.status(entry, key) } : {}),
|
|
@@ -497,13 +1113,13 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
497
1113
|
? East.value(collapsed, BooleanType)
|
|
498
1114
|
: East.value(collapsed(nodeOf(value), key), BooleanType)));
|
|
499
1115
|
});
|
|
500
|
-
/**
|
|
501
|
-
const childOf = (kt) => building(where, kt, () => reifyAccessor([rowType, kt], onEntry(
|
|
1116
|
+
/** The tree's children, built for entries keyed by `kt` — the child collection's type is its output. */
|
|
1117
|
+
const childOf = (kt) => building(where, kt, () => reifyAccessor([rowType, kt], onEntry(tree)));
|
|
502
1118
|
/** The subtree walk below one entry — every level's entries in pre-order, over the child collection type. */
|
|
503
1119
|
const walkFor = (cc) => walks.get(cc, () => {
|
|
504
1120
|
const at = `${where} › children`;
|
|
505
1121
|
const { entry, key: kc } = shapeOf(cc, at);
|
|
506
|
-
assertEntry(entry, rowType, `${at} (a
|
|
1122
|
+
assertEntry(entry, rowType, `${at} (a tree's children are more of this series' rows — step down to another type with Plan.children)`);
|
|
507
1123
|
const next = childOf(kc);
|
|
508
1124
|
const nextType = Expr.type(next).output;
|
|
509
1125
|
if (!isTypeEqual(nextType, cc)) {
|
|
@@ -559,7 +1175,7 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
559
1175
|
const childrenFor = (kt) => kids.get(kt, () => {
|
|
560
1176
|
if (children === undefined)
|
|
561
1177
|
return undefined;
|
|
562
|
-
if (
|
|
1178
|
+
if (tree !== undefined) {
|
|
563
1179
|
const of = childOf(kt);
|
|
564
1180
|
const cc = Expr.type(of).output;
|
|
565
1181
|
const walk = walkFor(cc);
|
|
@@ -567,7 +1183,7 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
567
1183
|
}
|
|
568
1184
|
const parts = steps.map((step, i) => {
|
|
569
1185
|
const at = `${where} › children[${i}]`;
|
|
570
|
-
const of = building(at, kt, () => reifyAccessor([rowType, kt], onEntry(step
|
|
1186
|
+
const of = building(at, kt, () => reifyAccessor([rowType, kt], onEntry(stepOf(step))));
|
|
571
1187
|
const cc = Expr.type(of).output;
|
|
572
1188
|
const blocks = step.series.map((s) => nestedSpec(s, at).emitter(cc, at));
|
|
573
1189
|
return { of, cc, blocks };
|
|
@@ -583,20 +1199,20 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
583
1199
|
return out;
|
|
584
1200
|
});
|
|
585
1201
|
});
|
|
586
|
-
// ── Writing a gesture back (#880)
|
|
1202
|
+
// ── Writing a gesture back (#880, #1436) ──────────────────────────────
|
|
587
1203
|
// The entry a writer is handed is DETACHED (the series value's `write`
|
|
588
1204
|
// copies it), so a nested entry is written in place in its collection and
|
|
589
|
-
//
|
|
1205
|
+
// an item joins its collection in place, under its id.
|
|
590
1206
|
const owns = new ByType();
|
|
591
1207
|
const writers = new ByType();
|
|
592
1208
|
const entryAccess = (value) => nodeOf(value);
|
|
593
1209
|
/** The item a dropped card becomes, for entries keyed by `kt`. */
|
|
594
|
-
const createFor = (kt,
|
|
1210
|
+
const createFor = (kt, make) => building(where, kt, () => East.function([PlanDropType, rowType, kt], itemType, (_$, drop, value, key) => make(drop, nodeOf(value), key)));
|
|
595
1211
|
/**
|
|
596
|
-
* An item at a move's instants (#825) —
|
|
597
|
-
* from the axis's instants, each on its own arm, every other
|
|
598
|
-
* was; `none` when an instant rides an arm the field cannot
|
|
599
|
-
* instant into a Float field).
|
|
1212
|
+
* An item at a move's instants (#825, #1436) — the instant fields its read
|
|
1213
|
+
* names set from the axis's instants, each on its own arm, every other
|
|
1214
|
+
* field as it was; `none` when an instant rides an arm the field cannot
|
|
1215
|
+
* hold (a time instant into a Float field).
|
|
600
1216
|
*/
|
|
601
1217
|
const placed = move === undefined ? undefined : (() => {
|
|
602
1218
|
const m = move;
|
|
@@ -628,92 +1244,74 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
628
1244
|
});
|
|
629
1245
|
})();
|
|
630
1246
|
/**
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
* This series' own edit on one of its entries — the row at `path` is its
|
|
639
|
-
* own: a dropped card's item into its list, and a moved element's item
|
|
640
|
-
* re-timed where it is, taken out of the list, or put into it (#825).
|
|
1247
|
+
* This series' own edit on one of its entries (#1436) — the row at `path`
|
|
1248
|
+
* is its own: a dropped card's item into the collection its elements'
|
|
1249
|
+
* read names, under the id the Plan minted; a moved element's item, found
|
|
1250
|
+
* by its id (the element's key), re-timed where it is, taken out of the
|
|
1251
|
+
* collection, or put into it under the same id. A collection already
|
|
1252
|
+
* holding the id refuses the item. A number typed into one of its table
|
|
1253
|
+
* positions sets that position's value at the bucket's start.
|
|
641
1254
|
*/
|
|
642
1255
|
const ownFor = (kt) => owns.get(kt, () => {
|
|
643
|
-
|
|
1256
|
+
const moves = editRead !== undefined && placed !== undefined && move !== undefined;
|
|
1257
|
+
if (!moves && typedWrites.length === 0)
|
|
644
1258
|
return undefined;
|
|
645
|
-
const
|
|
1259
|
+
const made = moves && create !== undefined ? createFor(kt, create) : undefined;
|
|
1260
|
+
const field = editRead?.field ?? "";
|
|
1261
|
+
const item = move?.item;
|
|
646
1262
|
return East.function([rowType, kt, PathType, PlanGestureType, PlanCarriedType], OptionType(rowType), ($, value, key, path, gesture, carried) => {
|
|
647
|
-
const make =
|
|
648
|
-
const place =
|
|
1263
|
+
const make = made === undefined ? undefined : $.const(made);
|
|
1264
|
+
const place = moves ? $.const(placed) : undefined;
|
|
649
1265
|
const result = $.let(none, OptionType(rowType));
|
|
650
1266
|
$.match(gesture, {
|
|
651
1267
|
drop: ($2, drop) => {
|
|
652
|
-
if (make === undefined
|
|
1268
|
+
if (make === undefined)
|
|
653
1269
|
return;
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
$3(
|
|
1270
|
+
const coll = $2.let(entryAccess(value)[field]);
|
|
1271
|
+
// The minted id, unless the collection already holds it.
|
|
1272
|
+
$2.if(coll.has(drop.id).not(), ($3) => {
|
|
1273
|
+
$3(coll.insert(drop.id, make(drop, value, key)));
|
|
658
1274
|
$3.assign(result, some(value));
|
|
659
|
-
};
|
|
660
|
-
// With the item's key declared, a card whose item
|
|
661
|
-
// repeats a key in the list is refused (#825).
|
|
662
|
-
if (holds === undefined || move === undefined)
|
|
663
|
-
add($2);
|
|
664
|
-
else
|
|
665
|
-
$2.if(holds(list, item[move.key]).not(), add);
|
|
1275
|
+
});
|
|
666
1276
|
},
|
|
667
1277
|
move: ($2, mv) => {
|
|
668
|
-
if (place === undefined ||
|
|
1278
|
+
if (place === undefined || item === undefined)
|
|
669
1279
|
return;
|
|
670
|
-
const keyField = move.key;
|
|
671
|
-
const itemOf = move.item;
|
|
672
1280
|
const here = $2.let(East.value(variant("entry", { series: cfg.key, path }), PlanRowIdType), PlanRowIdType);
|
|
673
|
-
const
|
|
674
|
-
// The element's item, by its key.
|
|
675
|
-
const at = $2.let(list.firstMap(($3, item, i) => East.equal(item[keyField], mv.key).ifElse(() => East.value(some(i), OptionType(IntegerType)), () => East.value(none, OptionType(IntegerType)))), OptionType(IntegerType));
|
|
1281
|
+
const coll = $2.let(entryAccess(value)[field]);
|
|
676
1282
|
$2.if(East.equal(here, mv.from).and(() => East.equal(here, mv.to)), ($3) => {
|
|
677
|
-
// Along its row, or resized: its
|
|
678
|
-
$3.
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
$
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
});
|
|
687
|
-
},
|
|
1283
|
+
// Along its row, or resized: its times set where it is.
|
|
1284
|
+
$3.if(coll.has(mv.key), ($4) => {
|
|
1285
|
+
const moved = $4.let(place(coll.get(mv.key), mv.start, mv.end), OptionType(item));
|
|
1286
|
+
$4.match(moved, {
|
|
1287
|
+
some: ($5, next) => {
|
|
1288
|
+
$5(coll.update(mv.key, next));
|
|
1289
|
+
$5.assign(result, some(value));
|
|
1290
|
+
},
|
|
1291
|
+
});
|
|
688
1292
|
});
|
|
689
1293
|
}).else(($3) => {
|
|
690
|
-
// Its source: taken out of the
|
|
1294
|
+
// Its source: taken out of the collection, and carried.
|
|
691
1295
|
$3.if(East.equal(here, mv.from), ($4) => {
|
|
692
|
-
$4.
|
|
693
|
-
some
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
const after = $5.let(list.slice(i.add(1n), list.size()));
|
|
697
|
-
$5(list.clear());
|
|
698
|
-
$5(list.append(before));
|
|
699
|
-
$5(list.append(after));
|
|
700
|
-
$5.assign(result, some(value));
|
|
701
|
-
},
|
|
1296
|
+
$4.if(coll.has(mv.key), ($5) => {
|
|
1297
|
+
$5(carried.update(East.value(some(East.Blob.encodeBeast(coll.get(mv.key), "v2")), OptionType(BlobType))));
|
|
1298
|
+
$5(coll.delete(mv.key));
|
|
1299
|
+
$5.assign(result, some(value));
|
|
702
1300
|
});
|
|
703
1301
|
});
|
|
704
|
-
// Its target: the carried item put in, at its new
|
|
705
|
-
//
|
|
706
|
-
//
|
|
1302
|
+
// Its target: the carried item put in under its id, at its new
|
|
1303
|
+
// times — unless the collection already holds the id, when it
|
|
1304
|
+
// is put nowhere and the move lands nowhere.
|
|
707
1305
|
$3.if(East.equal(here, mv.to), ($4) => {
|
|
708
1306
|
const held = $4.let(carried.get(), OptionType(BlobType));
|
|
709
1307
|
$4.match(held, {
|
|
710
1308
|
some: ($5, bytes) => {
|
|
711
|
-
$5.if(
|
|
712
|
-
const
|
|
713
|
-
const moved = $6.let(place(
|
|
1309
|
+
$5.if(coll.has(mv.key).not(), ($6) => {
|
|
1310
|
+
const taken = $6.let(bytes.decodeBeast(item, "v2"), item);
|
|
1311
|
+
const moved = $6.let(place(taken, mv.start, mv.end), OptionType(item));
|
|
714
1312
|
$6.match(moved, {
|
|
715
|
-
some: ($7,
|
|
716
|
-
$7(
|
|
1313
|
+
some: ($7, next) => {
|
|
1314
|
+
$7(coll.insert(mv.key, next));
|
|
717
1315
|
$7(carried.update(East.value(none, OptionType(BlobType))));
|
|
718
1316
|
$7.assign(result, some(value));
|
|
719
1317
|
},
|
|
@@ -724,11 +1322,55 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
724
1322
|
});
|
|
725
1323
|
});
|
|
726
1324
|
},
|
|
1325
|
+
// A number typed into a cell (#1436): its position's value at the bucket's start set, or added
|
|
1326
|
+
// where the collection holds none; cleared, deleted. An Integer collection takes a whole number,
|
|
1327
|
+
// and an instant on an arm its keys cannot hold writes nothing.
|
|
1328
|
+
value: ($2, typed) => {
|
|
1329
|
+
if (typedWrites.length === 0)
|
|
1330
|
+
return;
|
|
1331
|
+
const here = $2.let(East.value(variant("entry", { series: cfg.key, path }), PlanRowIdType), PlanRowIdType);
|
|
1332
|
+
$2.if(East.equal(here, typed.row), ($3) => {
|
|
1333
|
+
for (const write of typedWrites) {
|
|
1334
|
+
$3.if(typed.position.equal(BigInt(write.position)), ($4) => {
|
|
1335
|
+
const keyAs = $4.const(write.keyAs);
|
|
1336
|
+
const at = $4.let(keyAs(typed.at), OptionType(write.key));
|
|
1337
|
+
$4.match(at, {
|
|
1338
|
+
some: ($5, k) => {
|
|
1339
|
+
const coll = $5.let(entryAccess(value)[write.field]);
|
|
1340
|
+
$5.match(typed.value, {
|
|
1341
|
+
some: ($6, n) => {
|
|
1342
|
+
const put = ($7, stored) => {
|
|
1343
|
+
$7(coll.insertOrUpdate(k, stored));
|
|
1344
|
+
$7.assign(result, some(value));
|
|
1345
|
+
};
|
|
1346
|
+
if (isTypeEqual(write.value, IntegerType)) {
|
|
1347
|
+
$6.if(n.remainder(1).equal(0), ($7) => { put($7, n.toInteger()); });
|
|
1348
|
+
}
|
|
1349
|
+
else if (isTypeEqual(write.value, OptionType(FloatType))) {
|
|
1350
|
+
put($6, some(n));
|
|
1351
|
+
}
|
|
1352
|
+
else {
|
|
1353
|
+
put($6, n);
|
|
1354
|
+
}
|
|
1355
|
+
},
|
|
1356
|
+
none: ($6) => {
|
|
1357
|
+
$6.if(coll.has(k), ($7) => {
|
|
1358
|
+
$7(coll.delete(k));
|
|
1359
|
+
$7.assign(result, some(value));
|
|
1360
|
+
});
|
|
1361
|
+
},
|
|
1362
|
+
});
|
|
1363
|
+
},
|
|
1364
|
+
});
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
},
|
|
727
1369
|
});
|
|
728
1370
|
return result;
|
|
729
1371
|
});
|
|
730
1372
|
});
|
|
731
|
-
/** The
|
|
1373
|
+
/** The tree's writer: the rows below an entry are this series' own. */
|
|
732
1374
|
const walkWriterFor = (kt) => {
|
|
733
1375
|
const at = `${where} › children`;
|
|
734
1376
|
const of = childOf(kt);
|
|
@@ -737,10 +1379,10 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
737
1379
|
const own = ownFor(kc);
|
|
738
1380
|
if (own === undefined)
|
|
739
1381
|
return undefined;
|
|
740
|
-
const ref = childRefOf(rowType, kt,
|
|
1382
|
+
const ref = treeField !== undefined ? { kind: "field", field: treeField } : childRefOf(rowType, kt, tree);
|
|
741
1383
|
if (ref === undefined) {
|
|
742
1384
|
throw new Error(`${at}: this series takes gestures, and one on a child row is written back into its entry through ` +
|
|
743
|
-
"`children` — which must read a field of the entry
|
|
1385
|
+
"`children` — which must read a field of the entry, not compute a collection");
|
|
744
1386
|
}
|
|
745
1387
|
const ops = collectionOps(cc);
|
|
746
1388
|
const collOf = (entry) => (ref.kind === "field" ? entryAccess(entry)[ref.field] : nodeOf(entry));
|
|
@@ -785,7 +1427,7 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
785
1427
|
const stepsWriterFor = (kt) => {
|
|
786
1428
|
const parts = steps.flatMap((step, i) => {
|
|
787
1429
|
const at = `${where} › children[${i}]`;
|
|
788
|
-
const accessor = step
|
|
1430
|
+
const accessor = stepOf(step);
|
|
789
1431
|
const of = building(at, kt, () => reifyAccessor([rowType, kt], onEntry(accessor)));
|
|
790
1432
|
const cc = Expr.type(of).output;
|
|
791
1433
|
const writes = step.series
|
|
@@ -793,11 +1435,11 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
793
1435
|
.filter((w) => w !== undefined);
|
|
794
1436
|
if (writes.length === 0)
|
|
795
1437
|
return [];
|
|
796
|
-
const ref = childRefOf(rowType, kt, accessor);
|
|
1438
|
+
const ref = step.field !== undefined ? { kind: "field", field: step.field } : childRefOf(rowType, kt, accessor);
|
|
797
1439
|
if (ref === undefined) {
|
|
798
1440
|
throw new Error(`${at}: a series under this step-down takes gestures, and one on its rows is written back into ` +
|
|
799
|
-
"the entry through
|
|
800
|
-
"
|
|
1441
|
+
"the entry through the step-down — which must read a field of the entry, or be the entry itself, not " +
|
|
1442
|
+
"compute a collection");
|
|
801
1443
|
}
|
|
802
1444
|
const { entry: childType, key: kc } = shapeOf(cc, at);
|
|
803
1445
|
return [{ ref, cc, kc, childType, writes }];
|
|
@@ -836,7 +1478,7 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
836
1478
|
const writerFor = (kt) => writers.get(kt, () => {
|
|
837
1479
|
const own = ownFor(kt);
|
|
838
1480
|
const below = children === undefined ? undefined
|
|
839
|
-
:
|
|
1481
|
+
: tree !== undefined ? walkWriterFor(kt) : stepsWriterFor(kt);
|
|
840
1482
|
if (own === undefined && below === undefined)
|
|
841
1483
|
return undefined;
|
|
842
1484
|
return East.function([rowType, kt, PathType, IntegerType, StringType, PlanGestureType, PlanCarriedType], OptionType(rowType), ($, value, key, path, depth, series, gesture, carried) => {
|
|
@@ -861,6 +1503,22 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
861
1503
|
arm: recipe.arm,
|
|
862
1504
|
nested,
|
|
863
1505
|
nests: children !== undefined,
|
|
1506
|
+
charts,
|
|
1507
|
+
reads: recipe.reads ?? [],
|
|
1508
|
+
nest: {
|
|
1509
|
+
rowType,
|
|
1510
|
+
keyType: cfg.keyType ?? StringType,
|
|
1511
|
+
accessors: accessorsOf(cfg),
|
|
1512
|
+
tree: treeField,
|
|
1513
|
+
steps: steps.map((step, i) => ({
|
|
1514
|
+
field: step.field, of: step.of,
|
|
1515
|
+
series: step.series.map((x) => nestedSpec(x, `${where} › children[${i}]`)),
|
|
1516
|
+
})),
|
|
1517
|
+
members: [],
|
|
1518
|
+
aggregate: recipe.aggregate,
|
|
1519
|
+
subtotalsOwn: recipe.subtotalsOwn === true,
|
|
1520
|
+
rollup: recipe.rollup,
|
|
1521
|
+
},
|
|
864
1522
|
emitter(collection, at) {
|
|
865
1523
|
return emitters.get(collection, () => {
|
|
866
1524
|
const { entry, key: kt } = shapeOf(collection, at);
|
|
@@ -906,7 +1564,7 @@ function dataSpec(rowType, cfg, recipe) {
|
|
|
906
1564
|
},
|
|
907
1565
|
// One block of the entries' rows — what a paged canvas pages (#823).
|
|
908
1566
|
blocks(collection, at) {
|
|
909
|
-
return blockLists.get(collection, () => oneBlock(collection, spec.emitter(collection, at), false));
|
|
1567
|
+
return blockLists.get(collection, () => oneBlock(collection, spec.emitter(collection, at), false, charts));
|
|
910
1568
|
},
|
|
911
1569
|
entryParts(entry, kt, at) {
|
|
912
1570
|
assertEntry(entry, rowType, at);
|
|
@@ -953,10 +1611,13 @@ function viewsSpec(rowType, cfg, members) {
|
|
|
953
1611
|
const emitters = new ByType();
|
|
954
1612
|
const blockLists = new ByType();
|
|
955
1613
|
const writerLists = new ByType();
|
|
956
|
-
// ── A
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1614
|
+
// ── A tree: more of the views' own entries (#1219, #1436) — a field of the
|
|
1615
|
+
// entry, or the event kinds' accessor computing them (#1194) ──
|
|
1616
|
+
const children = cfg.children;
|
|
1617
|
+
const treeField = typeof children === "string" ? children : undefined;
|
|
1618
|
+
const bare = treeField !== undefined
|
|
1619
|
+
? (v) => collectionOn(v, treeField)
|
|
1620
|
+
: typeof children === "function" ? children : undefined;
|
|
960
1621
|
const recursive = rowType.type === "Recursive";
|
|
961
1622
|
const nodeOf = (value) => recursive
|
|
962
1623
|
? value.unwrap()
|
|
@@ -975,7 +1636,7 @@ function viewsSpec(rowType, cfg, members) {
|
|
|
975
1636
|
const walkFor = (cc) => walks.get(cc, () => {
|
|
976
1637
|
const at = `${where} › children`;
|
|
977
1638
|
const { entry, key: kc } = shapeOf(cc, at);
|
|
978
|
-
assertEntry(entry, rowType, `${at} (a
|
|
1639
|
+
assertEntry(entry, rowType, `${at} (a tree's children are more of this series' rows — step down to another type with Plan.children)`);
|
|
979
1640
|
const next = childOf(kc);
|
|
980
1641
|
const nextType = Expr.type(next).output;
|
|
981
1642
|
if (!isTypeEqual(nextType, cc)) {
|
|
@@ -1083,10 +1744,10 @@ function viewsSpec(rowType, cfg, members) {
|
|
|
1083
1744
|
});
|
|
1084
1745
|
if (owns.length === 0)
|
|
1085
1746
|
return undefined;
|
|
1086
|
-
const ref = childRefOf(rowType, kt, bare);
|
|
1747
|
+
const ref = treeField !== undefined ? { kind: "field", field: treeField } : childRefOf(rowType, kt, bare);
|
|
1087
1748
|
if (ref === undefined) {
|
|
1088
1749
|
throw new Error(`${at}: a member takes gestures, and one on a child row is written back into its entry through ` +
|
|
1089
|
-
"`children` — which must read a field of the entry
|
|
1750
|
+
"`children` — which must read a field of the entry, not compute a collection");
|
|
1090
1751
|
}
|
|
1091
1752
|
const ops = collectionOps(cc);
|
|
1092
1753
|
const collOf = (value) => (ref.kind === "field" ? entryAccess(value)[ref.field] : nodeOf(value));
|
|
@@ -1129,12 +1790,21 @@ function viewsSpec(rowType, cfg, members) {
|
|
|
1129
1790
|
return result;
|
|
1130
1791
|
});
|
|
1131
1792
|
});
|
|
1793
|
+
// How many chart rows each entry makes (#1398): a row a member — a chart member's own `match` deciding by entry
|
|
1794
|
+
// whether its row shows — and below them a tree's walk of more of the views' entries, each its members'
|
|
1795
|
+
// rows, or a step-down's series' over the child collection.
|
|
1796
|
+
const memberCharts = chartsOf(memberSpecs);
|
|
1797
|
+
const charts = entryCharts(memberCharts, cfg.children === undefined ? 0 : bare !== undefined ? memberCharts : chartsOf(host.nested), cfg.match !== undefined);
|
|
1132
1798
|
const spec = {
|
|
1133
1799
|
key: cfg.key,
|
|
1134
1800
|
title: cfg.title,
|
|
1135
1801
|
arm: "views",
|
|
1136
1802
|
nested: [...memberSpecs, ...host.nested],
|
|
1137
1803
|
nests: cfg.children !== undefined,
|
|
1804
|
+
charts,
|
|
1805
|
+
reads: [],
|
|
1806
|
+
// Its members read its own entries; its children are the host envelope's (#1435).
|
|
1807
|
+
nest: { ...host.nest, members: memberSpecs },
|
|
1138
1808
|
emitter(collection, at) {
|
|
1139
1809
|
return emitters.get(collection, () => {
|
|
1140
1810
|
const { entry, key: kt } = shapeOf(collection, at);
|
|
@@ -1212,7 +1882,7 @@ function viewsSpec(rowType, cfg, members) {
|
|
|
1212
1882
|
},
|
|
1213
1883
|
// One block of the entries' view rows — what a paged canvas pages (#823).
|
|
1214
1884
|
blocks(collection, at) {
|
|
1215
|
-
return blockLists.get(collection, () => oneBlock(collection, spec.emitter(collection, at), false));
|
|
1885
|
+
return blockLists.get(collection, () => oneBlock(collection, spec.emitter(collection, at), false, charts));
|
|
1216
1886
|
},
|
|
1217
1887
|
// An entry's view rows are its members' own (each at the entry's path,
|
|
1218
1888
|
// under its member's key), and the rows below them the views' (#880).
|
|
@@ -1275,6 +1945,14 @@ function sectionSpec(cfg, members) {
|
|
|
1275
1945
|
arm: "section",
|
|
1276
1946
|
nested: memberSpecs,
|
|
1277
1947
|
nests: false,
|
|
1948
|
+
// Each entry makes its members' rows; the header is no entry's (#1398).
|
|
1949
|
+
charts: chartsOf(memberSpecs),
|
|
1950
|
+
reads: [],
|
|
1951
|
+
// Its members read the section's entries; it reads nothing of its own (#1435).
|
|
1952
|
+
nest: {
|
|
1953
|
+
rowType: undefined, keyType: StringType, accessors: [], tree: undefined, steps: [], members: memberSpecs,
|
|
1954
|
+
aggregate: undefined, subtotalsOwn: false, rollup: undefined,
|
|
1955
|
+
},
|
|
1278
1956
|
emitter(collection, at) {
|
|
1279
1957
|
return emitters.get(collection, () => {
|
|
1280
1958
|
const blocks = memberSpecs.map((m) => m.emitter(collection, `${at} › ${where}`));
|
|
@@ -1298,7 +1976,7 @@ function sectionSpec(cfg, members) {
|
|
|
1298
1976
|
return East.function([collection, PathType, IdOptType], PlanBlocksType, ($, coll, prefix, parent) => {
|
|
1299
1977
|
const id = $.let(East.value(variant("section", { series: cfg.key, path: prefix }), PlanRowIdType), PlanRowIdType);
|
|
1300
1978
|
const under = $.let(East.value(some(id), IdOptType), IdOptType);
|
|
1301
|
-
const head = $.let(East.value({ fixed: true, parent, rows: [header(id, parent)] }, PlanBlockType), PlanBlockType);
|
|
1979
|
+
const head = $.let(East.value({ fixed: true, parent, charts: none, rows: [header(id, parent)] }, PlanBlockType), PlanBlockType);
|
|
1302
1980
|
const out = $.let(East.value([head], PlanBlocksType), PlanBlocksType);
|
|
1303
1981
|
for (const member of members)
|
|
1304
1982
|
$(out.append(member(coll, prefix, under)));
|
|
@@ -1342,11 +2020,15 @@ function rowsSpec(identity, rows) {
|
|
|
1342
2020
|
arm: "rows",
|
|
1343
2021
|
nested: [],
|
|
1344
2022
|
nests: false,
|
|
2023
|
+
// Its rows' kinds are an East value the build does not read (#1398): laid out below an entry, their chart rows are
|
|
2024
|
+
// not known.
|
|
2025
|
+
charts: undefined,
|
|
2026
|
+
reads: [],
|
|
1345
2027
|
emitter,
|
|
1346
2028
|
// A FIXED block: no entry produces hand-built rows, so every window
|
|
1347
2029
|
// serves them alike and the canvas draws them once (#823).
|
|
1348
2030
|
blocks(collection) {
|
|
1349
|
-
return blockLists.get(collection, () => oneBlock(collection, emitter(collection), true));
|
|
2031
|
+
return blockLists.get(collection, () => oneBlock(collection, emitter(collection), true, undefined));
|
|
1350
2032
|
},
|
|
1351
2033
|
// No entry produces them, so no gesture is written into one (#880).
|
|
1352
2034
|
writer() {
|
|
@@ -1469,17 +2151,34 @@ export function applySeriesValue(s, data) {
|
|
|
1469
2151
|
}
|
|
1470
2152
|
/**
|
|
1471
2153
|
* Check a TS series list before it is applied — its keys unique across the
|
|
1472
|
-
* whole tree
|
|
1473
|
-
*
|
|
2154
|
+
* whole tree, and its values collections keyed by the axis's instants (#1436).
|
|
2155
|
+
* An East expression list is checked at render (a repeated id is a row
|
|
2156
|
+
* diagnostic), since its series are not known until it runs.
|
|
1474
2157
|
*
|
|
1475
2158
|
* @param series - The `series` input
|
|
1476
2159
|
* @param where - Who is asking, for the message
|
|
2160
|
+
* @param axisKind - The axis's kind, when its declaration says it
|
|
1477
2161
|
*/
|
|
1478
|
-
export function checkSeries(series, where) {
|
|
2162
|
+
export function checkSeries(series, where, axisKind) {
|
|
1479
2163
|
if (!Array.isArray(series))
|
|
1480
2164
|
return;
|
|
1481
2165
|
const specs = series.map((s) => specOf(s)).filter((s) => s !== undefined);
|
|
1482
2166
|
assertUniqueKeys(specs, where);
|
|
2167
|
+
// A values collection is keyed by its instant (#1436): one keyed by String
|
|
2168
|
+
// rides only an ordinal axis.
|
|
2169
|
+
if (axisKind === undefined || axisKind === "ordinal")
|
|
2170
|
+
return;
|
|
2171
|
+
const walk = (spec) => {
|
|
2172
|
+
for (const use of spec.reads) {
|
|
2173
|
+
if (use.read.kind !== "values" || !isTypeEqual(use.key, StringType))
|
|
2174
|
+
continue;
|
|
2175
|
+
throw new Error(`Plan.values: "${use.field}" is keyed by String, and the axis is ${axisKind} — values are keyed by their ` +
|
|
2176
|
+
`instant, ${axisKind === "time" ? "a DateTime" : "a Float or an Integer"} here: read things people drag ` +
|
|
2177
|
+
`with Plan.items("${use.field}", times, draw)`);
|
|
2178
|
+
}
|
|
2179
|
+
spec.nested.forEach(walk);
|
|
2180
|
+
};
|
|
2181
|
+
specs.forEach(walk);
|
|
1483
2182
|
}
|
|
1484
2183
|
/**
|
|
1485
2184
|
* Reads a series value's facts off the spec its builder recorded (#1190).
|
|
@@ -1495,7 +2194,10 @@ export function planSeriesFacts(series, collection, where) {
|
|
|
1495
2194
|
const spec = specOf(series);
|
|
1496
2195
|
if (spec === undefined)
|
|
1497
2196
|
return undefined;
|
|
1498
|
-
return {
|
|
2197
|
+
return {
|
|
2198
|
+
arm: spec.arm, key: spec.key, title: spec.title, nests: spec.nests, writes: spec.writer(collection, where) !== undefined,
|
|
2199
|
+
charts: spec.charts,
|
|
2200
|
+
};
|
|
1499
2201
|
}
|
|
1500
2202
|
/**
|
|
1501
2203
|
* The keys of a series list's whole tree, each series' and every series
|
|
@@ -1615,9 +2317,6 @@ export function seriesWriteFn(series, collection) {
|
|
|
1615
2317
|
return result;
|
|
1616
2318
|
});
|
|
1617
2319
|
}
|
|
1618
|
-
// ============================================================================
|
|
1619
|
-
// Builders — Plan.series.*
|
|
1620
|
-
// ============================================================================
|
|
1621
2320
|
/**
|
|
1622
2321
|
* A span series — one state-run row per entry; a row with children shows its
|
|
1623
2322
|
* own runs plus bands over its subtree's runs (`rollup`) — each band sums its
|
|
@@ -1626,27 +2325,46 @@ export function seriesWriteFn(series, collection) {
|
|
|
1626
2325
|
* @typeParam R - The entry type
|
|
1627
2326
|
* @typeParam K - The axis kind the runs imply (inferred from `runs`; `never` when erased)
|
|
1628
2327
|
* @typeParam KT - The entries' key type (`keyType`; `String` by default)
|
|
2328
|
+
* @typeParam FR - The collection its runs read
|
|
2329
|
+
* @typeParam UR - What its runs read
|
|
2330
|
+
* @typeParam UD - What its decisions read
|
|
2331
|
+
* @typeParam UP - What its ports read
|
|
2332
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2333
|
+
* @typeParam CU - One step-down's reads
|
|
2334
|
+
* @typeParam CF - The folds of its cells
|
|
2335
|
+
* @typeParam CS - Several step-downs' reads
|
|
2336
|
+
* @typeParam RL - Its `rollup`, as written
|
|
1629
2337
|
* @param rowType - The entry type (every builder takes it first — the `Slice.config` shape)
|
|
1630
|
-
* @param config - The accessors and nesting ({@link PlanSpanSeriesConfig})
|
|
1631
|
-
* @returns A series value, branded with its kind
|
|
2338
|
+
* @param config - The reads, accessors and nesting ({@link PlanSpanSeriesConfig})
|
|
2339
|
+
* @returns A series value, branded with its kind and what it reads
|
|
1632
2340
|
*/
|
|
1633
2341
|
export function createSeriesSpan(rowType, config) {
|
|
1634
2342
|
const cfg = config;
|
|
2343
|
+
const where = `Plan.series.span "${cfg.key}"`;
|
|
2344
|
+
const edit = editRecipeOf(cfg.edit, "runs", "{ from, to }", cfg.runs, where);
|
|
1635
2345
|
// A row rolls up its children: its own (`children`), or — declared on a
|
|
1636
2346
|
// views member — the ones the views nest under it (#1219).
|
|
1637
2347
|
const rollup = cfg.children !== undefined || cfg.rollup !== undefined ? resolveTag(cfg.rollup ?? "union", PlanRollupType) : undefined;
|
|
2348
|
+
const runs = elementField(rowType, cfg.runs, "run", where, "runs");
|
|
2349
|
+
if (runs === undefined)
|
|
2350
|
+
throw new Error(`${where}: give its runs — Plan.items(field, { from, to }, draw), or a function of the row`);
|
|
2351
|
+
const decisions = elementField(rowType, cfg.decisions, "decision", where, "decisions");
|
|
2352
|
+
const ports = elementField(rowType, cfg.ports, "port", where, "ports");
|
|
1638
2353
|
const spec = dataSpec(rowType, cfg, {
|
|
1639
2354
|
arm: "span",
|
|
1640
|
-
kind: (
|
|
1641
|
-
runs:
|
|
1642
|
-
...(
|
|
1643
|
-
...(
|
|
2355
|
+
kind: (node, key, hasChildren, value) => spanKind({
|
|
2356
|
+
runs: runs.at(node, key, value),
|
|
2357
|
+
...(decisions !== undefined ? { decisions: decisions.at(node, key, value) } : {}),
|
|
2358
|
+
...(ports !== undefined ? { ports: ports.at(node, key, value) } : {}),
|
|
1644
2359
|
}, rollup === undefined
|
|
1645
2360
|
? East.value(none, OptionType(PlanRollupType))
|
|
1646
2361
|
// A row rolls up only when it HAS child rows — a leaf's bands
|
|
1647
2362
|
// would repeat its own runs.
|
|
1648
2363
|
: hasChildren.ifElse(() => East.value(some(rollup), OptionType(PlanRollupType)), () => East.value(none, OptionType(PlanRollupType)))),
|
|
1649
|
-
edit
|
|
2364
|
+
edit,
|
|
2365
|
+
reads: [...runs.reads, ...(decisions?.reads ?? []), ...(ports?.reads ?? [])],
|
|
2366
|
+
// Its runs roll up into its bands where it has children or declares a rollup (#1435).
|
|
2367
|
+
...(cfg.children !== undefined || cfg.rollup !== undefined ? { rollup: tagOf(cfg.rollup, "union") } : {}),
|
|
1650
2368
|
});
|
|
1651
2369
|
return seriesValue(rowType, cfg.keyType, spec, cfg);
|
|
1652
2370
|
}
|
|
@@ -1657,21 +2375,33 @@ export function createSeriesSpan(rowType, config) {
|
|
|
1657
2375
|
* @typeParam R - The entry type
|
|
1658
2376
|
* @typeParam K - The axis kind the cells imply (inferred from `cells`; `never` when erased)
|
|
1659
2377
|
* @typeParam KT - The entries' key type
|
|
2378
|
+
* @typeParam UC - What its cells read
|
|
2379
|
+
* @typeParam FO - How a bucket folds them
|
|
2380
|
+
* @typeParam A - Its `aggregate`, as written
|
|
2381
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2382
|
+
* @typeParam CU - One step-down's reads
|
|
2383
|
+
* @typeParam CF - The folds of its cells
|
|
2384
|
+
* @typeParam CS - Several step-downs' reads
|
|
1660
2385
|
* @param rowType - The entry type
|
|
1661
|
-
* @param config - The accessors and nesting ({@link PlanHeatSeriesConfig})
|
|
1662
|
-
* @returns A series value, branded with its kind
|
|
2386
|
+
* @param config - The reads, accessors and nesting ({@link PlanHeatSeriesConfig})
|
|
2387
|
+
* @returns A series value, branded with its kind, what it reads and the fold of its cells
|
|
1663
2388
|
*/
|
|
1664
2389
|
export function createSeriesHeat(rowType, config) {
|
|
1665
2390
|
const cfg = config;
|
|
2391
|
+
const where = `Plan.series.heat "${cfg.key}"`;
|
|
1666
2392
|
const aggregate = cfg.children !== undefined
|
|
1667
2393
|
? East.value(some(resolveTag(cfg.aggregate ?? "mean", PlanAggregateType)), OptionType(PlanAggregateType))
|
|
1668
2394
|
: East.value(none, OptionType(PlanAggregateType));
|
|
2395
|
+
const cells = consumerField(rowType, cfg.cells, "heat", where, "cells");
|
|
1669
2396
|
const spec = dataSpec(rowType, cfg, {
|
|
1670
2397
|
arm: "heat",
|
|
1671
|
-
kind: (
|
|
1672
|
-
cells:
|
|
2398
|
+
kind: (node, key, _hasChildren, value) => heatKind({
|
|
2399
|
+
...(cells !== undefined ? { cells: cells.at(node, key, value) } : {}),
|
|
1673
2400
|
...(cfg.scale !== undefined ? { scale: cfg.scale } : {}),
|
|
1674
2401
|
}, aggregate),
|
|
2402
|
+
reads: cells?.reads ?? [],
|
|
2403
|
+
// Its row derives its children's numbers by its aggregate: a tree's own values, or a step-down's (#1435).
|
|
2404
|
+
...(cfg.children !== undefined ? { aggregate: tagOf(cfg.aggregate, "mean"), subtotalsOwn: true } : {}),
|
|
1675
2405
|
});
|
|
1676
2406
|
return seriesValue(rowType, cfg.keyType, spec, cfg);
|
|
1677
2407
|
}
|
|
@@ -1682,28 +2412,48 @@ export function createSeriesHeat(rowType, config) {
|
|
|
1682
2412
|
* @typeParam R - The entry type
|
|
1683
2413
|
* @typeParam K - The axis kind the cells imply (inferred from `cells` / `series`; `never` when erased)
|
|
1684
2414
|
* @typeParam KT - The entries' key type
|
|
2415
|
+
* @typeParam UC - What its `cells` read
|
|
2416
|
+
* @typeParam S - Its `series` positions, as written
|
|
2417
|
+
* @typeParam FO - Its `cells`' fold, as written
|
|
2418
|
+
* @typeParam A - Its `aggregate`, as written
|
|
2419
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2420
|
+
* @typeParam CU - One step-down's reads
|
|
2421
|
+
* @typeParam CF - The folds of its cells
|
|
2422
|
+
* @typeParam CS - Several step-downs' reads
|
|
1685
2423
|
* @param rowType - The entry type
|
|
1686
|
-
* @param config - The accessors and nesting ({@link PlanTableSeriesOfConfig})
|
|
1687
|
-
* @returns A series value, branded with its kind
|
|
2424
|
+
* @param config - The reads, accessors and nesting ({@link PlanTableSeriesOfConfig})
|
|
2425
|
+
* @returns A series value, branded with its kind, what it reads and the folds of its positions
|
|
1688
2426
|
*/
|
|
1689
2427
|
export function createSeriesTable(rowType, config) {
|
|
1690
2428
|
const cfg = config;
|
|
2429
|
+
const where = `Plan.series.table "${cfg.key}"`;
|
|
1691
2430
|
if (cfg.cells !== undefined && cfg.series !== undefined) {
|
|
1692
|
-
throw new Error(
|
|
2431
|
+
throw new Error(`${where}: pass \`cells\` (one plain value series) OR \`series\` — not both`);
|
|
1693
2432
|
}
|
|
1694
2433
|
const aggregate = cfg.children !== undefined
|
|
1695
2434
|
? East.value(some(resolveTag(cfg.aggregate ?? "sum", TableAggregateType)), OptionType(TableAggregateType))
|
|
1696
2435
|
: East.value(none, OptionType(TableAggregateType));
|
|
2436
|
+
const cells = consumerField(rowType, cfg.cells, "tableCells", where, "cells");
|
|
2437
|
+
// Its cells fold as the row declares, `sum` unless it says (#1436): what a parent subtotals them by (#1435, #1438).
|
|
2438
|
+
const rowFold = tagOf(cfg.fold, "sum");
|
|
2439
|
+
const cellReads = (cells?.reads ?? []).map((read) => (read.fold !== undefined || rowFold === undefined ? read : { ...read, fold: rowFold }));
|
|
2440
|
+
const positions = listField(rowType, cfg.series, "tableSeries", where, "series");
|
|
2441
|
+
// The positions a typed number writes (#1436), each read checked as it built above.
|
|
2442
|
+
const values = tableEditsOf(rowType, cfg, where);
|
|
1697
2443
|
const spec = dataSpec(rowType, cfg, {
|
|
1698
2444
|
arm: "table",
|
|
1699
|
-
kind: (
|
|
1700
|
-
...(
|
|
2445
|
+
kind: (node, key, _hasChildren, value) => tableKind({
|
|
2446
|
+
...(cells !== undefined ? { cells: cells.at(node, key, value) } : {}),
|
|
1701
2447
|
...(cfg.fold !== undefined ? { fold: cfg.fold } : {}),
|
|
1702
|
-
...(
|
|
2448
|
+
...(positions !== undefined ? { series: positions.at(node, key, value) } : {}),
|
|
1703
2449
|
...(cfg.split !== undefined ? { split: cfg.split } : {}),
|
|
1704
2450
|
...(cfg.format !== undefined ? { format: cfg.format } : {}),
|
|
1705
2451
|
...(cfg.emphasis !== undefined ? { emphasis: cfg.emphasis } : {}),
|
|
1706
2452
|
}, aggregate),
|
|
2453
|
+
reads: [...cellReads, ...(positions?.reads ?? [])],
|
|
2454
|
+
values,
|
|
2455
|
+
// Its row derives its children's numbers by its aggregate: a tree's own values, or a step-down's (#1435).
|
|
2456
|
+
...(cfg.children !== undefined ? { aggregate: tagOf(cfg.aggregate, "sum"), subtotalsOwn: true } : {}),
|
|
1707
2457
|
});
|
|
1708
2458
|
return seriesValue(rowType, cfg.keyType, spec, cfg);
|
|
1709
2459
|
}
|
|
@@ -1713,20 +2463,34 @@ export function createSeriesTable(rowType, config) {
|
|
|
1713
2463
|
* @typeParam R - The entry type
|
|
1714
2464
|
* @typeParam K - The axis kind the tiles imply (inferred from `events` / `markers`; `never` when erased)
|
|
1715
2465
|
* @typeParam KT - The entries' key type
|
|
2466
|
+
* @typeParam FE - The collection its tiles read
|
|
2467
|
+
* @typeParam UE - What its tiles read
|
|
2468
|
+
* @typeParam UM - What its markers read
|
|
2469
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2470
|
+
* @typeParam CU - One step-down's reads
|
|
2471
|
+
* @typeParam CF - The folds of its cells
|
|
2472
|
+
* @typeParam CS - Several step-downs' reads
|
|
1716
2473
|
* @param rowType - The entry type
|
|
1717
|
-
* @param config - The accessors ({@link PlanBucketsSeriesConfig})
|
|
1718
|
-
* @returns A series value, branded with its kind
|
|
2474
|
+
* @param config - The reads and accessors ({@link PlanBucketsSeriesConfig})
|
|
2475
|
+
* @returns A series value, branded with its kind and what it reads
|
|
1719
2476
|
*/
|
|
1720
2477
|
export function createSeriesBuckets(rowType, config) {
|
|
1721
2478
|
const cfg = config;
|
|
2479
|
+
const where = `Plan.series.buckets "${cfg.key}"`;
|
|
2480
|
+
const edit = editRecipeOf(cfg.edit, "events", "{ at }", cfg.events, where);
|
|
2481
|
+
const events = elementField(rowType, cfg.events, "event", where, "events");
|
|
2482
|
+
if (events === undefined)
|
|
2483
|
+
throw new Error(`${where}: give its events — Plan.items(field, { at }, draw), or a function of the row`);
|
|
2484
|
+
const markers = elementField(rowType, cfg.markers, "marker", where, "markers");
|
|
1722
2485
|
const spec = dataSpec(rowType, cfg, {
|
|
1723
2486
|
arm: "buckets",
|
|
1724
|
-
kind: (
|
|
1725
|
-
...(cfg.lanes !== undefined ? { lanes: cfg.lanes(
|
|
1726
|
-
events:
|
|
1727
|
-
...(
|
|
2487
|
+
kind: (node, key, _hasChildren, value) => bucketsKind({
|
|
2488
|
+
...(cfg.lanes !== undefined ? { lanes: cfg.lanes(node, key) } : {}),
|
|
2489
|
+
events: events.at(node, key, value),
|
|
2490
|
+
...(markers !== undefined ? { markers: markers.at(node, key, value) } : {}),
|
|
1728
2491
|
}),
|
|
1729
|
-
edit
|
|
2492
|
+
edit,
|
|
2493
|
+
reads: [...events.reads, ...(markers?.reads ?? [])],
|
|
1730
2494
|
});
|
|
1731
2495
|
return seriesValue(rowType, cfg.keyType, spec, cfg);
|
|
1732
2496
|
}
|
|
@@ -1736,16 +2500,28 @@ export function createSeriesBuckets(rowType, config) {
|
|
|
1736
2500
|
* @typeParam R - The entry type
|
|
1737
2501
|
* @typeParam K - The axis kind the chips imply (inferred from `chips`; `never` when erased)
|
|
1738
2502
|
* @typeParam KT - The entries' key type
|
|
2503
|
+
* @typeParam FC - The collection its chips read
|
|
2504
|
+
* @typeParam UC - What its chips read
|
|
2505
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2506
|
+
* @typeParam CU - One step-down's reads
|
|
2507
|
+
* @typeParam CF - The folds of its cells
|
|
2508
|
+
* @typeParam CS - Several step-downs' reads
|
|
1739
2509
|
* @param rowType - The entry type
|
|
1740
|
-
* @param config - The accessors ({@link PlanCardsSeriesConfig})
|
|
1741
|
-
* @returns A series value, branded with its kind
|
|
2510
|
+
* @param config - The reads and accessors ({@link PlanCardsSeriesConfig})
|
|
2511
|
+
* @returns A series value, branded with its kind and what it reads
|
|
1742
2512
|
*/
|
|
1743
2513
|
export function createSeriesCards(rowType, config) {
|
|
1744
2514
|
const cfg = config;
|
|
2515
|
+
const where = `Plan.series.cards "${cfg.key}"`;
|
|
2516
|
+
const edit = editRecipeOf(cfg.edit, "chips", "{ from, to }", cfg.chips, where);
|
|
2517
|
+
const chips = elementField(rowType, cfg.chips, "chip", where, "chips");
|
|
2518
|
+
if (chips === undefined)
|
|
2519
|
+
throw new Error(`${where}: give its chips — Plan.items(field, { from, to }, draw), or a function of the row`);
|
|
1745
2520
|
const spec = dataSpec(rowType, cfg, {
|
|
1746
2521
|
arm: "cards",
|
|
1747
|
-
kind: (
|
|
1748
|
-
edit
|
|
2522
|
+
kind: (node, key, _hasChildren, value) => cardsKind(chips.at(node, key, value)),
|
|
2523
|
+
edit,
|
|
2524
|
+
reads: chips.reads,
|
|
1749
2525
|
});
|
|
1750
2526
|
return seriesValue(rowType, cfg.keyType, spec, cfg);
|
|
1751
2527
|
}
|
|
@@ -1755,37 +2531,61 @@ export function createSeriesCards(rowType, config) {
|
|
|
1755
2531
|
* @typeParam R - The entry type
|
|
1756
2532
|
* @typeParam K - The axis kind the marks imply (inferred from `marks`; `never` when erased)
|
|
1757
2533
|
* @typeParam KT - The entries' key type
|
|
2534
|
+
* @typeParam FM - The collection its marks read
|
|
2535
|
+
* @typeParam UM - What its marks read
|
|
2536
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2537
|
+
* @typeParam CU - One step-down's reads
|
|
2538
|
+
* @typeParam CF - The folds of its cells
|
|
2539
|
+
* @typeParam CS - Several step-downs' reads
|
|
1758
2540
|
* @param rowType - The entry type
|
|
1759
|
-
* @param config - The accessors ({@link PlanEventsSeriesConfig})
|
|
1760
|
-
* @returns A series value, branded with its kind
|
|
2541
|
+
* @param config - The reads and accessors ({@link PlanEventsSeriesConfig})
|
|
2542
|
+
* @returns A series value, branded with its kind and what it reads
|
|
1761
2543
|
*/
|
|
1762
2544
|
export function createSeriesEvents(rowType, config) {
|
|
1763
2545
|
const cfg = config;
|
|
2546
|
+
const where = `Plan.series.events "${cfg.key}"`;
|
|
2547
|
+
const edit = editRecipeOf(cfg.edit, "marks", "{ at }", cfg.marks, where);
|
|
2548
|
+
const marks = elementField(rowType, cfg.marks, "mark", where, "marks");
|
|
2549
|
+
if (marks === undefined)
|
|
2550
|
+
throw new Error(`${where}: give its marks — Plan.items(field, { at }, draw), or a function of the row`);
|
|
1764
2551
|
const spec = dataSpec(rowType, cfg, {
|
|
1765
2552
|
arm: "events",
|
|
1766
|
-
kind: (
|
|
1767
|
-
edit
|
|
2553
|
+
kind: (node, key, _hasChildren, value) => eventsKind(marks.at(node, key, value)),
|
|
2554
|
+
edit,
|
|
2555
|
+
reads: marks.reads,
|
|
1768
2556
|
});
|
|
1769
2557
|
return seriesValue(rowType, cfg.keyType, spec, cfg);
|
|
1770
2558
|
}
|
|
1771
2559
|
/**
|
|
1772
|
-
* A chart series — one chart row per entry, layers
|
|
1773
|
-
*
|
|
1774
|
-
*
|
|
1775
|
-
*
|
|
2560
|
+
* A chart series — one chart row per entry, its layers over the entry's own
|
|
2561
|
+
* values (`Plan.line` … `Plan.band` over `Plan.values`), or built from the
|
|
2562
|
+
* entry by a function. Its layers over values brand it with the axis kind
|
|
2563
|
+
* their keys ride; a Chart layer's face hides its x type, so a series whose
|
|
2564
|
+
* layers are all Chart layers constrains no axis at compile time — the
|
|
2565
|
+
* render-time diagnostic holds it to the axis like any row.
|
|
1776
2566
|
*
|
|
1777
2567
|
* @typeParam R - The entry type
|
|
1778
2568
|
* @typeParam KT - The entries' key type
|
|
2569
|
+
* @typeParam K - The axis kind its layers' values ride
|
|
2570
|
+
* @typeParam L - Its `layers`, as written
|
|
2571
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2572
|
+
* @typeParam CU - One step-down's reads
|
|
2573
|
+
* @typeParam CF - The folds of its cells
|
|
2574
|
+
* @typeParam CS - Several step-downs' reads
|
|
1779
2575
|
* @param rowType - The entry type
|
|
1780
|
-
* @param config - The accessors and shared axes ({@link PlanChartSeriesConfig})
|
|
1781
|
-
* @returns A series value
|
|
2576
|
+
* @param config - The layers, accessors and shared axes ({@link PlanChartSeriesConfig})
|
|
2577
|
+
* @returns A series value, branded with its kind and what it reads
|
|
1782
2578
|
*/
|
|
1783
2579
|
export function createSeriesChart(rowType, config) {
|
|
1784
2580
|
const cfg = config;
|
|
2581
|
+
const where = `Plan.series.chart "${cfg.key}"`;
|
|
2582
|
+
const layers = listField(rowType, cfg.layers, "layer", where, "layers");
|
|
2583
|
+
if (layers === undefined)
|
|
2584
|
+
throw new Error(`${where}: give its layers — Plan.line(Plan.values(field, draw)) and the like, or a function of the row`);
|
|
1785
2585
|
const spec = dataSpec(rowType, cfg, {
|
|
1786
2586
|
arm: "chart",
|
|
1787
|
-
kind: (
|
|
1788
|
-
layers:
|
|
2587
|
+
kind: (node, key, _hasChildren, value) => chartKind({
|
|
2588
|
+
layers: layers.at(node, key, value),
|
|
1789
2589
|
...(cfg.left !== undefined ? { left: cfg.left } : {}),
|
|
1790
2590
|
...(cfg.right !== undefined ? { right: cfg.right } : {}),
|
|
1791
2591
|
...(cfg.height !== undefined ? { height: cfg.height } : {}),
|
|
@@ -1796,6 +2596,7 @@ export function createSeriesChart(rowType, config) {
|
|
|
1796
2596
|
? { pinned: (value, key) => East.value(cfg.pinned(value, key), BooleanType) }
|
|
1797
2597
|
: {}),
|
|
1798
2598
|
...(cfg.swatches !== undefined ? { swatches: cfg.swatches } : {}),
|
|
2599
|
+
reads: layers.reads,
|
|
1799
2600
|
});
|
|
1800
2601
|
return seriesValue(rowType, cfg.keyType, spec, cfg);
|
|
1801
2602
|
}
|
|
@@ -1806,19 +2607,25 @@ export function createSeriesChart(rowType, config) {
|
|
|
1806
2607
|
* its member count is derived.
|
|
1807
2608
|
*
|
|
1808
2609
|
* @remarks
|
|
1809
|
-
* Hierarchy comes from the data's nesting:
|
|
1810
|
-
*
|
|
1811
|
-
*
|
|
1812
|
-
*
|
|
1813
|
-
*
|
|
1814
|
-
* fixed titled block.
|
|
2610
|
+
* Hierarchy comes from the data's nesting: a group's members are a `Dict` of
|
|
2611
|
+
* the entry (`Plan.children(field, [series…])`), so a flat source is grouped
|
|
2612
|
+
* in the dataflow, or reshaped inline into entries that hold their members.
|
|
2613
|
+
* The `by` form and the static `group(R, chrome, children)` form are gone —
|
|
2614
|
+
* see `Plan.series.section` for a fixed titled block.
|
|
1815
2615
|
*
|
|
1816
2616
|
* @typeParam R - The entry type
|
|
1817
2617
|
* @typeParam K - The axis kind the summary cells imply
|
|
1818
2618
|
* @typeParam KT - The entries' key type
|
|
2619
|
+
* @typeParam US - What its `summary` reads
|
|
2620
|
+
* @typeParam FO - How a bucket folds its summary cells
|
|
2621
|
+
* @typeParam A - Its `summaryAggregate`, as written
|
|
2622
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2623
|
+
* @typeParam CU - One step-down's reads
|
|
2624
|
+
* @typeParam CF - The folds of its cells
|
|
2625
|
+
* @typeParam CS - Several step-downs' reads
|
|
1819
2626
|
* @param rowType - The entry type
|
|
1820
2627
|
* @param config - The strip's accessors and its members ({@link PlanGroupSeriesConfig})
|
|
1821
|
-
* @returns A series value, branded with its kind
|
|
2628
|
+
* @returns A series value, branded with its kind and what it reads
|
|
1822
2629
|
* @throws {Error} When called with the removed `by` or static forms
|
|
1823
2630
|
*/
|
|
1824
2631
|
export function createSeriesGroup(rowType, config) {
|
|
@@ -1834,17 +2641,20 @@ export function createSeriesGroup(rowType, config) {
|
|
|
1834
2641
|
if (cfg.children === undefined) {
|
|
1835
2642
|
throw new Error(`${where}: a group strip needs its members — declare \`children\``);
|
|
1836
2643
|
}
|
|
1837
|
-
|
|
1838
|
-
// The strip's ONE summary (#824): the per-entry cells, the declared
|
|
1839
|
-
// aggregate, or a plain band — both at once is refused here.
|
|
1840
|
-
const declared = summary === undefined ? groupSummary(undefined, cfg.summaryAggregate, where) : undefined;
|
|
1841
|
-
if (summary !== undefined && cfg.summaryAggregate !== undefined) {
|
|
2644
|
+
if (cfg.summary !== undefined && cfg.summaryAggregate !== undefined) {
|
|
1842
2645
|
throw new Error(`${where}: give \`summary\` (explicit strip cells) OR \`summaryAggregate\` (cells derived from the ` +
|
|
1843
2646
|
"members) — a collapsed strip shows one or the other");
|
|
1844
2647
|
}
|
|
2648
|
+
const summary = consumerField(rowType, cfg.summary, "heat", where, "summary");
|
|
2649
|
+
// The strip's ONE summary (#824): the per-entry cells, the declared
|
|
2650
|
+
// aggregate, or a plain band.
|
|
2651
|
+
const declared = summary === undefined ? groupSummary(undefined, cfg.summaryAggregate, where) : undefined;
|
|
1845
2652
|
const spec = dataSpec(rowType, cfg, {
|
|
1846
2653
|
arm: "group",
|
|
1847
|
-
kind: (
|
|
2654
|
+
kind: (node, key, _hasChildren, value) => groupKind(declared ?? East.value(variant("cells", East.value(summary.at(node, key, value), PlanHeatCellsType)), PlanGroupSummaryType)),
|
|
2655
|
+
reads: summary?.reads ?? [],
|
|
2656
|
+
// Its strip derives its members' numbers by its summaryAggregate (#1435).
|
|
2657
|
+
...(cfg.summaryAggregate !== undefined ? { aggregate: tagOf(cfg.summaryAggregate, "mean") } : {}),
|
|
1848
2658
|
});
|
|
1849
2659
|
return seriesValue(rowType, cfg.keyType, spec, cfg);
|
|
1850
2660
|
}
|
|
@@ -1856,10 +2666,11 @@ export function createSeriesGroup(rowType, config) {
|
|
|
1856
2666
|
*
|
|
1857
2667
|
* @typeParam R - The entry type (the members' — they share the section's entries)
|
|
1858
2668
|
* @typeParam K - The union of the members' axis kinds (inferred; `never` when all are erased)
|
|
2669
|
+
* @typeParam S - The members, as written
|
|
1859
2670
|
* @param rowType - The entry type
|
|
1860
2671
|
* @param config - The header ({@link PlanSectionSeriesConfig})
|
|
1861
2672
|
* @param members - The member series, in order
|
|
1862
|
-
* @returns A series value, branded with its members' kinds
|
|
2673
|
+
* @returns A series value, branded with its members' kinds and what they read
|
|
1863
2674
|
*/
|
|
1864
2675
|
export function createSeriesSection(rowType, config, members) {
|
|
1865
2676
|
const cfg = config;
|
|
@@ -1878,7 +2689,7 @@ export function createSeriesSection(rowType, config, members) {
|
|
|
1878
2689
|
* view row's id is its member series' key and the entry's path, and a seek on
|
|
1879
2690
|
* the entry lands on its first view row.
|
|
1880
2691
|
*
|
|
1881
|
-
* The views' `children` are a step-down's series, or — a
|
|
2692
|
+
* The views' `children` are a step-down's series, or — a tree's field — more
|
|
1882
2693
|
* of the views' own entries, each drawn as its members' rows, to any depth,
|
|
1883
2694
|
* the views' `match` and `collapsed` at every level (#1219). A span member that
|
|
1884
2695
|
* declares `rollup` rolls up the children nested under its row.
|
|
@@ -1886,10 +2697,15 @@ export function createSeriesSection(rowType, config, members) {
|
|
|
1886
2697
|
* @typeParam R - The entry type
|
|
1887
2698
|
* @typeParam K - The union of the members' axis kinds (inferred; `never` when all are erased)
|
|
1888
2699
|
* @typeParam KT - The entries' key type
|
|
2700
|
+
* @typeParam S - The members, as written
|
|
2701
|
+
* @typeParam CT - A tree's field, as `children` names it
|
|
2702
|
+
* @typeParam CU - One step-down's reads
|
|
2703
|
+
* @typeParam CF - The folds of its cells
|
|
2704
|
+
* @typeParam CS - Several step-downs' reads
|
|
1889
2705
|
* @param rowType - The entry type
|
|
1890
2706
|
* @param config - Membership, collapse and children ({@link PlanViewsSeriesConfig})
|
|
1891
2707
|
* @param members - The member series — one row each per entry, in order
|
|
1892
|
-
* @returns A series value, branded with its members' kinds
|
|
2708
|
+
* @returns A series value, branded with its members' kinds and what it reads
|
|
1893
2709
|
*/
|
|
1894
2710
|
export function createSeriesViews(rowType, config, members) {
|
|
1895
2711
|
const cfg = config;
|