@agentshouse/mdruntime 0.1.0-cedb03eaa48b6 → 0.1.0-cedd665dffa4c
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 +24 -19
- package/dist/acceptance.d.ts +3 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +299 -0
- package/dist/act-lanes.d.ts +30 -0
- package/dist/act-lanes.d.ts.map +1 -0
- package/dist/act-lanes.js +225 -0
- package/dist/actions.d.ts +26 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +302 -0
- package/dist/adapter.d.ts +173 -125
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +6 -10
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +35 -41
- package/dist/binary.d.ts +0 -5
- package/dist/binary.d.ts.map +1 -1
- package/dist/binary.js +1 -1
- package/dist/bootstrap.d.ts +30 -11
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +309 -113
- package/dist/cell.d.ts +6 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +9 -0
- package/dist/chain.d.ts +12 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +64 -0
- package/dist/change-set.d.ts +13 -16
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +17 -89
- package/dist/change.d.ts +36 -1
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +17 -3
- package/dist/chat-types.d.ts +3 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +11 -0
- package/dist/client.d.ts +37 -26
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +113 -23
- package/dist/collection.d.ts +32 -21
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +53 -318
- package/dist/compile.d.ts +18 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +723 -0
- package/dist/connection.d.ts +7 -137
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +110 -3602
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/{chat/context.js → context.js} +2 -5
- package/dist/conversation-live.d.ts +150 -0
- package/dist/conversation-live.d.ts.map +1 -0
- package/dist/conversation-live.js +259 -0
- package/dist/conversation-row.d.ts +40 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +66 -0
- package/dist/conversation.d.ts +75 -49
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +1029 -806
- package/dist/declaration.d.ts +10 -0
- package/dist/declaration.d.ts.map +1 -0
- package/dist/declaration.js +24 -0
- package/dist/digest.d.ts +7 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +113 -0
- package/dist/discovery.d.ts +10 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +150 -0
- package/dist/durability.d.ts +20 -4
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +9 -0
- package/dist/entry.d.ts +5 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +33 -29
- package/dist/expectation.d.ts +26 -13
- package/dist/expectation.d.ts.map +1 -1
- package/dist/expectation.js +72 -19
- package/dist/failure.d.ts +3 -0
- package/dist/failure.d.ts.map +1 -1
- package/dist/failure.js +6 -0
- package/dist/figures.d.ts +49 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +199 -0
- package/dist/file.d.ts +2 -19
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +8 -122
- package/dist/holdings.d.ts +29 -0
- package/dist/holdings.d.ts.map +1 -0
- package/dist/holdings.js +95 -0
- package/dist/host.d.ts +21 -8
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +119 -51
- package/dist/identity.d.ts +0 -2
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -6
- package/dist/index.d.ts +41 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -4
- package/dist/install.d.ts +60 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +537 -0
- package/dist/lifecycle.d.ts +7 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +278 -0
- package/dist/listing.d.ts +52 -0
- package/dist/listing.d.ts.map +1 -0
- package/dist/listing.js +152 -0
- package/dist/live.d.ts +25 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +206 -0
- package/dist/loaded.d.ts +5 -0
- package/dist/loaded.d.ts.map +1 -0
- package/dist/loaded.js +40 -0
- package/dist/locks.d.ts +7 -0
- package/dist/locks.d.ts.map +1 -0
- package/dist/locks.js +32 -0
- package/dist/lost.d.ts +5 -0
- package/dist/lost.d.ts.map +1 -0
- package/dist/lost.js +49 -0
- package/dist/media.d.ts +13 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +269 -0
- package/dist/memory.d.ts +19 -7
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +281 -118
- package/dist/messages.d.ts +58 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +162 -0
- package/dist/model.d.ts +8 -11
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +6 -23
- package/dist/models.d.ts +10 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +153 -0
- package/dist/name.d.ts +4 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +122 -0
- package/dist/observation.d.ts +38 -10
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +232 -44
- package/dist/opened.d.ts +22 -0
- package/dist/opened.d.ts.map +1 -0
- package/dist/opened.js +107 -0
- package/dist/opening.d.ts +4 -0
- package/dist/opening.d.ts.map +1 -0
- package/dist/opening.js +53 -0
- package/dist/outcome.d.ts +51 -9
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +62 -2
- package/dist/overlay.d.ts +8 -6
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +121 -182
- package/dist/page-metadata.d.ts +8 -0
- package/dist/page-metadata.d.ts.map +1 -0
- package/dist/page-metadata.js +19 -0
- package/dist/parts.d.ts +4 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +13 -0
- package/dist/paths.d.ts +2 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +26 -0
- package/dist/preparation.d.ts +41 -0
- package/dist/preparation.d.ts.map +1 -0
- package/dist/preparation.js +314 -0
- package/dist/presence.d.ts +58 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +231 -0
- package/dist/queries.d.ts +16 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +308 -0
- package/dist/query.d.ts +21 -207
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -493
- package/dist/{chat/questions.d.ts → questions.d.ts} +5 -7
- package/dist/questions.d.ts.map +1 -0
- package/dist/{chat/questions.js → questions.js} +11 -7
- package/dist/queue.d.ts +40 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +480 -0
- package/dist/reach.d.ts +21 -11
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +342 -112
- package/dist/react.d.ts +17 -3
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +33 -1
- package/dist/{chat/read.d.ts → read.d.ts} +2 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/{chat/read.js → read.js} +4 -0
- package/dist/readiness.d.ts +22 -20
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +5 -13
- package/dist/reads.d.ts +38 -10
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +163 -83
- package/dist/recovery.d.ts +5 -2
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +65 -8
- package/dist/refresh.d.ts +18 -15
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +145 -60
- package/dist/refusal.d.ts +5 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +55 -0
- package/dist/replica.d.ts +49 -36
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +322 -198
- package/dist/retried.d.ts +30 -0
- package/dist/retried.d.ts.map +1 -0
- package/dist/retried.js +72 -0
- package/dist/room-draft.d.ts +55 -13
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +416 -122
- package/dist/room-drafts.d.ts +24 -0
- package/dist/room-drafts.d.ts.map +1 -0
- package/dist/room-drafts.js +220 -0
- package/dist/rows.d.ts +32 -31
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +59 -124
- package/dist/runtime.d.ts +34 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/save.d.ts +43 -49
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +736 -302
- package/dist/saves.d.ts +32 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +426 -0
- package/dist/search.d.ts +12 -95
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -266
- package/dist/seed.d.ts +11 -2
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +71 -1
- package/dist/shared.d.ts +6 -7
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +75 -104
- package/dist/shown.d.ts +33 -0
- package/dist/shown.d.ts.map +1 -0
- package/dist/shown.js +309 -0
- package/dist/socket/admission.d.ts +7 -0
- package/dist/socket/admission.d.ts.map +1 -0
- package/dist/socket/admission.js +39 -0
- package/dist/socket/answers.d.ts +6 -0
- package/dist/socket/answers.d.ts.map +1 -0
- package/dist/socket/answers.js +20 -0
- package/dist/socket/lanes.d.ts +28 -0
- package/dist/socket/lanes.d.ts.map +1 -0
- package/dist/socket/lanes.js +103 -0
- package/dist/socket/reads.d.ts +10 -0
- package/dist/socket/reads.d.ts.map +1 -0
- package/dist/socket/reads.js +31 -0
- package/dist/socket/session.d.ts +38 -0
- package/dist/socket/session.d.ts.map +1 -0
- package/dist/socket/session.js +23 -0
- package/dist/socket.d.ts +67 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +164 -0
- package/dist/source.d.ts +59 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +93 -0
- package/dist/status.d.ts +4 -5
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -7
- package/dist/store/installs.d.ts +30 -0
- package/dist/store/installs.d.ts.map +1 -0
- package/dist/store/installs.js +40 -0
- package/dist/store/readiness.d.ts +11 -0
- package/dist/store/readiness.d.ts.map +1 -0
- package/dist/store/readiness.js +68 -0
- package/dist/store/records.d.ts +217 -0
- package/dist/store/records.d.ts.map +1 -0
- package/dist/store/records.js +464 -0
- package/dist/store/room-held.d.ts +8 -0
- package/dist/store/room-held.d.ts.map +1 -0
- package/dist/store/room-held.js +17 -0
- package/dist/store/rooms-shown.d.ts +8 -0
- package/dist/store/rooms-shown.d.ts.map +1 -0
- package/dist/store/rooms-shown.js +13 -0
- package/dist/store/space.d.ts +11 -0
- package/dist/store/space.d.ts.map +1 -0
- package/dist/store/space.js +41 -0
- package/dist/store/watchers.d.ts +17 -0
- package/dist/store/watchers.d.ts.map +1 -0
- package/dist/store/watchers.js +56 -0
- package/dist/store/writes.d.ts +24 -0
- package/dist/store/writes.d.ts.map +1 -0
- package/dist/store/writes.js +125 -0
- package/dist/store.d.ts +114 -163
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +163 -750
- package/dist/stored.d.ts +167 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +703 -0
- package/dist/surface.d.ts +89 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +222 -0
- package/dist/sync.d.ts +19 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +535 -0
- package/dist/tables.d.ts +419 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +758 -0
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +128 -0
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/turn.d.ts +4 -2
- package/dist/turn.d.ts.map +1 -1
- package/dist/turn.js +46 -22
- package/dist/validation.d.ts +29 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +98 -0
- package/dist/windows.d.ts +1 -16
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +2 -79
- package/dist/wire.d.ts +74 -9
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +26 -6
- package/package.json +19 -19
- package/AGENTS.md +0 -305
- package/dist/attempt.d.ts +0 -16
- package/dist/attempt.d.ts.map +0 -1
- package/dist/attempt.js +0 -70
- package/dist/chat/acts.d.ts +0 -33
- package/dist/chat/acts.d.ts.map +0 -1
- package/dist/chat/acts.js +0 -36
- package/dist/chat/context.d.ts +0 -3
- package/dist/chat/context.d.ts.map +0 -1
- package/dist/chat/earlier.d.ts +0 -10
- package/dist/chat/earlier.d.ts.map +0 -1
- package/dist/chat/earlier.js +0 -54
- package/dist/chat/input.d.ts +0 -9
- package/dist/chat/input.d.ts.map +0 -1
- package/dist/chat/input.js +0 -99
- package/dist/chat/kit.d.ts +0 -61
- package/dist/chat/kit.d.ts.map +0 -1
- package/dist/chat/kit.js +0 -123
- package/dist/chat/lasting.d.ts +0 -6
- package/dist/chat/lasting.d.ts.map +0 -1
- package/dist/chat/lasting.js +0 -19
- package/dist/chat/list.d.ts +0 -27
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -99
- package/dist/chat/markdown.d.ts +0 -20
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -188
- package/dist/chat/message.d.ts +0 -6
- package/dist/chat/message.d.ts.map +0 -1
- package/dist/chat/message.js +0 -192
- package/dist/chat/messages.d.ts +0 -22
- package/dist/chat/messages.d.ts.map +0 -1
- package/dist/chat/messages.js +0 -155
- package/dist/chat/name.d.ts +0 -6
- package/dist/chat/name.d.ts.map +0 -1
- package/dist/chat/name.js +0 -37
- package/dist/chat/opened.d.ts +0 -11
- package/dist/chat/opened.d.ts.map +0 -1
- package/dist/chat/opened.js +0 -17
- package/dist/chat/overlay.d.ts +0 -31
- package/dist/chat/overlay.d.ts.map +0 -1
- package/dist/chat/overlay.js +0 -97
- package/dist/chat/parts.d.ts +0 -57
- package/dist/chat/parts.d.ts.map +0 -1
- package/dist/chat/parts.js +0 -119
- package/dist/chat/process.d.ts +0 -20
- package/dist/chat/process.d.ts.map +0 -1
- package/dist/chat/process.js +0 -32
- package/dist/chat/provider.d.ts +0 -63
- package/dist/chat/provider.d.ts.map +0 -1
- package/dist/chat/provider.js +0 -628
- package/dist/chat/question.d.ts +0 -9
- package/dist/chat/question.d.ts.map +0 -1
- package/dist/chat/question.js +0 -69
- package/dist/chat/questions.d.ts.map +0 -1
- package/dist/chat/read.d.ts.map +0 -1
- package/dist/chat/ready.d.ts +0 -34
- package/dist/chat/ready.d.ts.map +0 -1
- package/dist/chat/ready.js +0 -91
- package/dist/chat/style.d.ts +0 -4
- package/dist/chat/style.d.ts.map +0 -1
- package/dist/chat/style.js +0 -302
- package/dist/chat.d.ts +0 -14
- package/dist/chat.d.ts.map +0 -1
- package/dist/chat.js +0 -8
- package/dist/fence.d.ts +0 -6
- package/dist/fence.d.ts.map +0 -1
- package/dist/fence.js +0 -10
- package/dist/log.d.ts +0 -5
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js +0 -14
- package/dist/read-side.d.ts +0 -27
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -824
package/dist/room-draft.js
CHANGED
|
@@ -1,60 +1,70 @@
|
|
|
1
|
-
import { apply,
|
|
1
|
+
import { apply, create, documentValue, equalValue, parse, serialize, } from '@agentshouse/mdmodel';
|
|
2
|
+
import { definitionsAt, governing } from './collection.js';
|
|
2
3
|
import { runtimeError } from './failure.js';
|
|
3
|
-
import {
|
|
4
|
+
import { sha256 } from './digest.js';
|
|
5
|
+
import { declaredType } from './outcome.js';
|
|
4
6
|
import { binaryLocalId } from './identity.js';
|
|
5
7
|
import { normalize } from './paths.js';
|
|
6
|
-
export function returnedBy(
|
|
7
|
-
return { kind, code:
|
|
8
|
+
export function returnedBy() {
|
|
9
|
+
return { kind: 'withdrawn', code: 'withdrawn', fields: {}, retryable: false };
|
|
8
10
|
}
|
|
9
11
|
export function staleWrite(current) {
|
|
10
|
-
return { outcome: 'stale',
|
|
12
|
+
return { outcome: 'stale', current };
|
|
11
13
|
}
|
|
12
|
-
function malformed() {
|
|
13
|
-
throw runtimeError('room-draft-malformed');
|
|
14
|
+
function malformed(at, needs) {
|
|
15
|
+
throw runtimeError('room-draft-malformed', at === undefined ? 'room-draft-malformed' : `room-draft-malformed at ${at}: ${needs}`);
|
|
14
16
|
}
|
|
15
17
|
function plain(value) {
|
|
16
18
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
17
19
|
}
|
|
18
|
-
function text(value) {
|
|
19
|
-
return typeof value === 'string' ? value : malformed();
|
|
20
|
+
function text(value, at) {
|
|
21
|
+
return typeof value === 'string' ? value : malformed(at, 'text');
|
|
20
22
|
}
|
|
21
|
-
function optionalText(value) {
|
|
22
|
-
return value === undefined ? undefined : text(value);
|
|
23
|
+
function optionalText(value, at) {
|
|
24
|
+
return value === undefined ? undefined : text(value, at);
|
|
23
25
|
}
|
|
24
|
-
function markdownBase(value) {
|
|
25
|
-
return value === null ? null : optionalText(value);
|
|
26
|
+
function markdownBase(value, at) {
|
|
27
|
+
return value === null ? null : optionalText(value, at);
|
|
26
28
|
}
|
|
27
|
-
function entries(value, each) {
|
|
29
|
+
function entries(value, at, each) {
|
|
28
30
|
if (!plain(value))
|
|
29
|
-
malformed();
|
|
31
|
+
malformed(at, 'an object of named values');
|
|
30
32
|
const read = {};
|
|
31
33
|
for (const [name, item] of Object.entries(value))
|
|
32
|
-
read[name] = each(item);
|
|
34
|
+
read[name] = each(item, `${at}.${name}`);
|
|
33
35
|
return read;
|
|
34
36
|
}
|
|
35
|
-
function
|
|
37
|
+
function documentValueAt(item, at) {
|
|
38
|
+
return documentValue(item) ? item : malformed(at, 'a document value');
|
|
39
|
+
}
|
|
40
|
+
function fieldValue(value, at) {
|
|
36
41
|
if (value === null)
|
|
37
42
|
return null;
|
|
38
|
-
if (!plain(value) || !Object.hasOwn(value, 'value') || !
|
|
39
|
-
malformed();
|
|
43
|
+
if (!plain(value) || !Object.hasOwn(value, 'value') || !documentValue(value.value)) {
|
|
44
|
+
malformed(at, '{ value } with a document value, or null where the document lacks it');
|
|
40
45
|
}
|
|
41
46
|
return { value: value.value };
|
|
42
47
|
}
|
|
43
|
-
function textPart(value) {
|
|
48
|
+
function textPart(value, at) {
|
|
44
49
|
if (!plain(value))
|
|
45
|
-
malformed();
|
|
46
|
-
const base = optionalText(value.base);
|
|
47
|
-
return { value: text(value.value), ...(base === undefined ? {} : { base }) };
|
|
50
|
+
malformed(at, '{ value, base }');
|
|
51
|
+
const base = optionalText(value.base, `${at}.base`);
|
|
52
|
+
return { value: text(value.value, `${at}.value`), ...(base === undefined ? {} : { base }) };
|
|
48
53
|
}
|
|
49
|
-
function creationOf(value) {
|
|
54
|
+
function creationOf(value, at) {
|
|
50
55
|
if (!plain(value))
|
|
51
|
-
malformed();
|
|
56
|
+
malformed(at, '{ type, fields, sections }, or { markdown }');
|
|
52
57
|
if (Object.hasOwn(value, 'markdown'))
|
|
53
|
-
return { markdown: text(value.markdown) };
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
return { markdown: text(value.markdown, `${at}.markdown`) };
|
|
59
|
+
if (typeof value.type !== 'string')
|
|
60
|
+
malformed(`${at}.type`, 'a type name, or markdown in place of type, fields and sections');
|
|
61
|
+
return {
|
|
62
|
+
type: value.type,
|
|
63
|
+
fields: entries(value.fields, `${at}.fields`, documentValueAt),
|
|
64
|
+
sections: entries(value.sections, `${at}.sections`, text),
|
|
65
|
+
};
|
|
56
66
|
}
|
|
57
|
-
const PART_NAMES =
|
|
67
|
+
const PART_NAMES = [
|
|
58
68
|
'fields',
|
|
59
69
|
'sections',
|
|
60
70
|
'preamble',
|
|
@@ -63,47 +73,57 @@ const PART_NAMES = new Set([
|
|
|
63
73
|
'move',
|
|
64
74
|
'removal',
|
|
65
75
|
'file',
|
|
66
|
-
]
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
];
|
|
77
|
+
const NAMED_PARTS = `a part named ${PART_NAMES.slice(0, -1).join(', ')} or ${PART_NAMES.slice(-1).join('')}`;
|
|
78
|
+
export function readParts(value, path) {
|
|
79
|
+
if (!plain(value))
|
|
80
|
+
malformed(path, 'an object of parts');
|
|
81
|
+
const unknown = Object.keys(value).find((name) => !PART_NAMES.includes(name));
|
|
82
|
+
if (unknown !== undefined)
|
|
83
|
+
malformed(`${path} ${unknown}`, NAMED_PARTS);
|
|
70
84
|
const parts = {};
|
|
71
85
|
if (value.fields !== undefined) {
|
|
72
|
-
parts.fields = entries(value.fields, (item) => {
|
|
73
|
-
if (!plain(item) || !Object.hasOwn(item, 'value') || !
|
|
74
|
-
malformed();
|
|
86
|
+
parts.fields = entries(value.fields, `${path} fields`, (item, at) => {
|
|
87
|
+
if (!plain(item) || !Object.hasOwn(item, 'value') || !documentValue(item.value)) {
|
|
88
|
+
malformed(at, '{ value, base } with a document value');
|
|
75
89
|
}
|
|
76
90
|
return item.base === undefined
|
|
77
91
|
? { value: item.value }
|
|
78
|
-
: { value: item.value, base: fieldValue(item.base) };
|
|
92
|
+
: { value: item.value, base: fieldValue(item.base, `${at}.base`) };
|
|
79
93
|
});
|
|
80
94
|
}
|
|
81
95
|
if (value.sections !== undefined)
|
|
82
|
-
parts.sections = entries(value.sections, textPart);
|
|
96
|
+
parts.sections = entries(value.sections, `${path} sections`, textPart);
|
|
83
97
|
if (value.preamble !== undefined)
|
|
84
|
-
parts.preamble = textPart(value.preamble);
|
|
98
|
+
parts.preamble = textPart(value.preamble, `${path} preamble`);
|
|
85
99
|
if (value.markdown !== undefined)
|
|
86
|
-
parts.markdown = textPart(value.markdown);
|
|
100
|
+
parts.markdown = textPart(value.markdown, `${path} markdown`);
|
|
87
101
|
if (value.creation !== undefined)
|
|
88
|
-
parts.creation = creationOf(value.creation);
|
|
102
|
+
parts.creation = creationOf(value.creation, `${path} creation`);
|
|
89
103
|
if (value.move !== undefined) {
|
|
90
104
|
if (!plain(value.move))
|
|
91
|
-
malformed();
|
|
92
|
-
const base = markdownBase(value.move.base);
|
|
93
|
-
|
|
105
|
+
malformed(`${path} move`, '{ to, room, base }');
|
|
106
|
+
const base = markdownBase(value.move.base, `${path} move.base`);
|
|
107
|
+
const room = optionalText(value.move.room, `${path} move.room`);
|
|
108
|
+
parts.move = {
|
|
109
|
+
to: text(value.move.to, `${path} move.to`),
|
|
110
|
+
...(room === undefined ? {} : { room }),
|
|
111
|
+
...(base === undefined ? {} : { base }),
|
|
112
|
+
};
|
|
94
113
|
}
|
|
95
114
|
if (value.removal !== undefined) {
|
|
96
115
|
if (!plain(value.removal))
|
|
97
|
-
malformed();
|
|
98
|
-
const base = markdownBase(value.removal.base);
|
|
116
|
+
malformed(`${path} removal`, '{ base }');
|
|
117
|
+
const base = markdownBase(value.removal.base, `${path} removal.base`);
|
|
99
118
|
parts.removal = base === undefined ? {} : { base };
|
|
100
119
|
}
|
|
101
120
|
if (value.file !== undefined) {
|
|
102
121
|
if (!plain(value.file) || !(value.file.blob instanceof Blob))
|
|
103
|
-
malformed();
|
|
122
|
+
malformed(`${path} file`, '{ blob, base } with a Blob');
|
|
104
123
|
if (Object.keys(value).length > 1)
|
|
105
124
|
throw runtimeError('room-draft-file-exclusive');
|
|
106
|
-
|
|
125
|
+
const base = markdownBase(value.file.base, `${path} file.base`);
|
|
126
|
+
parts.file = base === undefined ? { blob: value.file.blob } : { blob: value.file.blob, base };
|
|
107
127
|
}
|
|
108
128
|
return parts;
|
|
109
129
|
}
|
|
@@ -120,11 +140,51 @@ function kept(prior, base) {
|
|
|
120
140
|
throw runtimeError('room-draft-base-missing');
|
|
121
141
|
return base;
|
|
122
142
|
}
|
|
143
|
+
function movePart(current, move) {
|
|
144
|
+
return {
|
|
145
|
+
to: move.to,
|
|
146
|
+
...(move.room === undefined ? {} : { room: move.room }),
|
|
147
|
+
base: kept(current, move.base),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
123
150
|
function editsText(parts) {
|
|
124
151
|
return (parts.preamble !== undefined ||
|
|
125
152
|
named(parts.fields).length > 0 ||
|
|
126
153
|
named(parts.sections).length > 0);
|
|
127
154
|
}
|
|
155
|
+
function partNames(parts) {
|
|
156
|
+
const names = [];
|
|
157
|
+
for (const [name, part] of Object.entries(parts)) {
|
|
158
|
+
if (name === 'preamble' || name === 'markdown')
|
|
159
|
+
names.push(name);
|
|
160
|
+
else if ((name === 'fields' || name === 'sections') && plain(part))
|
|
161
|
+
names.push(...Object.keys(part).map((one) => `${name}/${one}`));
|
|
162
|
+
else
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
return names.sort().join('\u0000');
|
|
166
|
+
}
|
|
167
|
+
function withBaseOf(prior, part) {
|
|
168
|
+
return plain(part) && plain(prior) && Object.hasOwn(prior, 'base')
|
|
169
|
+
? { ...part, base: prior.base }
|
|
170
|
+
: part;
|
|
171
|
+
}
|
|
172
|
+
export function gatheredParts(earlier, later) {
|
|
173
|
+
if (!plain(earlier) || !plain(later))
|
|
174
|
+
return null;
|
|
175
|
+
const named = partNames(earlier);
|
|
176
|
+
if (named === null || named !== partNames(later))
|
|
177
|
+
return null;
|
|
178
|
+
return Object.fromEntries(Object.entries(later).map(([name, part]) => [
|
|
179
|
+
name,
|
|
180
|
+
name === 'fields' || name === 'sections'
|
|
181
|
+
? Object.fromEntries(Object.entries(part).map(([one, value]) => [
|
|
182
|
+
one,
|
|
183
|
+
withBaseOf(earlier[name][one], value),
|
|
184
|
+
]))
|
|
185
|
+
: withBaseOf(earlier[name], part),
|
|
186
|
+
]));
|
|
187
|
+
}
|
|
128
188
|
export function held(current, parts, file) {
|
|
129
189
|
if (parts.markdown !== undefined && editsText(parts)) {
|
|
130
190
|
throw runtimeError('room-draft-markdown-exclusive');
|
|
@@ -144,9 +204,7 @@ export function held(current, parts, file) {
|
|
|
144
204
|
}
|
|
145
205
|
return {
|
|
146
206
|
file: current.file,
|
|
147
|
-
...(parts.move === undefined
|
|
148
|
-
? {}
|
|
149
|
-
: { move: { to: parts.move.to, base: kept(current.move, parts.move.base) } }),
|
|
207
|
+
...(parts.move === undefined ? {} : { move: movePart(current.move, parts.move) }),
|
|
150
208
|
...(parts.removal === undefined
|
|
151
209
|
? {}
|
|
152
210
|
: { removal: { base: kept(current.removal, parts.removal.base) } }),
|
|
@@ -181,9 +239,8 @@ export function held(current, parts, file) {
|
|
|
181
239
|
}
|
|
182
240
|
if (parts.creation !== undefined)
|
|
183
241
|
next.creation = parts.creation;
|
|
184
|
-
if (parts.move !== undefined)
|
|
185
|
-
next.move =
|
|
186
|
-
}
|
|
242
|
+
if (parts.move !== undefined)
|
|
243
|
+
next.move = movePart(current?.move, parts.move);
|
|
187
244
|
if (parts.removal !== undefined) {
|
|
188
245
|
next.removal = { base: kept(current?.removal, parts.removal.base) };
|
|
189
246
|
}
|
|
@@ -200,8 +257,10 @@ export function underneath(parts, path, visible) {
|
|
|
200
257
|
const markdown = visible?.documents[path] ?? null;
|
|
201
258
|
const document = visible?.collection.document(path);
|
|
202
259
|
const report = {};
|
|
260
|
+
const unread = document?.type !== undefined &&
|
|
261
|
+
governing(visible.collection.composition, path).status === 'unavailable';
|
|
203
262
|
const fields = {};
|
|
204
|
-
for (const [name, part] of named(parts.fields)) {
|
|
263
|
+
for (const [name, part] of unread ? [] : named(parts.fields)) {
|
|
205
264
|
const current = document !== undefined && Object.hasOwn(document.fields, name)
|
|
206
265
|
? { value: document.fields[name] }
|
|
207
266
|
: null;
|
|
@@ -211,7 +270,7 @@ export function underneath(parts, path, visible) {
|
|
|
211
270
|
if (Object.keys(fields).length > 0)
|
|
212
271
|
report.fields = fields;
|
|
213
272
|
const sections = {};
|
|
214
|
-
for (const [name, part] of named(parts.sections)) {
|
|
273
|
+
for (const [name, part] of unread ? [] : named(parts.sections)) {
|
|
215
274
|
const current = document !== undefined && Object.hasOwn(document.sections, name)
|
|
216
275
|
? document.sections[name]
|
|
217
276
|
: null;
|
|
@@ -221,8 +280,9 @@ export function underneath(parts, path, visible) {
|
|
|
221
280
|
if (Object.keys(sections).length > 0)
|
|
222
281
|
report.sections = sections;
|
|
223
282
|
const preamble = document?.preamble ?? null;
|
|
224
|
-
if (parts.preamble !== undefined && preamble !== parts.preamble.base)
|
|
283
|
+
if (!unread && parts.preamble !== undefined && preamble !== parts.preamble.base) {
|
|
225
284
|
report.preamble = preamble;
|
|
285
|
+
}
|
|
226
286
|
if (parts.markdown !== undefined && markdown !== parts.markdown.base)
|
|
227
287
|
report.markdown = markdown;
|
|
228
288
|
if (parts.creation !== undefined && markdown !== null)
|
|
@@ -238,33 +298,253 @@ export function underneath(parts, path, visible) {
|
|
|
238
298
|
}
|
|
239
299
|
return report;
|
|
240
300
|
}
|
|
241
|
-
const UNTYPED_MEDIA_TYPE = 'application/octet-stream';
|
|
242
301
|
export async function heldFile(blob, base) {
|
|
243
|
-
const bytes = await blob.arrayBuffer();
|
|
244
302
|
return {
|
|
245
|
-
blob,
|
|
246
303
|
localId: binaryLocalId(),
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
304
|
+
...(blob instanceof File ? { name: blob.name } : {}),
|
|
305
|
+
byteLength: blob.size,
|
|
306
|
+
mediaType: declaredType(blob),
|
|
307
|
+
sha256: await sha256(blob),
|
|
250
308
|
base,
|
|
251
309
|
};
|
|
252
310
|
}
|
|
253
311
|
export function binaryBase(visible, path) {
|
|
254
|
-
|
|
312
|
+
const binary = visible?.binaries[path];
|
|
313
|
+
if (binary === undefined)
|
|
314
|
+
return null;
|
|
315
|
+
return visible?.revisions[path] ?? (binary.state === 'pending' ? binary.localId : null);
|
|
255
316
|
}
|
|
256
|
-
export function changedParts(path,
|
|
317
|
+
export function changedParts(path, parts, visible) {
|
|
318
|
+
const report = underneath(parts, path, visible);
|
|
319
|
+
const made = parts.file?.base === null;
|
|
257
320
|
return [
|
|
258
|
-
...(report.creation === undefined ? [] : [{ path, part: 'creation' }]),
|
|
259
321
|
...named(report.fields).map(([name]) => ({ path, part: 'field', name })),
|
|
260
322
|
...named(report.sections).map(([name]) => ({ path, part: 'section', name })),
|
|
261
323
|
...(report.preamble === undefined ? [] : [{ path, part: 'preamble' }]),
|
|
262
324
|
...(report.markdown === undefined ? [] : [{ path, part: 'markdown' }]),
|
|
263
325
|
...(report.move === undefined ? [] : [{ path, part: 'move' }]),
|
|
264
326
|
...(report.removal === undefined ? [] : [{ path, part: 'removal' }]),
|
|
265
|
-
...(report.file === undefined ? [] : [{ path, part: 'file' }]),
|
|
327
|
+
...(report.file === undefined || made ? [] : [{ path, part: 'file' }]),
|
|
266
328
|
];
|
|
267
329
|
}
|
|
330
|
+
function marksOf(fields, sections, rest) {
|
|
331
|
+
return {
|
|
332
|
+
...(Object.keys(fields).length === 0 ? {} : { fields }),
|
|
333
|
+
...(Object.keys(sections).length === 0 ? {} : { sections }),
|
|
334
|
+
...(rest.preamble === undefined ? {} : { preamble: rest.preamble }),
|
|
335
|
+
...(rest.markdown === undefined ? {} : { markdown: rest.markdown }),
|
|
336
|
+
...(rest.file === undefined ? {} : { file: rest.file }),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
export function marksOver(kept, under) {
|
|
340
|
+
return marksOf({ ...under.fields, ...kept.fields }, { ...under.sections, ...kept.sections }, {
|
|
341
|
+
preamble: kept.preamble ?? under.preamble,
|
|
342
|
+
markdown: kept.markdown ?? under.markdown,
|
|
343
|
+
file: kept.file ?? under.file,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
export function heldMarks(marks, parts) {
|
|
347
|
+
const whole = parts.markdown !== undefined;
|
|
348
|
+
const heldIn = (record, part) => Object.fromEntries(named(record).filter(([name]) => whole || own(part, name) !== undefined));
|
|
349
|
+
return marksOf(heldIn(marks.fields, parts.fields), heldIn(marks.sections, parts.sections), {
|
|
350
|
+
preamble: whole || parts.preamble !== undefined ? marks.preamble : undefined,
|
|
351
|
+
markdown: whole ? marks.markdown : undefined,
|
|
352
|
+
file: parts.file === undefined ? undefined : marks.file,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
function followedBy(first, then) {
|
|
356
|
+
const kept = first.replace(/(?:\r?\n)+$/u, '');
|
|
357
|
+
return kept.trim() === '' ? then : `${kept}\n\n${then.replace(/^(?:\r?\n)+/u, '')}`;
|
|
358
|
+
}
|
|
359
|
+
function bothSides(current, value) {
|
|
360
|
+
return lineEnded(current) === lineEnded(value) ? value : followedBy(current, value);
|
|
361
|
+
}
|
|
362
|
+
export function partsBetween(path, before, after) {
|
|
363
|
+
const changes = [];
|
|
364
|
+
for (const name of new Set([...Object.keys(before.fields), ...Object.keys(after.fields)])) {
|
|
365
|
+
const value = own(after.fields, name);
|
|
366
|
+
if (!equalValue(own(before.fields, name), value)) {
|
|
367
|
+
changes.push({ kind: 'field', path, name, value });
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (after.preamble !== before.preamble) {
|
|
371
|
+
changes.push({ kind: 'preamble', path, value: after.preamble });
|
|
372
|
+
}
|
|
373
|
+
for (const [name, value] of Object.entries(after.sections)) {
|
|
374
|
+
if (own(before.sections, name) !== value)
|
|
375
|
+
changes.push({ kind: 'section', path, name, value });
|
|
376
|
+
}
|
|
377
|
+
return changes;
|
|
378
|
+
}
|
|
379
|
+
export function applyParts(document, changes, definition) {
|
|
380
|
+
const parts = new Map();
|
|
381
|
+
for (const change of changes) {
|
|
382
|
+
if (change.kind === 'field')
|
|
383
|
+
parts.set(`field ${change.name}`, {
|
|
384
|
+
kind: 'field',
|
|
385
|
+
name: change.name,
|
|
386
|
+
value: change.value,
|
|
387
|
+
prior: own(document.fields, change.name),
|
|
388
|
+
});
|
|
389
|
+
if (change.kind === 'preamble')
|
|
390
|
+
parts.set('preamble', { kind: 'preamble', value: change.value, prior: document.preamble });
|
|
391
|
+
if (change.kind === 'section')
|
|
392
|
+
parts.set(`section ${change.name}`, {
|
|
393
|
+
kind: 'section',
|
|
394
|
+
name: change.name,
|
|
395
|
+
value: change.value,
|
|
396
|
+
prior: own(document.sections, change.name),
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
if (parts.size === 0)
|
|
400
|
+
return { outcome: 'applied', document };
|
|
401
|
+
return apply(document, [...parts.values()], definition);
|
|
402
|
+
}
|
|
403
|
+
function wholeJoined(part, current, path, composition, change) {
|
|
404
|
+
const definitions = definitionsAt(composition, path);
|
|
405
|
+
const read = (text) => {
|
|
406
|
+
const parsed = parse(text, path, definitions);
|
|
407
|
+
return parsed.ok ? parsed.document : undefined;
|
|
408
|
+
};
|
|
409
|
+
const base = read(part.base);
|
|
410
|
+
const mine = read(part.value);
|
|
411
|
+
const now = read(current);
|
|
412
|
+
if (base === undefined ||
|
|
413
|
+
mine === undefined ||
|
|
414
|
+
now === undefined ||
|
|
415
|
+
mine.type !== base.type ||
|
|
416
|
+
now.type !== base.type ||
|
|
417
|
+
Object.keys(base.sections).some((name) => !Object.hasOwn(mine.sections, name))) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
const definition = definitions(base.type);
|
|
421
|
+
const changes = partsBetween(path, base, mine);
|
|
422
|
+
const again = applyParts(base, changes, definition);
|
|
423
|
+
if (again.outcome !== 'applied' || serialize(again.document) !== part.value)
|
|
424
|
+
return null;
|
|
425
|
+
const fields = {};
|
|
426
|
+
const sections = {};
|
|
427
|
+
let preamble;
|
|
428
|
+
const over = [];
|
|
429
|
+
for (const one of changes) {
|
|
430
|
+
if (one.kind === 'field') {
|
|
431
|
+
const held = own(now.fields, one.name);
|
|
432
|
+
if (!equalValue(held, own(base.fields, one.name)) && !equalValue(held, one.value)) {
|
|
433
|
+
fields[one.name] = { current: held === undefined ? null : { value: held }, change };
|
|
434
|
+
}
|
|
435
|
+
over.push(one);
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (one.kind === 'preamble') {
|
|
439
|
+
const value = now.preamble === base.preamble ? one.value : bothSides(now.preamble, one.value);
|
|
440
|
+
if (value !== one.value)
|
|
441
|
+
preamble = { change };
|
|
442
|
+
over.push({ ...one, value });
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
const prior = own(base.sections, one.name);
|
|
446
|
+
const held = own(now.sections, one.name);
|
|
447
|
+
if (held === undefined && prior !== undefined)
|
|
448
|
+
return null;
|
|
449
|
+
const value = held === undefined || held === prior ? one.value : bothSides(held, one.value);
|
|
450
|
+
if (value !== one.value)
|
|
451
|
+
sections[one.name] = { change };
|
|
452
|
+
over.push({ ...one, value });
|
|
453
|
+
}
|
|
454
|
+
const joined = applyParts(now, over, definition);
|
|
455
|
+
if (joined.outcome !== 'applied')
|
|
456
|
+
return null;
|
|
457
|
+
return {
|
|
458
|
+
value: serialize(joined.document),
|
|
459
|
+
marks: marksOf(fields, sections, { preamble }),
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
export function joinedOver(parts, marks, path, visible) {
|
|
463
|
+
const report = underneath(parts, path, visible);
|
|
464
|
+
const change = visible.changes[path] ?? null;
|
|
465
|
+
const next = { ...parts };
|
|
466
|
+
const fields = {};
|
|
467
|
+
const sections = {};
|
|
468
|
+
const rest = {};
|
|
469
|
+
let rebased = false;
|
|
470
|
+
const text = (value, current, mark) => {
|
|
471
|
+
const joined = bothSides(current, value);
|
|
472
|
+
if (joined !== value)
|
|
473
|
+
mark();
|
|
474
|
+
return { value: joined, base: current };
|
|
475
|
+
};
|
|
476
|
+
const now = visible.collection.document(path);
|
|
477
|
+
if (now !== undefined) {
|
|
478
|
+
for (const [name, current] of named(report.fields)) {
|
|
479
|
+
const { value } = parts.fields[name];
|
|
480
|
+
next.fields = { ...next.fields, [name]: { value, base: current } };
|
|
481
|
+
if (!sameField(current, { value }))
|
|
482
|
+
fields[name] = { current, change };
|
|
483
|
+
rebased = true;
|
|
484
|
+
}
|
|
485
|
+
const removed = [];
|
|
486
|
+
for (const [name, current] of named(report.sections)) {
|
|
487
|
+
if (current === null) {
|
|
488
|
+
removed.push(name);
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const joined = text(parts.sections[name].value, current, () => {
|
|
492
|
+
sections[name] = { change };
|
|
493
|
+
});
|
|
494
|
+
next.sections = { ...next.sections, [name]: joined };
|
|
495
|
+
rebased = true;
|
|
496
|
+
}
|
|
497
|
+
if (typeof report.preamble === 'string') {
|
|
498
|
+
next.preamble = text(parts.preamble.value, report.preamble, () => {
|
|
499
|
+
rest.preamble = { change };
|
|
500
|
+
});
|
|
501
|
+
rebased = true;
|
|
502
|
+
}
|
|
503
|
+
const whole = removed.length === 0
|
|
504
|
+
? null
|
|
505
|
+
: applyParts(now, changesOf(path, next).changes, definitionsAt(visible.collection.composition, path)(now.type));
|
|
506
|
+
if (whole?.outcome === 'applied') {
|
|
507
|
+
delete next.fields;
|
|
508
|
+
delete next.sections;
|
|
509
|
+
delete next.preamble;
|
|
510
|
+
next.markdown = { value: serialize(whole.document), base: visible.documents[path] };
|
|
511
|
+
for (const name of removed)
|
|
512
|
+
sections[name] = { change };
|
|
513
|
+
rebased = true;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (typeof report.markdown === 'string' && parts.markdown !== undefined) {
|
|
517
|
+
const current = report.markdown;
|
|
518
|
+
const whole = wholeJoined(parts.markdown, current, path, visible.collection.composition, change);
|
|
519
|
+
const value = whole?.value ?? bothSides(current, parts.markdown.value);
|
|
520
|
+
next.markdown = { value, base: current };
|
|
521
|
+
if (whole !== null) {
|
|
522
|
+
Object.assign(fields, whole.marks.fields);
|
|
523
|
+
Object.assign(sections, whole.marks.sections);
|
|
524
|
+
if (whole.marks.preamble !== undefined)
|
|
525
|
+
rest.preamble = whole.marks.preamble;
|
|
526
|
+
}
|
|
527
|
+
else if (value !== parts.markdown.value)
|
|
528
|
+
rest.markdown = { change };
|
|
529
|
+
rebased = true;
|
|
530
|
+
}
|
|
531
|
+
if (typeof report.move === 'string' && parts.move !== undefined) {
|
|
532
|
+
next.move = { ...parts.move, base: report.move };
|
|
533
|
+
rebased = true;
|
|
534
|
+
}
|
|
535
|
+
if (typeof report.removal === 'string' && parts.removal !== undefined) {
|
|
536
|
+
next.removal = { base: report.removal };
|
|
537
|
+
rebased = true;
|
|
538
|
+
}
|
|
539
|
+
if (typeof report.file === 'string' && parts.file !== undefined && parts.file.base !== null) {
|
|
540
|
+
next.file = { ...parts.file, base: report.file };
|
|
541
|
+
if (visible.binaries[path]?.sha256 !== parts.file.sha256) {
|
|
542
|
+
rest.file = { current: report.file, change };
|
|
543
|
+
}
|
|
544
|
+
rebased = true;
|
|
545
|
+
}
|
|
546
|
+
return rebased ? { parts: next, marks: marksOver(marksOf(fields, sections, rest), marks) } : null;
|
|
547
|
+
}
|
|
268
548
|
function joined(existing, returned) {
|
|
269
549
|
const merged = { ...existing };
|
|
270
550
|
for (const [name, part] of named(returned))
|
|
@@ -272,34 +552,45 @@ function joined(existing, returned) {
|
|
|
272
552
|
merged[name] = part;
|
|
273
553
|
return Object.keys(merged).length === 0 ? undefined : merged;
|
|
274
554
|
}
|
|
275
|
-
function
|
|
555
|
+
export function lineEnded(text) {
|
|
276
556
|
return text === '' || text.endsWith('\n') ? text : `${text}\n`;
|
|
277
557
|
}
|
|
278
|
-
function
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (next.outcome !== 'applied')
|
|
286
|
-
return malformed();
|
|
287
|
-
document = next.document;
|
|
288
|
-
}
|
|
289
|
-
return serialize(document);
|
|
558
|
+
function written(start, changes, definition) {
|
|
559
|
+
const next = apply(start, changes, definition);
|
|
560
|
+
return next.outcome === 'applied' ? next.document : malformed();
|
|
561
|
+
}
|
|
562
|
+
function empty(definition) {
|
|
563
|
+
const parsed = parse('', '', definition);
|
|
564
|
+
return parsed.ok ? parsed.document : malformed();
|
|
290
565
|
}
|
|
291
|
-
export function partsAfter(markdown, parts) {
|
|
566
|
+
export function partsAfter(markdown, parts, definitions) {
|
|
292
567
|
const fields = named(parts.fields);
|
|
568
|
+
const sections = named(parts.sections);
|
|
569
|
+
if (fields.length === 0 && sections.length === 0 && parts.preamble === undefined)
|
|
570
|
+
return markdown;
|
|
571
|
+
const whole = parse(markdown, '', definitions);
|
|
572
|
+
const type = whole.ok ? whole.document.type : undefined;
|
|
573
|
+
const definition = definitions?.(type);
|
|
574
|
+
if (type !== undefined && definition === undefined)
|
|
575
|
+
return null;
|
|
576
|
+
const valued = fields.length === 0
|
|
577
|
+
? empty(definition)
|
|
578
|
+
: written(create(type, definition), fields.map(([name, part]) => ({
|
|
579
|
+
kind: 'field',
|
|
580
|
+
name,
|
|
581
|
+
value: part.value,
|
|
582
|
+
prior: undefined,
|
|
583
|
+
})), definition);
|
|
584
|
+
const head = parts.preamble === undefined
|
|
585
|
+
? valued
|
|
586
|
+
: written(valued, [{ kind: 'preamble', value: lineEnded(parts.preamble.value), prior: valued.preamble }], definition);
|
|
293
587
|
const pieces = [
|
|
294
|
-
...(fields.length === 0 ? [] : [
|
|
295
|
-
...(
|
|
296
|
-
...named(parts.sections).map(([name, part]) => `## ${name}\n${part.value}`),
|
|
588
|
+
...(fields.length === 0 && parts.preamble === undefined ? [] : [serialize(head)]),
|
|
589
|
+
...sections.map(([name, part]) => serialize(written(empty(definition), [{ kind: 'section', name, value: lineEnded(part.value), prior: undefined }], definition))),
|
|
297
590
|
];
|
|
298
|
-
|
|
299
|
-
return markdown;
|
|
300
|
-
return `${ended(markdown)}\n${pieces.map(ended).join('')}`;
|
|
591
|
+
return followedBy(markdown, pieces.join(''));
|
|
301
592
|
}
|
|
302
|
-
export function returnedInto(existing, returned) {
|
|
593
|
+
export function returnedInto(existing, returned, definitions) {
|
|
303
594
|
if (existing === undefined)
|
|
304
595
|
return returned;
|
|
305
596
|
const next = { ...existing };
|
|
@@ -319,7 +610,9 @@ export function returnedInto(existing, returned) {
|
|
|
319
610
|
delete next.fields;
|
|
320
611
|
delete next.sections;
|
|
321
612
|
delete next.preamble;
|
|
322
|
-
const value = partsAfter(whole.value, existing.markdown === undefined ? existing : returned);
|
|
613
|
+
const value = partsAfter(whole.value, existing.markdown === undefined ? existing : returned, definitions);
|
|
614
|
+
if (value === null)
|
|
615
|
+
return null;
|
|
323
616
|
next.markdown = { value, base: whole.base };
|
|
324
617
|
}
|
|
325
618
|
const creation = existing.creation ?? returned.creation;
|
|
@@ -340,6 +633,36 @@ export function moveTarget(move) {
|
|
|
340
633
|
const to = normalize(move.to);
|
|
341
634
|
return to === null || to === '' ? move.to : to;
|
|
342
635
|
}
|
|
636
|
+
export function readSavedParts(named) {
|
|
637
|
+
const read = named.map(({ path, parts }) => ({ path, parts: readParts(parts, path) }));
|
|
638
|
+
read.forEach(({ path }, at) => {
|
|
639
|
+
if (path === '' || normalize(path) !== path)
|
|
640
|
+
malformed(path, 'a path inside the Room, such as notes/a.md');
|
|
641
|
+
if (read.findIndex((one) => one.path === path) !== at)
|
|
642
|
+
malformed(path, 'each path once in one save');
|
|
643
|
+
});
|
|
644
|
+
return read;
|
|
645
|
+
}
|
|
646
|
+
export function partsChanges(named) {
|
|
647
|
+
const changes = [];
|
|
648
|
+
const preconditions = [];
|
|
649
|
+
for (const { path, parts } of readSavedParts(named)) {
|
|
650
|
+
const parted = held(undefined, parts);
|
|
651
|
+
const made = changesOf(path, parted);
|
|
652
|
+
changes.push(...made.changes);
|
|
653
|
+
preconditions.push(...made.bases);
|
|
654
|
+
for (const change of made.changes) {
|
|
655
|
+
if (change.kind === 'create')
|
|
656
|
+
preconditions.push({ kind: 'absent', path });
|
|
657
|
+
if (change.kind === 'move')
|
|
658
|
+
preconditions.push({ kind: 'absent', path: change.to });
|
|
659
|
+
}
|
|
660
|
+
const revision = parted.markdown?.base ?? parted.move?.base ?? parted.removal?.base;
|
|
661
|
+
if (typeof revision === 'string')
|
|
662
|
+
preconditions.push({ kind: 'revision', path, revision });
|
|
663
|
+
}
|
|
664
|
+
return { changes, preconditions };
|
|
665
|
+
}
|
|
343
666
|
export function changesOf(path, parts) {
|
|
344
667
|
const changes = [];
|
|
345
668
|
const bases = [];
|
|
@@ -359,23 +682,23 @@ export function changesOf(path, parts) {
|
|
|
359
682
|
bases.push({ kind: 'field', path, name, value: part.base?.value });
|
|
360
683
|
}
|
|
361
684
|
for (const [name, part] of named(parts.sections)) {
|
|
362
|
-
changes.push({ kind: 'section', path, name, value: part.value });
|
|
685
|
+
changes.push({ kind: 'section', path, name, value: lineEnded(part.value) });
|
|
363
686
|
bases.push({ kind: 'section', path, name, value: part.base });
|
|
364
687
|
}
|
|
365
688
|
if (parts.preamble !== undefined) {
|
|
366
|
-
changes.push({ kind: 'preamble', path, value: parts.preamble.value });
|
|
689
|
+
changes.push({ kind: 'preamble', path, value: lineEnded(parts.preamble.value) });
|
|
367
690
|
bases.push({ kind: 'preamble', path, value: parts.preamble.base });
|
|
368
691
|
}
|
|
369
692
|
if (parts.markdown !== undefined) {
|
|
370
693
|
changes.push({ kind: 'replace', path, content: parts.markdown.value });
|
|
371
694
|
}
|
|
372
695
|
if (parts.file !== undefined && parts.removal === undefined) {
|
|
373
|
-
const { base, ...file } = parts.file;
|
|
696
|
+
const { base, name: _name, ...file } = parts.file;
|
|
374
697
|
const at = parts.move === undefined ? path : moveTarget(parts.move);
|
|
375
698
|
if (base !== null && at !== path)
|
|
376
699
|
changes.push({ kind: 'move', path, to: at });
|
|
377
700
|
changes.push({ kind: 'binary', path: at, ...file });
|
|
378
|
-
if (base === null
|
|
701
|
+
if (base === null)
|
|
379
702
|
bases.push({ kind: 'absent', path: at });
|
|
380
703
|
return { changes, bases };
|
|
381
704
|
}
|
|
@@ -387,35 +710,6 @@ export function changesOf(path, parts) {
|
|
|
387
710
|
changes.push({ kind: 'remove', path });
|
|
388
711
|
return { changes, bases };
|
|
389
712
|
}
|
|
390
|
-
function rebased(before, after) {
|
|
391
|
-
return before === undefined ? after : { ...after, base: before.base };
|
|
392
|
-
}
|
|
393
|
-
function rebasedAll(before, after) {
|
|
394
|
-
return {
|
|
395
|
-
...before,
|
|
396
|
-
...Object.fromEntries(Object.entries(after).map(([name, part]) => [name, rebased(before?.[name], part)])),
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
export function joinedDraft(carried, saved) {
|
|
400
|
-
const draft = saved.find((item) => item.path === carried.path);
|
|
401
|
-
if (draft === undefined)
|
|
402
|
-
return carried;
|
|
403
|
-
const held = carried.parts;
|
|
404
|
-
const next = draft.parts;
|
|
405
|
-
return {
|
|
406
|
-
path: carried.path,
|
|
407
|
-
parts: {
|
|
408
|
-
...held,
|
|
409
|
-
...next,
|
|
410
|
-
...(next.fields === undefined ? {} : { fields: rebasedAll(held.fields, next.fields) }),
|
|
411
|
-
...(next.sections === undefined
|
|
412
|
-
? {}
|
|
413
|
-
: { sections: rebasedAll(held.sections, next.sections) }),
|
|
414
|
-
...(next.preamble === undefined ? {} : { preamble: rebased(held.preamble, next.preamble) }),
|
|
415
|
-
...(next.markdown === undefined ? {} : { markdown: rebased(held.markdown, next.markdown) }),
|
|
416
|
-
},
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
713
|
export function withdrawnDrafts(drafts, changes) {
|
|
420
714
|
return drafts.flatMap((draft) => {
|
|
421
715
|
const file = draft.parts.file;
|