@abide/abide 0.105.1 → 0.107.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/bin/abide.ts +4 -1
- package/docs/REGISTRY.md +156 -44
- package/docs/RULEBOOK.md +392 -88
- package/docs/abide.md +7245 -10248
- package/package.json +4 -1
- package/scaffold/AGENTS.md +2 -0
- package/scaffold/src/getGreeting.ts +6 -0
- package/scaffold/src/index.abide +3 -1
- package/scaffold/src/tests/getGreeting.test.ts +6 -0
- package/scaffold/src/tests/index.test.ts +18 -0
- package/src/compiler/DOCS_SITE.ts +2 -0
- package/src/compiler/Lowering.ts +234 -14
- package/src/compiler/PositionTable.ts +14 -7
- package/src/compiler/PositionedRefusal.ts +13 -0
- package/src/compiler/Refusals.ts +18 -11
- package/src/compiler/SHARED_NAMES.ts +2 -0
- package/src/compiler/ShadowMap.ts +37 -0
- package/src/compiler/TEMPLATE_BLOCKS.ts +12 -0
- package/src/compiler/TypeSession.ts +410 -31
- package/src/compiler/appLayout.ts +18 -2
- package/src/compiler/argsSchemaOf.ts +55 -9
- package/src/compiler/checkApp.ts +33 -0
- package/src/compiler/checkedShadow.ts +36 -22
- package/src/compiler/citedClauses.ts +14 -0
- package/src/compiler/classifyRead.ts +6 -0
- package/src/compiler/classifyTemplate.ts +7 -4
- package/src/compiler/compileApp.ts +2 -2
- package/src/compiler/declaredExports.ts +27 -6
- package/src/compiler/emitClient.ts +306 -103
- package/src/compiler/handlersUnder.ts +4 -0
- package/src/compiler/invocationProps.ts +1 -1
- package/src/compiler/isIgnored.ts +27 -0
- package/src/compiler/parseAbide.ts +176 -76
- package/src/compiler/projectShadow.ts +30 -6
- package/src/compiler/readSources.ts +1 -1
- package/src/compiler/readsIn.ts +100 -1
- package/src/compiler/renderMarkup.ts +36 -5
- package/src/compiler/scaffold.ts +19 -6
- package/src/compiler/serveLanguage.ts +156 -21
- package/src/compiler/templateContext.ts +150 -0
- package/src/compiler/tokenize.ts +6 -0
- package/src/server/BRIDGE_VERSION.ts +1 -1
- package/src/server/Inbox.ts +8 -0
- package/src/server/MCP_PROTOCOL_VERSION.ts +1 -1
- package/src/server/MOUNTABLE.ts +6 -0
- package/src/server/abideModules.ts +8 -1
- package/src/server/answerRequest.ts +3 -1
- package/src/server/answerRpc.ts +26 -12
- package/src/server/answerSocket.ts +26 -1
- package/src/server/argsFor.ts +4 -3
- package/src/server/assistant.ts +21 -14
- package/src/server/bridgeRelay.ts +108 -20
- package/src/server/claudeApi.ts +19 -11
- package/src/server/claudeCode.ts +19 -14
- package/src/server/commands.ts +73 -9
- package/src/server/createApp.ts +41 -7
- package/src/server/devWorker.ts +3 -3
- package/src/server/generatedSurfaces.ts +37 -4
- package/src/server/muxUpgrade.ts +47 -0
- package/src/server/preload.ts +13 -2
- package/src/server/render.ts +4 -1
- package/src/server/runCompiled.ts +1 -0
- package/src/server/seedBuffer.ts +31 -1
- package/src/server/serveDev.ts +83 -72
- package/src/server/surfaceOf.ts +3 -0
- package/src/server/testMount.ts +53 -0
- package/src/shared/ADDRESSES.ts +1 -1
- package/src/shared/ERROR_META.ts +3 -0
- package/src/shared/Schema.ts +1 -1
- package/src/shared/WORK.ts +14 -12
- package/src/shared/applyPatch.ts +1 -1
- package/src/shared/boundValue.ts +81 -0
- package/src/shared/index.ts +7 -2
- package/src/shared/jsonSchema.ts +25 -2
- package/src/shared/log.ts +11 -1
- package/src/shared/reactive/Keyed.ts +30 -6
- package/src/shared/reactive/PATCHES.ts +1 -1
- package/src/shared/reactive/Reactive.ts +118 -60
- package/src/shared/reactive/canonicalKey.ts +1 -1
- package/src/shared/reactive/index.ts +13 -5
- package/src/shared/reactive/recordWrites.ts +1 -1
- package/src/shared/reactive/watch.ts +26 -4
- package/src/shared/rpc.ts +6 -1
- package/src/shared/url.ts +7 -3
- package/src/shared/validateJson.ts +1 -1
- package/src/ui/ArmRegion.ts +2 -2
- package/src/ui/List.ts +9 -9
- package/src/ui/RawRun.ts +1 -1
- package/src/ui/Router.ts +194 -36
- package/src/ui/Scope.ts +29 -0
- package/src/ui/adoptWalk.ts +3 -3
- package/src/ui/applyHead.ts +25 -3
- package/src/ui/bindElement.ts +4 -0
- package/src/ui/bindProperty.ts +70 -22
- package/src/ui/index.ts +1 -1
- package/src/ui/listenForRoutes.ts +14 -3
- package/src/ui/reconcile.ts +23 -28
- package/src/ui/regions.ts +9 -2
- package/src/ui/rows.ts +108 -28
package/src/ui/index.ts
CHANGED
|
@@ -56,7 +56,7 @@ export {
|
|
|
56
56
|
type Region,
|
|
57
57
|
} from './regions.ts'
|
|
58
58
|
export { rowKeyOf } from './rowKeyOf.ts'
|
|
59
|
-
export { replaceRow } from './rows.ts'
|
|
59
|
+
export { itemOf, noUpdate, replaceRow, rowCell } from './rows.ts'
|
|
60
60
|
export { EMPTY_SCOPE, Scope } from './Scope.ts'
|
|
61
61
|
export { setAttribute } from './setAttribute.ts'
|
|
62
62
|
export { setClass } from './setClass.ts'
|
|
@@ -32,13 +32,18 @@ export function listenForRoutes(router: Router): () => void {
|
|
|
32
32
|
// BACK AND FORWARD HAVE ALREADY MOVED THE ADDRESS BAR by the time this runs, so the page is
|
|
33
33
|
// mounted where the bar already points and nothing is pushed for it. 30.20 — a step within the
|
|
34
34
|
// standing page, back over an in-page `#anchor` jump, is `go`'s to keep: nothing asked, nothing
|
|
35
|
-
// remounted.
|
|
35
|
+
// remounted. 30.29 — the scroll is the router's to put back, once the page it belongs to is
|
|
36
|
+
// mounted: the browser's own restoration runs before that page exists.
|
|
36
37
|
const onPop = (): void => {
|
|
37
38
|
if (router.match(location.pathname) === undefined) {
|
|
38
39
|
location.reload()
|
|
39
40
|
return
|
|
40
41
|
}
|
|
41
|
-
void router.go(
|
|
42
|
+
void router.go(
|
|
43
|
+
location.href,
|
|
44
|
+
{ replace: true, keepScroll: true },
|
|
45
|
+
router.stepped(),
|
|
46
|
+
)
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
const listening = new AbortController()
|
|
@@ -48,7 +53,13 @@ export function listenForRoutes(router: Router): () => void {
|
|
|
48
53
|
document.addEventListener('pointerdown', onIntent, options)
|
|
49
54
|
document.addEventListener('focusin', onIntent, options)
|
|
50
55
|
addEventListener('popstate', onPop, options)
|
|
51
|
-
|
|
56
|
+
// A reload leaves the document by way of `pagehide`, the last moment the entry can be written.
|
|
57
|
+
addEventListener('pagehide', () => router.remember(), options)
|
|
58
|
+
history.scrollRestoration = 'manual'
|
|
59
|
+
return () => {
|
|
60
|
+
listening.abort()
|
|
61
|
+
history.scrollRestoration = 'auto'
|
|
62
|
+
}
|
|
52
63
|
}
|
|
53
64
|
|
|
54
65
|
/**
|
package/src/ui/reconcile.ts
CHANGED
|
@@ -4,9 +4,9 @@ import type { List } from './List.ts'
|
|
|
4
4
|
import { HYDRATE_LOG } from './Mismatch.ts'
|
|
5
5
|
import { beginLayer, endLayer } from './measureLayer.ts'
|
|
6
6
|
import { emptyRegion } from './regions.ts'
|
|
7
|
-
import { dropRow, makeRow, moveRow, type Row } from './rows.ts'
|
|
7
|
+
import { dropRow, makeRow, moveRow, type Row, updateRow } from './rows.ts'
|
|
8
8
|
|
|
9
|
-
// 41.8 — a KEYED list, reconciled by moving the nodes that are already there rather than by
|
|
9
|
+
// 41.8, 32.67 — a KEYED list, reconciled by moving the nodes that are already there rather than by
|
|
10
10
|
// rebuilding them. A rebuild produces the right screen and the wrong document: focus, selection,
|
|
11
11
|
// scroll position and anything a row was in the middle of go with the nodes that were replaced.
|
|
12
12
|
//
|
|
@@ -19,7 +19,7 @@ import { dropRow, makeRow, moveRow, type Row } from './rows.ts'
|
|
|
19
19
|
* Reconciles a keyed list's rows to `data`, moving survivors rather than remaking them.
|
|
20
20
|
*
|
|
21
21
|
* A key it has not seen gets a row from the builders `list.setUp` answers for it (14.8). Rows that
|
|
22
|
-
* survive are MOVED, never remade.
|
|
22
|
+
* survive are MOVED, never remade, and take the value now under their key (32.67).
|
|
23
23
|
*/
|
|
24
24
|
export function reconcile(list: List, data: unknown[]): void {
|
|
25
25
|
if (data.length === 0) {
|
|
@@ -98,33 +98,28 @@ export function reconcile(list: List, data: unknown[]): void {
|
|
|
98
98
|
for (let at = 0; at < wanted; at += 1) {
|
|
99
99
|
const key = keys[at] as unknown
|
|
100
100
|
const existing = held.get(key)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// while the text on screen stayed identical, so nothing about the output could show it.
|
|
105
|
-
if (
|
|
106
|
-
existing !== undefined &&
|
|
107
|
-
Object.is(existing.data, data[at]) &&
|
|
108
|
-
!patchedSince(existing)
|
|
109
|
-
) {
|
|
110
|
-
held.delete(key)
|
|
111
|
-
existing.seen = PATCHES.epoch
|
|
112
|
-
survivor[at] = existing
|
|
113
|
-
from[at] = existing.at
|
|
114
|
-
if (existing.at < lastSurvivor) ordered = false
|
|
115
|
-
lastSurvivor = existing.at
|
|
101
|
+
if (existing === undefined) {
|
|
102
|
+
survivor[at] = null
|
|
103
|
+
from[at] = -1
|
|
116
104
|
continue
|
|
117
105
|
}
|
|
118
|
-
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
106
|
+
held.delete(key)
|
|
107
|
+
// 32.67 — A KEPT KEY KEEPS ITS ROW, whatever value now stands under it: a different one
|
|
108
|
+
// is written into the row's item and its bindings update in place, so focus, selection
|
|
109
|
+
// and an open `<details>` stay with nodes that were never replaced. 32.33 — so is the
|
|
110
|
+
// same object a patch wrote inside.
|
|
111
|
+
//
|
|
112
|
+
// `Object.is` RATHER THAN `===`, for NaN: `NaN === NaN` is false, so a row whose value is
|
|
113
|
+
// NaN was written on every reconcile and woke every binding it holds for a value that
|
|
114
|
+
// never moved — and nothing about the output could show it.
|
|
115
|
+
const value = data[at]
|
|
116
|
+
if (!Object.is(existing.data, value) || patchedSince(existing))
|
|
117
|
+
updateRow(existing, value)
|
|
118
|
+
existing.seen = PATCHES.epoch
|
|
119
|
+
survivor[at] = existing
|
|
120
|
+
from[at] = existing.at
|
|
121
|
+
if (existing.at < lastSurvivor) ordered = false
|
|
122
|
+
lastSurvivor = existing.at
|
|
128
123
|
}
|
|
129
124
|
|
|
130
125
|
// THE ROWS THAT NEED NOT MOVE ARE THE LONGEST RUN ALREADY IN ORDER. Every survivor outside it
|
package/src/ui/regions.ts
CHANGED
|
@@ -54,7 +54,7 @@ export function pageRegion(host: Node): Region {
|
|
|
54
54
|
if (close !== null) return { open: node as Comment, close }
|
|
55
55
|
}
|
|
56
56
|
throw new Mismatch(
|
|
57
|
-
"abide: the host holds no page region, so the client and the server disagree about this document's shape
|
|
57
|
+
"abide: the host holds no page region, so the client and the server disagree about this document's shape. RULEBOOK 41.10.",
|
|
58
58
|
)
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -95,7 +95,7 @@ export function fillRegion(
|
|
|
95
95
|
const parent = region.close.parentNode
|
|
96
96
|
if (parent === null)
|
|
97
97
|
throw new Mismatch(
|
|
98
|
-
`abide: this region is not in a document, so the client and the server disagree about this region's shape
|
|
98
|
+
`abide: this region is not in a document, so the client and the server disagree about this region's shape. RULEBOOK 41.10.`,
|
|
99
99
|
)
|
|
100
100
|
emptyRegion(region, parent)
|
|
101
101
|
if (build === undefined) return
|
|
@@ -135,6 +135,12 @@ export function fillEmpty(
|
|
|
135
135
|
*
|
|
136
136
|
* NODE BY NODE WHILE ANYTHING IS LEAVING (32.38), because a node holding a leaving element has to
|
|
137
137
|
* stay where it stands, and only `leave` asks.
|
|
138
|
+
*
|
|
139
|
+
* 32.66 — AND WHAT STAYS IS PUT OUTSIDE THE ANCHORS by moving the OPEN anchor past it, so the
|
|
140
|
+
* region is empty to `isEmptyRegion` and a hydration walk from `open.nextSibling` starts at what
|
|
141
|
+
* the next fill builds. The comment moves rather than the held nodes: it has no box, and moving an
|
|
142
|
+
* element mid-exit would restart a CSS animation on it. Everything left between the anchors after
|
|
143
|
+
* the removal is held, so the move puts all of it before `open`, where it already stood on screen.
|
|
138
144
|
*/
|
|
139
145
|
export function emptyRegion(region: Region, parent: ParentNode): void {
|
|
140
146
|
const { open, close } = region
|
|
@@ -144,6 +150,7 @@ export function emptyRegion(region: Region, parent: ParentNode): void {
|
|
|
144
150
|
parent.lastChild !== close
|
|
145
151
|
) {
|
|
146
152
|
removeUntil(open.nextSibling, close)
|
|
153
|
+
if (open.nextSibling !== close) parent.insertBefore(open, close)
|
|
147
154
|
return
|
|
148
155
|
}
|
|
149
156
|
if (open.nextSibling === close) return
|
package/src/ui/rows.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { REGION_CLOSE, ROW_OPEN } from '#shared/ANCHORS.ts'
|
|
2
|
+
import { moveItem, rowItem } from '#shared/reactive/index.ts'
|
|
2
3
|
import { PATCHES } from '#shared/reactive/PATCHES.ts'
|
|
3
4
|
import { leave } from './leave.ts'
|
|
4
5
|
import { moveNode } from './moveNode.ts'
|
|
@@ -18,13 +19,24 @@ import { EMPTY_SCOPE, type Scope } from './Scope.ts'
|
|
|
18
19
|
export type Row = {
|
|
19
20
|
key: unknown
|
|
20
21
|
/**
|
|
21
|
-
* The value the row
|
|
22
|
+
* The value the row shows.
|
|
22
23
|
*
|
|
23
|
-
* A
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* A KEPT KEY KEEPS ITS ROW (32.67): a different value under it is written here and into the
|
|
25
|
+
* row's bindings rather than remaking the row, so identity decides whether there is anything to
|
|
26
|
+
* write, not whether the row survives.
|
|
26
27
|
*/
|
|
27
28
|
data: unknown
|
|
29
|
+
/**
|
|
30
|
+
* The row's item as a cell (`rowCell`), or null where nothing the row binds reads it through
|
|
31
|
+
* one yet.
|
|
32
|
+
*
|
|
33
|
+
* MADE ONLY WHERE A BINDING NEEDS IT: a slot that reads the item and nothing else is written by
|
|
34
|
+
* `update`, and a binding at the row's top level reads the record until the row's first new
|
|
35
|
+
* item (`updateRow`), so a row that never takes one allocates nothing for 32.67.
|
|
36
|
+
*/
|
|
37
|
+
item: (() => unknown) | null
|
|
38
|
+
/** Rewrites the row's slots that read its item alone (`RowBuilders.update`). */
|
|
39
|
+
update: (row: Row, at: number) => void
|
|
28
40
|
/**
|
|
29
41
|
* The row's first node: its element, or its `ROW_OPEN` anchor where the body has several —
|
|
30
42
|
* the start of a range, not the nodes `make` handed back.
|
|
@@ -43,7 +55,7 @@ export type Row = {
|
|
|
43
55
|
*/
|
|
44
56
|
at: number
|
|
45
57
|
/**
|
|
46
|
-
* The patch epoch the row
|
|
58
|
+
* The patch epoch the row last took its item at (32.33).
|
|
47
59
|
*
|
|
48
60
|
* Its item written past this is content the row never saw, under the same object a kept row is
|
|
49
61
|
* matched by.
|
|
@@ -51,19 +63,28 @@ export type Row = {
|
|
|
51
63
|
seen: number
|
|
52
64
|
}
|
|
53
65
|
|
|
66
|
+
/**
|
|
67
|
+
* A row's builders, each handed the row's RECORD — whose `data` is the item — so the one record
|
|
68
|
+
* carries the item to all four, and a rebuilt row (41.10) writes its new first node back there.
|
|
69
|
+
*/
|
|
54
70
|
export type RowBuilders = {
|
|
55
71
|
/**
|
|
56
72
|
* A row's nodes, BUILT in the document the list stands in — handed over by the reconcile
|
|
57
|
-
* rather than found by the row, which is the one place a row's document is decided.
|
|
73
|
+
* rather than found by the row, which is the one place a row's document is decided. Every slot
|
|
74
|
+
* reading the item alone is written here, before the nodes are inserted.
|
|
58
75
|
*/
|
|
59
|
-
make: (document: Document,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
*/
|
|
64
|
-
mount: (row: Row, item: unknown, at: number) => Scope
|
|
76
|
+
make: (document: Document, row: Row, at: number) => Node[]
|
|
77
|
+
mount: (row: Row, at: number) => Scope
|
|
78
|
+
/** 32.67 — rewrites, from `row.data`, the slots `make` wrote from the item alone. */
|
|
79
|
+
update: (row: Row, at: number) => void
|
|
65
80
|
}
|
|
66
81
|
|
|
82
|
+
/** Answers the builders a row is made and mounted by; called once per row (14.8). */
|
|
83
|
+
export type RowSetUp = (row: Row, at: number) => RowBuilders
|
|
84
|
+
|
|
85
|
+
/** The `update` of a row that has no slot reading its item alone. */
|
|
86
|
+
export function noUpdate(): void {}
|
|
87
|
+
|
|
67
88
|
/**
|
|
68
89
|
* The anchor ending the anchored row whose first node is `first`: the next `ROW_OPEN` or
|
|
69
90
|
* `REGION_CLOSE` at the row's own depth, or null where there is none in this parent.
|
|
@@ -167,37 +188,98 @@ export function replaceRow(row: Row, next: Node[]): void {
|
|
|
167
188
|
|
|
168
189
|
/** A new row, built and inserted before `before`. */
|
|
169
190
|
export function makeRow(
|
|
170
|
-
setUp:
|
|
191
|
+
setUp: RowSetUp,
|
|
171
192
|
parent: Node,
|
|
172
193
|
before: Node,
|
|
173
194
|
key: unknown,
|
|
174
|
-
|
|
195
|
+
data: unknown,
|
|
175
196
|
at: number,
|
|
176
197
|
): Row {
|
|
198
|
+
// `before` STANDS IN FOR THE ROW'S FIRST NODE until `make` hands it over, so the field holds a
|
|
199
|
+
// node for the record's whole life.
|
|
200
|
+
const row = newRow(key, data, before as ChildNode, at)
|
|
177
201
|
// 14.8 — set up ONCE for the row, and the same builders make it and mount it.
|
|
178
|
-
const builders = setUp(
|
|
179
|
-
|
|
202
|
+
const builders = setUp(row, at)
|
|
203
|
+
row.update = builders.update
|
|
204
|
+
const nodes = builders.make(parent.ownerDocument as Document, row, at)
|
|
180
205
|
for (const node of nodes) parent.insertBefore(node, before)
|
|
181
|
-
|
|
206
|
+
row.node = nodes[0] as ChildNode
|
|
207
|
+
row.scope = builders.mount(row, at)
|
|
208
|
+
return row
|
|
182
209
|
}
|
|
183
210
|
|
|
184
211
|
/**
|
|
185
|
-
* A row
|
|
212
|
+
* A row over nodes the server painted, set up and mounted.
|
|
186
213
|
*
|
|
187
|
-
*
|
|
188
|
-
* — a made row and a hydrated one alike. The mount is handed the RECORD, because a row it rebuilds
|
|
189
|
-
* (41.10) has a new first node to write back.
|
|
214
|
+
* 41.8 — the hydration half of `makeRow`: the nodes are already in the document.
|
|
190
215
|
*/
|
|
191
|
-
export function
|
|
192
|
-
|
|
216
|
+
export function paintedRow(
|
|
217
|
+
setUp: RowSetUp,
|
|
193
218
|
key: unknown,
|
|
194
|
-
|
|
219
|
+
data: unknown,
|
|
195
220
|
node: ChildNode,
|
|
196
221
|
at: number,
|
|
197
222
|
): Row {
|
|
198
|
-
const row
|
|
223
|
+
const row = newRow(key, data, node, at)
|
|
224
|
+
const builders = setUp(row, at)
|
|
225
|
+
row.update = builders.update
|
|
226
|
+
row.scope = builders.mount(row, at)
|
|
227
|
+
return row
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* The row's item as a cell its bindings read, made on the first ask (32.67).
|
|
232
|
+
*
|
|
233
|
+
* Asked by a row whose binding reads the item inside a region of its own, or a branch-local setup.
|
|
234
|
+
*/
|
|
235
|
+
export function rowCell(row: Row): () => unknown {
|
|
236
|
+
let item = row.item
|
|
237
|
+
if (item === null) {
|
|
238
|
+
item = rowItem(row.data)
|
|
239
|
+
row.item = item
|
|
240
|
+
}
|
|
241
|
+
return item
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The row's item as a binding at its own top level reads it (`Scope.itemWatch`): off the record
|
|
246
|
+
* until the row has a cell, and through the cell from then on (32.67).
|
|
247
|
+
*/
|
|
248
|
+
export function itemOf(row: Row): unknown {
|
|
249
|
+
const item = row.item
|
|
250
|
+
return item === null ? row.data : item()
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Writes a kept key's new value into its row, which keeps its nodes (32.67).
|
|
255
|
+
*
|
|
256
|
+
* 32.33 — the same object a patch wrote inside is written too, and wakes the row's readers as a
|
|
257
|
+
* different one would.
|
|
258
|
+
*
|
|
259
|
+
* THE CELL IS MADE ON THE FIRST NEW ITEM, not when the row is: a row's item watches read the record
|
|
260
|
+
* until then (`itemOf`), so a row that never takes one allocates nothing for it. Made here, they
|
|
261
|
+
* are rerun to read it, which is also what subscribes them to whatever the new item has them read.
|
|
262
|
+
*/
|
|
263
|
+
export function updateRow(row: Row, data: unknown): void {
|
|
264
|
+
row.data = data
|
|
265
|
+
if (row.item !== null) moveItem(row.item, data)
|
|
266
|
+
else if (row.scope.items !== 0) {
|
|
267
|
+
row.item = rowItem(data)
|
|
268
|
+
row.scope.rerunItems()
|
|
269
|
+
}
|
|
270
|
+
row.update(row, row.at)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* A row's record, its shape fixed once for every path that makes one — a made row and a hydrated
|
|
275
|
+
* one alike.
|
|
276
|
+
*/
|
|
277
|
+
function newRow(key: unknown, data: unknown, node: ChildNode, at: number): Row {
|
|
278
|
+
return {
|
|
199
279
|
key,
|
|
200
|
-
data
|
|
280
|
+
data,
|
|
281
|
+
item: null,
|
|
282
|
+
update: noUpdate,
|
|
201
283
|
node,
|
|
202
284
|
// A `Scope` rather than `undefined` until the mount returns, so the field holds one class
|
|
203
285
|
// for the record's whole life.
|
|
@@ -205,8 +287,6 @@ export function rowOf(
|
|
|
205
287
|
at,
|
|
206
288
|
seen: PATCHES.epoch,
|
|
207
289
|
}
|
|
208
|
-
row.scope = builders.mount(row, item, at)
|
|
209
|
-
return row
|
|
210
290
|
}
|
|
211
291
|
|
|
212
292
|
/**
|