@agentshouse/mdruntime 0.1.0-cec6690d5712e → 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 +207 -94
- 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 +18 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +8 -0
- package/dist/bootstrap.d.ts +31 -11
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +311 -92
- 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 -14
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +17 -62
- package/dist/change.d.ts +46 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +39 -0
- 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 +51 -27
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +133 -26
- package/dist/collection.d.ts +34 -9
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +55 -79
- 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 +8 -111
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +113 -2221
- 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 +84 -45
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +1118 -584
- 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 +23 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +9 -0
- package/dist/entry.d.ts +20 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +161 -0
- 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 +29 -4
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +179 -25
- package/dist/identity.d.ts +1 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +3 -0
- package/dist/index.d.ts +42 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -2
- 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 +26 -8
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +307 -97
- 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 +11 -12
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +7 -15
- 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 +42 -9
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +238 -33
- 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 +63 -5
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +70 -0
- package/dist/overlay.d.ts +21 -6
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +163 -187
- 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 +51 -183
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -464
- 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 +20 -5
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +357 -80
- package/dist/react.d.ts +23 -7
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +40 -18
- 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 +55 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +25 -0
- package/dist/reads.d.ts +39 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +178 -0
- package/dist/recovery.d.ts +28 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +254 -0
- package/dist/refresh.d.ts +17 -14
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +145 -58
- 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 +53 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +349 -167
- 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 +82 -11
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +490 -78
- 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 +31 -35
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +60 -126
- 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 +45 -22
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +977 -215
- 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 +15 -55
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -121
- package/dist/seed.d.ts +25 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +145 -0
- package/dist/shared.d.ts +10 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +339 -0
- 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 +5 -2
- 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 -116
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +164 -494
- 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 +9 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +75 -0
- 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 +11 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +16 -0
- package/dist/wire.d.ts +221 -34
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +74 -31
- package/package.json +28 -24
- package/AGENTS.md +0 -299
- package/dist/attachment.d.ts +0 -3
- package/dist/attachment.d.ts.map +0 -1
- package/dist/attachment.js +0 -8
- package/dist/attempt.d.ts +0 -16
- package/dist/attempt.d.ts.map +0 -1
- package/dist/attempt.js +0 -57
- package/dist/chat/acts.d.ts +0 -34
- 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/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 -60
- 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 -20
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -59
- package/dist/chat/markdown.d.ts +0 -19
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -187
- 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 -21
- package/dist/chat/messages.d.ts.map +0 -1
- package/dist/chat/messages.js +0 -151
- 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 -645
- package/dist/chat/question.d.ts +0 -9
- package/dist/chat/question.d.ts.map +0 -1
- package/dist/chat/question.js +0 -80
- 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 -33
- 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/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 -18
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -433
package/dist/room-draft.js
CHANGED
|
@@ -1,58 +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';
|
|
4
|
+
import { sha256 } from './digest.js';
|
|
5
|
+
import { declaredType } from './outcome.js';
|
|
6
|
+
import { binaryLocalId } from './identity.js';
|
|
3
7
|
import { normalize } from './paths.js';
|
|
4
|
-
export function returnedBy(
|
|
5
|
-
return { kind, code:
|
|
8
|
+
export function returnedBy() {
|
|
9
|
+
return { kind: 'withdrawn', code: 'withdrawn', fields: {}, retryable: false };
|
|
6
10
|
}
|
|
7
11
|
export function staleWrite(current) {
|
|
8
|
-
return { outcome: 'stale',
|
|
12
|
+
return { outcome: 'stale', current };
|
|
9
13
|
}
|
|
10
|
-
function malformed() {
|
|
11
|
-
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}`);
|
|
12
16
|
}
|
|
13
17
|
function plain(value) {
|
|
14
18
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
15
19
|
}
|
|
16
|
-
function text(value) {
|
|
17
|
-
return typeof value === 'string' ? value : malformed();
|
|
20
|
+
function text(value, at) {
|
|
21
|
+
return typeof value === 'string' ? value : malformed(at, 'text');
|
|
18
22
|
}
|
|
19
|
-
function optionalText(value) {
|
|
20
|
-
return value === undefined ? undefined : text(value);
|
|
23
|
+
function optionalText(value, at) {
|
|
24
|
+
return value === undefined ? undefined : text(value, at);
|
|
21
25
|
}
|
|
22
|
-
function markdownBase(value) {
|
|
23
|
-
return value === null ? null : optionalText(value);
|
|
26
|
+
function markdownBase(value, at) {
|
|
27
|
+
return value === null ? null : optionalText(value, at);
|
|
24
28
|
}
|
|
25
|
-
function entries(value, each) {
|
|
29
|
+
function entries(value, at, each) {
|
|
26
30
|
if (!plain(value))
|
|
27
|
-
malformed();
|
|
31
|
+
malformed(at, 'an object of named values');
|
|
28
32
|
const read = {};
|
|
29
33
|
for (const [name, item] of Object.entries(value))
|
|
30
|
-
read[name] = each(item);
|
|
34
|
+
read[name] = each(item, `${at}.${name}`);
|
|
31
35
|
return read;
|
|
32
36
|
}
|
|
33
|
-
function
|
|
37
|
+
function documentValueAt(item, at) {
|
|
38
|
+
return documentValue(item) ? item : malformed(at, 'a document value');
|
|
39
|
+
}
|
|
40
|
+
function fieldValue(value, at) {
|
|
34
41
|
if (value === null)
|
|
35
42
|
return null;
|
|
36
|
-
if (!plain(value) || !Object.hasOwn(value, 'value') || !
|
|
37
|
-
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');
|
|
38
45
|
}
|
|
39
46
|
return { value: value.value };
|
|
40
47
|
}
|
|
41
|
-
function textPart(value) {
|
|
48
|
+
function textPart(value, at) {
|
|
42
49
|
if (!plain(value))
|
|
43
|
-
malformed();
|
|
44
|
-
const base = optionalText(value.base);
|
|
45
|
-
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 }) };
|
|
46
53
|
}
|
|
47
|
-
function creationOf(value) {
|
|
54
|
+
function creationOf(value, at) {
|
|
48
55
|
if (!plain(value))
|
|
49
|
-
malformed();
|
|
56
|
+
malformed(at, '{ type, fields, sections }, or { markdown }');
|
|
50
57
|
if (Object.hasOwn(value, 'markdown'))
|
|
51
|
-
return { markdown: text(value.markdown) };
|
|
52
|
-
|
|
53
|
-
|
|
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
|
+
};
|
|
54
66
|
}
|
|
55
|
-
const PART_NAMES =
|
|
67
|
+
const PART_NAMES = [
|
|
56
68
|
'fields',
|
|
57
69
|
'sections',
|
|
58
70
|
'preamble',
|
|
@@ -60,41 +72,59 @@ const PART_NAMES = new Set([
|
|
|
60
72
|
'creation',
|
|
61
73
|
'move',
|
|
62
74
|
'removal',
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
'file',
|
|
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);
|
|
67
84
|
const parts = {};
|
|
68
85
|
if (value.fields !== undefined) {
|
|
69
|
-
parts.fields = entries(value.fields, (item) => {
|
|
70
|
-
if (!plain(item) || !Object.hasOwn(item, 'value') || !
|
|
71
|
-
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');
|
|
72
89
|
}
|
|
73
90
|
return item.base === undefined
|
|
74
91
|
? { value: item.value }
|
|
75
|
-
: { value: item.value, base: fieldValue(item.base) };
|
|
92
|
+
: { value: item.value, base: fieldValue(item.base, `${at}.base`) };
|
|
76
93
|
});
|
|
77
94
|
}
|
|
78
95
|
if (value.sections !== undefined)
|
|
79
|
-
parts.sections = entries(value.sections, textPart);
|
|
96
|
+
parts.sections = entries(value.sections, `${path} sections`, textPart);
|
|
80
97
|
if (value.preamble !== undefined)
|
|
81
|
-
parts.preamble = textPart(value.preamble);
|
|
98
|
+
parts.preamble = textPart(value.preamble, `${path} preamble`);
|
|
82
99
|
if (value.markdown !== undefined)
|
|
83
|
-
parts.markdown = textPart(value.markdown);
|
|
100
|
+
parts.markdown = textPart(value.markdown, `${path} markdown`);
|
|
84
101
|
if (value.creation !== undefined)
|
|
85
|
-
parts.creation = creationOf(value.creation);
|
|
102
|
+
parts.creation = creationOf(value.creation, `${path} creation`);
|
|
86
103
|
if (value.move !== undefined) {
|
|
87
104
|
if (!plain(value.move))
|
|
88
|
-
malformed();
|
|
89
|
-
const base = markdownBase(value.move.base);
|
|
90
|
-
|
|
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
|
+
};
|
|
91
113
|
}
|
|
92
114
|
if (value.removal !== undefined) {
|
|
93
115
|
if (!plain(value.removal))
|
|
94
|
-
malformed();
|
|
95
|
-
const base = markdownBase(value.removal.base);
|
|
116
|
+
malformed(`${path} removal`, '{ base }');
|
|
117
|
+
const base = markdownBase(value.removal.base, `${path} removal.base`);
|
|
96
118
|
parts.removal = base === undefined ? {} : { base };
|
|
97
119
|
}
|
|
120
|
+
if (value.file !== undefined) {
|
|
121
|
+
if (!plain(value.file) || !(value.file.blob instanceof Blob))
|
|
122
|
+
malformed(`${path} file`, '{ blob, base } with a Blob');
|
|
123
|
+
if (Object.keys(value).length > 1)
|
|
124
|
+
throw runtimeError('room-draft-file-exclusive');
|
|
125
|
+
const base = markdownBase(value.file.base, `${path} file.base`);
|
|
126
|
+
parts.file = base === undefined ? { blob: value.file.blob } : { blob: value.file.blob, base };
|
|
127
|
+
}
|
|
98
128
|
return parts;
|
|
99
129
|
}
|
|
100
130
|
function named(record) {
|
|
@@ -110,15 +140,76 @@ function kept(prior, base) {
|
|
|
110
140
|
throw runtimeError('room-draft-base-missing');
|
|
111
141
|
return base;
|
|
112
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
|
+
}
|
|
113
150
|
function editsText(parts) {
|
|
114
151
|
return (parts.preamble !== undefined ||
|
|
115
152
|
named(parts.fields).length > 0 ||
|
|
116
153
|
named(parts.sections).length > 0);
|
|
117
154
|
}
|
|
118
|
-
|
|
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
|
+
}
|
|
188
|
+
export function held(current, parts, file) {
|
|
119
189
|
if (parts.markdown !== undefined && editsText(parts)) {
|
|
120
190
|
throw runtimeError('room-draft-markdown-exclusive');
|
|
121
191
|
}
|
|
192
|
+
if (file !== undefined) {
|
|
193
|
+
if (current !== undefined && current.file === undefined) {
|
|
194
|
+
throw runtimeError('room-draft-file-exclusive');
|
|
195
|
+
}
|
|
196
|
+
return { file: { ...file, base: current?.file === undefined ? file.base : current.file.base } };
|
|
197
|
+
}
|
|
198
|
+
if (current?.file !== undefined) {
|
|
199
|
+
if (editsText(parts) ||
|
|
200
|
+
parts.markdown !== undefined ||
|
|
201
|
+
parts.creation !== undefined ||
|
|
202
|
+
(parts.move === undefined && parts.removal === undefined)) {
|
|
203
|
+
throw runtimeError('room-draft-file-exclusive');
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
file: current.file,
|
|
207
|
+
...(parts.move === undefined ? {} : { move: movePart(current.move, parts.move) }),
|
|
208
|
+
...(parts.removal === undefined
|
|
209
|
+
? {}
|
|
210
|
+
: { removal: { base: kept(current.removal, parts.removal.base) } }),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
122
213
|
const next = {};
|
|
123
214
|
const fields = named(parts.fields);
|
|
124
215
|
if (fields.length > 0) {
|
|
@@ -148,9 +239,8 @@ export function held(current, parts) {
|
|
|
148
239
|
}
|
|
149
240
|
if (parts.creation !== undefined)
|
|
150
241
|
next.creation = parts.creation;
|
|
151
|
-
if (parts.move !== undefined)
|
|
152
|
-
next.move =
|
|
153
|
-
}
|
|
242
|
+
if (parts.move !== undefined)
|
|
243
|
+
next.move = movePart(current?.move, parts.move);
|
|
154
244
|
if (parts.removal !== undefined) {
|
|
155
245
|
next.removal = { base: kept(current?.removal, parts.removal.base) };
|
|
156
246
|
}
|
|
@@ -167,8 +257,10 @@ export function underneath(parts, path, visible) {
|
|
|
167
257
|
const markdown = visible?.documents[path] ?? null;
|
|
168
258
|
const document = visible?.collection.document(path);
|
|
169
259
|
const report = {};
|
|
260
|
+
const unread = document?.type !== undefined &&
|
|
261
|
+
governing(visible.collection.composition, path).status === 'unavailable';
|
|
170
262
|
const fields = {};
|
|
171
|
-
for (const [name, part] of named(parts.fields)) {
|
|
263
|
+
for (const [name, part] of unread ? [] : named(parts.fields)) {
|
|
172
264
|
const current = document !== undefined && Object.hasOwn(document.fields, name)
|
|
173
265
|
? { value: document.fields[name] }
|
|
174
266
|
: null;
|
|
@@ -178,7 +270,7 @@ export function underneath(parts, path, visible) {
|
|
|
178
270
|
if (Object.keys(fields).length > 0)
|
|
179
271
|
report.fields = fields;
|
|
180
272
|
const sections = {};
|
|
181
|
-
for (const [name, part] of named(parts.sections)) {
|
|
273
|
+
for (const [name, part] of unread ? [] : named(parts.sections)) {
|
|
182
274
|
const current = document !== undefined && Object.hasOwn(document.sections, name)
|
|
183
275
|
? document.sections[name]
|
|
184
276
|
: null;
|
|
@@ -188,8 +280,9 @@ export function underneath(parts, path, visible) {
|
|
|
188
280
|
if (Object.keys(sections).length > 0)
|
|
189
281
|
report.sections = sections;
|
|
190
282
|
const preamble = document?.preamble ?? null;
|
|
191
|
-
if (parts.preamble !== undefined && preamble !== parts.preamble.base)
|
|
283
|
+
if (!unread && parts.preamble !== undefined && preamble !== parts.preamble.base) {
|
|
192
284
|
report.preamble = preamble;
|
|
285
|
+
}
|
|
193
286
|
if (parts.markdown !== undefined && markdown !== parts.markdown.base)
|
|
194
287
|
report.markdown = markdown;
|
|
195
288
|
if (parts.creation !== undefined && markdown !== null)
|
|
@@ -198,19 +291,260 @@ export function underneath(parts, path, visible) {
|
|
|
198
291
|
report.move = markdown;
|
|
199
292
|
if (parts.removal !== undefined && markdown !== parts.removal.base)
|
|
200
293
|
report.removal = markdown;
|
|
294
|
+
if (parts.file !== undefined) {
|
|
295
|
+
const file = binaryBase(visible, path);
|
|
296
|
+
if (file !== parts.file.base || markdown !== null)
|
|
297
|
+
report.file = file;
|
|
298
|
+
}
|
|
201
299
|
return report;
|
|
202
300
|
}
|
|
203
|
-
export function
|
|
301
|
+
export async function heldFile(blob, base) {
|
|
302
|
+
return {
|
|
303
|
+
localId: binaryLocalId(),
|
|
304
|
+
...(blob instanceof File ? { name: blob.name } : {}),
|
|
305
|
+
byteLength: blob.size,
|
|
306
|
+
mediaType: declaredType(blob),
|
|
307
|
+
sha256: await sha256(blob),
|
|
308
|
+
base,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
export function binaryBase(visible, path) {
|
|
312
|
+
const binary = visible?.binaries[path];
|
|
313
|
+
if (binary === undefined)
|
|
314
|
+
return null;
|
|
315
|
+
return visible?.revisions[path] ?? (binary.state === 'pending' ? binary.localId : null);
|
|
316
|
+
}
|
|
317
|
+
export function changedParts(path, parts, visible) {
|
|
318
|
+
const report = underneath(parts, path, visible);
|
|
319
|
+
const made = parts.file?.base === null;
|
|
204
320
|
return [
|
|
205
|
-
...(report.creation === undefined ? [] : [{ path, part: 'creation' }]),
|
|
206
321
|
...named(report.fields).map(([name]) => ({ path, part: 'field', name })),
|
|
207
322
|
...named(report.sections).map(([name]) => ({ path, part: 'section', name })),
|
|
208
323
|
...(report.preamble === undefined ? [] : [{ path, part: 'preamble' }]),
|
|
209
324
|
...(report.markdown === undefined ? [] : [{ path, part: 'markdown' }]),
|
|
210
325
|
...(report.move === undefined ? [] : [{ path, part: 'move' }]),
|
|
211
326
|
...(report.removal === undefined ? [] : [{ path, part: 'removal' }]),
|
|
327
|
+
...(report.file === undefined || made ? [] : [{ path, part: 'file' }]),
|
|
212
328
|
];
|
|
213
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
|
+
}
|
|
214
548
|
function joined(existing, returned) {
|
|
215
549
|
const merged = { ...existing };
|
|
216
550
|
for (const [name, part] of named(returned))
|
|
@@ -218,34 +552,45 @@ function joined(existing, returned) {
|
|
|
218
552
|
merged[name] = part;
|
|
219
553
|
return Object.keys(merged).length === 0 ? undefined : merged;
|
|
220
554
|
}
|
|
221
|
-
function
|
|
555
|
+
export function lineEnded(text) {
|
|
222
556
|
return text === '' || text.endsWith('\n') ? text : `${text}\n`;
|
|
223
557
|
}
|
|
224
|
-
function
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (next.outcome !== 'applied')
|
|
232
|
-
return malformed();
|
|
233
|
-
document = next.document;
|
|
234
|
-
}
|
|
235
|
-
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();
|
|
236
565
|
}
|
|
237
|
-
function
|
|
566
|
+
export function partsAfter(markdown, parts, definitions) {
|
|
238
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);
|
|
239
587
|
const pieces = [
|
|
240
|
-
...(fields.length === 0 ? [] : [
|
|
241
|
-
...(
|
|
242
|
-
...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))),
|
|
243
590
|
];
|
|
244
|
-
|
|
245
|
-
return markdown;
|
|
246
|
-
return `${ended(markdown)}\n${pieces.map(ended).join('')}`;
|
|
591
|
+
return followedBy(markdown, pieces.join(''));
|
|
247
592
|
}
|
|
248
|
-
export function returnedInto(existing, returned) {
|
|
593
|
+
export function returnedInto(existing, returned, definitions) {
|
|
249
594
|
if (existing === undefined)
|
|
250
595
|
return returned;
|
|
251
596
|
const next = { ...existing };
|
|
@@ -265,24 +610,59 @@ export function returnedInto(existing, returned) {
|
|
|
265
610
|
delete next.fields;
|
|
266
611
|
delete next.sections;
|
|
267
612
|
delete next.preamble;
|
|
268
|
-
const value =
|
|
613
|
+
const value = partsAfter(whole.value, existing.markdown === undefined ? existing : returned, definitions);
|
|
614
|
+
if (value === null)
|
|
615
|
+
return null;
|
|
269
616
|
next.markdown = { value, base: whole.base };
|
|
270
617
|
}
|
|
271
618
|
const creation = existing.creation ?? returned.creation;
|
|
272
619
|
const move = existing.move ?? returned.move;
|
|
273
620
|
const removal = existing.removal ?? returned.removal;
|
|
621
|
+
const file = existing.file ?? returned.file;
|
|
274
622
|
if (creation !== undefined)
|
|
275
623
|
next.creation = creation;
|
|
276
624
|
if (move !== undefined)
|
|
277
625
|
next.move = move;
|
|
278
626
|
if (removal !== undefined)
|
|
279
627
|
next.removal = removal;
|
|
628
|
+
if (file !== undefined)
|
|
629
|
+
next.file = file;
|
|
280
630
|
return next;
|
|
281
631
|
}
|
|
282
632
|
export function moveTarget(move) {
|
|
283
633
|
const to = normalize(move.to);
|
|
284
634
|
return to === null || to === '' ? move.to : to;
|
|
285
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
|
+
}
|
|
286
666
|
export function changesOf(path, parts) {
|
|
287
667
|
const changes = [];
|
|
288
668
|
const bases = [];
|
|
@@ -302,19 +682,51 @@ export function changesOf(path, parts) {
|
|
|
302
682
|
bases.push({ kind: 'field', path, name, value: part.base?.value });
|
|
303
683
|
}
|
|
304
684
|
for (const [name, part] of named(parts.sections)) {
|
|
305
|
-
changes.push({ kind: 'section', path, name, value: part.value });
|
|
685
|
+
changes.push({ kind: 'section', path, name, value: lineEnded(part.value) });
|
|
306
686
|
bases.push({ kind: 'section', path, name, value: part.base });
|
|
307
687
|
}
|
|
308
688
|
if (parts.preamble !== undefined) {
|
|
309
|
-
changes.push({ kind: 'preamble', path, value: parts.preamble.value });
|
|
689
|
+
changes.push({ kind: 'preamble', path, value: lineEnded(parts.preamble.value) });
|
|
310
690
|
bases.push({ kind: 'preamble', path, value: parts.preamble.base });
|
|
311
691
|
}
|
|
312
692
|
if (parts.markdown !== undefined) {
|
|
313
693
|
changes.push({ kind: 'replace', path, content: parts.markdown.value });
|
|
314
694
|
}
|
|
695
|
+
if (parts.file !== undefined && parts.removal === undefined) {
|
|
696
|
+
const { base, name: _name, ...file } = parts.file;
|
|
697
|
+
const at = parts.move === undefined ? path : moveTarget(parts.move);
|
|
698
|
+
if (base !== null && at !== path)
|
|
699
|
+
changes.push({ kind: 'move', path, to: at });
|
|
700
|
+
changes.push({ kind: 'binary', path: at, ...file });
|
|
701
|
+
if (base === null)
|
|
702
|
+
bases.push({ kind: 'absent', path: at });
|
|
703
|
+
return { changes, bases };
|
|
704
|
+
}
|
|
705
|
+
if (parts.file?.base === null)
|
|
706
|
+
return { changes, bases };
|
|
315
707
|
if (parts.move !== undefined)
|
|
316
708
|
changes.push({ kind: 'move', path, to: moveTarget(parts.move) });
|
|
317
709
|
if (parts.removal !== undefined)
|
|
318
710
|
changes.push({ kind: 'remove', path });
|
|
319
711
|
return { changes, bases };
|
|
320
712
|
}
|
|
713
|
+
export function withdrawnDrafts(drafts, changes) {
|
|
714
|
+
return drafts.flatMap((draft) => {
|
|
715
|
+
const file = draft.parts.file;
|
|
716
|
+
const at = draft.parts.move?.to ?? draft.path;
|
|
717
|
+
const change = changes.find((item) => (item.kind === 'move' || item.kind === 'remove') && item.path === at);
|
|
718
|
+
if (file === undefined || change === undefined)
|
|
719
|
+
return [draft];
|
|
720
|
+
if (change.kind === 'move') {
|
|
721
|
+
return [
|
|
722
|
+
{
|
|
723
|
+
path: draft.path,
|
|
724
|
+
parts: change.to === draft.path ? { file } : { file, move: { to: change.to, base: null } },
|
|
725
|
+
},
|
|
726
|
+
];
|
|
727
|
+
}
|
|
728
|
+
return file.base === null
|
|
729
|
+
? []
|
|
730
|
+
: [{ path: draft.path, parts: { file, removal: { base: null } } }];
|
|
731
|
+
});
|
|
732
|
+
}
|