@agentshouse/mdruntime 0.1.0-c7b0ab1aa40a3 → 0.1.0-ca1eff92bbe73
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/AGENTS.md +25 -13
- package/README.md +7 -7
- package/dist/adapter.d.ts +3 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +15 -2
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +1 -0
- package/dist/connection.d.ts +1 -0
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +28 -13
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +7 -0
- package/dist/model.d.ts +7 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +2 -0
- package/dist/paths.d.ts +0 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +0 -16
- package/dist/query.d.ts +1 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +78 -19
- package/dist/react.d.ts +1 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +2 -2
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +102 -46
- package/dist/replica.d.ts +1 -1
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +2 -2
- package/dist/rows.d.ts +2 -1
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +77 -37
- package/dist/save.d.ts +1 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +90 -43
- package/dist/store.d.ts +1 -0
- package/dist/store.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/query.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ARRAY_INDEX, itemFacts, memberFacts, pointerSegments, } from '@agentshouse/mdmodel';
|
|
1
2
|
import { referenceField } from './model.js';
|
|
2
3
|
import { normalize } from './paths.js';
|
|
3
4
|
export class QueryError extends Error {
|
|
@@ -12,6 +13,7 @@ const RELATED = ['types', 'where', 'pathPrefix', 'field'];
|
|
|
12
13
|
const PARTS = ['fields', 'sections', 'preamble', 'markdown', 'backlinks', 'change'];
|
|
13
14
|
const ORDER = ['by', 'direction', 'nulls', 'stringSort', 'locale', 'localeOptions'];
|
|
14
15
|
const CALENDAR_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
16
|
+
const STRAY_ESCAPE = /~(?![01])/u;
|
|
15
17
|
export function invalid(at, problem) {
|
|
16
18
|
throw new QueryError('invalid-query', at, problem);
|
|
17
19
|
}
|
|
@@ -109,23 +111,75 @@ function typing(facts, rooms, types, at) {
|
|
|
109
111
|
types: types === null ? declared : declared.filter((type) => types.includes(type.name)),
|
|
110
112
|
};
|
|
111
113
|
}
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
+
function pointer(input, at) {
|
|
115
|
+
if (typeof input !== 'string' || !input.startsWith('/') || STRAY_ESCAPE.test(input)) {
|
|
116
|
+
invalid(at, 'expects a JSON Pointer');
|
|
117
|
+
}
|
|
118
|
+
return input;
|
|
119
|
+
}
|
|
120
|
+
function stepped({ facts, through, conditional }, token) {
|
|
121
|
+
if (facts.type === 'array' && ARRAY_INDEX.test(token)) {
|
|
122
|
+
const item = itemFacts(facts, Number(token));
|
|
123
|
+
return item === undefined ? undefined : { facts: item, through, conditional };
|
|
124
|
+
}
|
|
125
|
+
let reached = facts;
|
|
126
|
+
let across = through;
|
|
127
|
+
while (reached?.type === 'array') {
|
|
128
|
+
reached = reached.items;
|
|
129
|
+
across = true;
|
|
130
|
+
}
|
|
131
|
+
const member = reached === undefined ? undefined : memberFacts(reached, token);
|
|
132
|
+
return member === undefined
|
|
133
|
+
? undefined
|
|
134
|
+
: { facts: member, through: across, conditional: conditional || member.conditional === true };
|
|
135
|
+
}
|
|
136
|
+
function specAt(type, field) {
|
|
137
|
+
let spec = {
|
|
138
|
+
facts: { ...type.frontmatter, properties: type.fields },
|
|
139
|
+
through: false,
|
|
140
|
+
conditional: false,
|
|
141
|
+
};
|
|
142
|
+
for (const token of pointerSegments(field)) {
|
|
143
|
+
if (spec === undefined)
|
|
144
|
+
return undefined;
|
|
145
|
+
spec = stepped(spec, token);
|
|
146
|
+
}
|
|
147
|
+
return spec;
|
|
148
|
+
}
|
|
149
|
+
function specs(typed, input, at) {
|
|
150
|
+
const field = pointer(input, at);
|
|
151
|
+
const declared = typed.types.flatMap((type) => {
|
|
152
|
+
const spec = specAt(type, field);
|
|
153
|
+
return spec === undefined ? [] : [spec];
|
|
154
|
+
});
|
|
114
155
|
if (declared.length === 0 && !typed.untyped) {
|
|
115
156
|
throw new QueryError('unknown-field', at, `no MD Type it reads declares ${field}`);
|
|
116
157
|
}
|
|
117
|
-
|
|
158
|
+
if (!declared.some((spec) => spec.conditional))
|
|
159
|
+
return declared;
|
|
160
|
+
return declared.map((spec) => ({
|
|
161
|
+
facts: { prose: false },
|
|
162
|
+
through: several(spec),
|
|
163
|
+
conditional: true,
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
function several(spec) {
|
|
167
|
+
return spec.through || spec.facts.type === 'array';
|
|
168
|
+
}
|
|
169
|
+
function single(spec) {
|
|
170
|
+
return spec.facts.type !== undefined && spec.facts.type !== 'array';
|
|
171
|
+
}
|
|
172
|
+
function every(declared, holds) {
|
|
173
|
+
return declared.length > 0 && declared.every(holds);
|
|
118
174
|
}
|
|
119
175
|
function kind(declared, checked, at) {
|
|
120
|
-
if (checked === null ||
|
|
176
|
+
if (checked === null ||
|
|
177
|
+
declared.length === 0 ||
|
|
178
|
+
declared.some((spec) => fits(spec.facts, checked))) {
|
|
121
179
|
return;
|
|
122
180
|
}
|
|
123
181
|
throw new QueryError('wrong-kind', at, `${JSON.stringify(checked)} is not of its field's kind`);
|
|
124
182
|
}
|
|
125
|
-
function listed(declared, list) {
|
|
126
|
-
return (declared.length > 0 &&
|
|
127
|
-
declared.every((facts) => facts.type !== undefined && (facts.type === 'array') === list));
|
|
128
|
-
}
|
|
129
183
|
function test(declared, input, at) {
|
|
130
184
|
if (!plain(input)) {
|
|
131
185
|
const equal = value(input, at);
|
|
@@ -139,8 +193,11 @@ function test(declared, input, at) {
|
|
|
139
193
|
const stray = operators.find((operator) => !RANGE.includes(operator));
|
|
140
194
|
if (stray !== undefined)
|
|
141
195
|
invalid(place(at, stray), 'cannot join a range');
|
|
142
|
-
if (
|
|
196
|
+
if (every(declared, (spec) => spec.facts.type === 'array'))
|
|
143
197
|
invalid(at, 'a range on a list');
|
|
198
|
+
if (every(declared, (spec) => spec.facts.type === 'boolean' || spec.facts.type === 'object')) {
|
|
199
|
+
throw new QueryError('wrong-kind', at, 'its field does not compare in order');
|
|
200
|
+
}
|
|
144
201
|
return {
|
|
145
202
|
op: 'range',
|
|
146
203
|
bounds: RANGE.filter((operator) => operators.includes(operator)).map((operator) => {
|
|
@@ -173,7 +230,7 @@ function test(declared, input, at) {
|
|
|
173
230
|
return { op: 'nin', values: compared };
|
|
174
231
|
if (compared.includes(null))
|
|
175
232
|
invalid(where, 'a list holds no null');
|
|
176
|
-
if (
|
|
233
|
+
if (every(declared, single))
|
|
177
234
|
invalid(where, 'the field is not a list');
|
|
178
235
|
return { op: 'all', values: compared };
|
|
179
236
|
}
|
|
@@ -181,7 +238,7 @@ function test(declared, input, at) {
|
|
|
181
238
|
if (!Number.isSafeInteger(operand) || operand < 0) {
|
|
182
239
|
invalid(where, 'expects a nonnegative integer');
|
|
183
240
|
}
|
|
184
|
-
if (
|
|
241
|
+
if (every(declared, single))
|
|
185
242
|
invalid(where, 'the field is not a list');
|
|
186
243
|
return { op: 'size', size: operand };
|
|
187
244
|
}
|
|
@@ -194,7 +251,7 @@ function condition(typed, input, at) {
|
|
|
194
251
|
invalid(at, 'expects an object of field predicates');
|
|
195
252
|
const conditions = [];
|
|
196
253
|
for (const name of Object.keys(input).sort()) {
|
|
197
|
-
const where = place(at, name);
|
|
254
|
+
const where = name.startsWith('/') ? `${at}${name}` : place(at, name);
|
|
198
255
|
const entry = input[name];
|
|
199
256
|
if (name === '$and' || name === '$or') {
|
|
200
257
|
const nested = list(entry, where).map((item, index) => condition(typed, item, `${where}[${index}]`));
|
|
@@ -224,11 +281,11 @@ function scope(facts, rooms, input, at) {
|
|
|
224
281
|
};
|
|
225
282
|
}
|
|
226
283
|
function referenceName(typed, field, at) {
|
|
227
|
-
if (typeof field !== 'string')
|
|
228
|
-
invalid(at, 'expects a field name');
|
|
229
284
|
const declared = specs(typed, field, at);
|
|
230
|
-
if (declared.length > 0 &&
|
|
285
|
+
if (declared.length > 0 &&
|
|
286
|
+
!declared.some((spec) => spec.conditional || referenceField(spec.facts))) {
|
|
231
287
|
invalid(at, 'not a reference field');
|
|
288
|
+
}
|
|
232
289
|
return field;
|
|
233
290
|
}
|
|
234
291
|
function hopOf(facts, rooms, root, input) {
|
|
@@ -250,8 +307,10 @@ function backlinksOf(facts, rooms, input) {
|
|
|
250
307
|
function keyPlan(typed, input, at, path) {
|
|
251
308
|
if (input === 'room' || input === 'type' || (path && input === 'path'))
|
|
252
309
|
return { of: input };
|
|
253
|
-
if (plain(input) &&
|
|
254
|
-
specs(typed, input.field, place(at, 'field'))
|
|
310
|
+
if (plain(input) && Object.hasOwn(input, 'field') && Object.keys(input).length === 1) {
|
|
311
|
+
if (specs(typed, input.field, place(at, 'field')).some(several)) {
|
|
312
|
+
invalid(place(at, 'field'), 'a path that can hold several values');
|
|
313
|
+
}
|
|
255
314
|
return { of: 'field', field: input.field };
|
|
256
315
|
}
|
|
257
316
|
return invalid(at, path ? 'expects room, path, type or a field' : 'expects room, type or a field');
|
|
@@ -309,10 +368,10 @@ function parts(typed, input, at, fields) {
|
|
|
309
368
|
return 'all';
|
|
310
369
|
const named = list(input, at);
|
|
311
370
|
named.forEach((name, index) => {
|
|
312
|
-
if (typeof name !== 'string')
|
|
313
|
-
invalid(`${at}[${index}]`, 'expects a name');
|
|
314
371
|
if (fields)
|
|
315
372
|
specs(typed, name, `${at}[${index}]`);
|
|
373
|
+
else if (typeof name !== 'string')
|
|
374
|
+
invalid(`${at}[${index}]`, 'expects a name');
|
|
316
375
|
});
|
|
317
376
|
return named;
|
|
318
377
|
}
|
package/dist/react.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export type Saving = {
|
|
|
26
26
|
readonly failure: Error | null;
|
|
27
27
|
save(room: string, roomDrafts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
|
|
28
28
|
};
|
|
29
|
+
export declare function saveRoomDrafts(client: MdRuntimeClient, room: string, roomDrafts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
|
|
29
30
|
export declare function useSave(client: MdRuntimeClient): Saving;
|
|
30
31
|
export {};
|
|
31
32
|
//# sourceMappingURL=react.d.ts.map
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
|
package/dist/react.js
CHANGED
|
@@ -31,7 +31,7 @@ export function useObserve(client, topic, ...input) {
|
|
|
31
31
|
return held !== null && held.client === client && held.key === key ? held.value : undefined;
|
|
32
32
|
}
|
|
33
33
|
const IDLE = { busy: false, outcome: null, failure: null };
|
|
34
|
-
async function
|
|
34
|
+
export async function saveRoomDrafts(client, room, roomDrafts) {
|
|
35
35
|
const kept = [];
|
|
36
36
|
for (const [path, parts] of roomDrafts) {
|
|
37
37
|
const prior = await client.roomDraft.read(room, path);
|
|
@@ -48,7 +48,7 @@ export function useSave(client) {
|
|
|
48
48
|
const save = useCallback(async (room, roomDrafts) => {
|
|
49
49
|
setState({ busy: true, outcome: null, failure: null });
|
|
50
50
|
try {
|
|
51
|
-
const outcome = await
|
|
51
|
+
const outcome = await saveRoomDrafts(client, room, roomDrafts);
|
|
52
52
|
setState({ busy: false, outcome, failure: null });
|
|
53
53
|
return outcome;
|
|
54
54
|
}
|
package/dist/read-side.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAU,KAAK,WAAW,EAAE,KAAK,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC3F,OAAO,KAAK,EAOV,IAAI,EAIJ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAuDpD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,KAAK,CACH,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,KAAK,IAAI,GACpD,MAAM,IAAI,CAAC;IACd,SAAS,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AA+UF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,WAAW,GAChB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CA4BpD;AAED,wBAAgB,cAAc,IAAI,QAAQ,CA4HzC"}
|
package/dist/read-side.js
CHANGED
|
@@ -1,54 +1,58 @@
|
|
|
1
|
-
import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq,
|
|
1
|
+
import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq, inArray, or, toArray, } from '@tanstack/db';
|
|
2
|
+
import { ARRAY_INDEX, pointerSegments } from '@agentshouse/mdmodel';
|
|
2
3
|
import { rowsOf } from './observation.js';
|
|
3
4
|
import { documentKey } from './rows.js';
|
|
4
5
|
function every(expressions) {
|
|
5
6
|
const [first, second, ...rest] = expressions;
|
|
6
7
|
return second === undefined ? first : and(first, second, ...rest);
|
|
7
8
|
}
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
return second === undefined ? first : or(first, second, ...rest);
|
|
9
|
+
function same(held, value) {
|
|
10
|
+
return Array.isArray(held) ? held.includes(value) : held === value;
|
|
11
11
|
}
|
|
12
|
-
function
|
|
13
|
-
|
|
12
|
+
function ordered(held, [operator, bound]) {
|
|
13
|
+
if (typeof held !== typeof bound || held === null || typeof held === 'object')
|
|
14
|
+
return false;
|
|
15
|
+
const left = held;
|
|
16
|
+
const right = bound;
|
|
17
|
+
if (operator === 'gt')
|
|
18
|
+
return left > right;
|
|
19
|
+
if (operator === 'gte')
|
|
20
|
+
return left >= right;
|
|
21
|
+
if (operator === 'lt')
|
|
22
|
+
return left < right;
|
|
23
|
+
return left <= right;
|
|
14
24
|
}
|
|
15
|
-
function
|
|
25
|
+
function satisfied(test, held) {
|
|
16
26
|
if (test.op === 'eq')
|
|
17
|
-
return
|
|
18
|
-
if (test.op === 'ne')
|
|
19
|
-
return test.value
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const compare = { gt, gte, lt, lte };
|
|
37
|
-
return every(test.bounds.map(([operator, bound]) => compare[operator](field, bound)));
|
|
38
|
-
}
|
|
39
|
-
if (test.op === 'all') {
|
|
40
|
-
return every([not(isUndefined(size)), ...test.values.map((value) => inArray(value, field))]);
|
|
41
|
-
}
|
|
42
|
-
if (test.op === 'size')
|
|
43
|
-
return eq(size, test.size);
|
|
44
|
-
return test.exists ? not(isUndefined(written)) : isUndefined(written);
|
|
27
|
+
return same(held, test.value);
|
|
28
|
+
if (test.op === 'ne')
|
|
29
|
+
return !same(held, test.value);
|
|
30
|
+
if (test.op === 'in')
|
|
31
|
+
return test.values.some((value) => same(held, value));
|
|
32
|
+
if (test.op === 'nin')
|
|
33
|
+
return !test.values.some((value) => same(held, value));
|
|
34
|
+
if (test.op === 'range')
|
|
35
|
+
return test.bounds.every((bound) => ordered(held, bound));
|
|
36
|
+
if (test.op === 'all')
|
|
37
|
+
return Array.isArray(held) && test.values.every((value) => same(held, value));
|
|
38
|
+
return Array.isArray(held) && held.length === test.size;
|
|
39
|
+
}
|
|
40
|
+
function tested(test, reached) {
|
|
41
|
+
if (test.op === 'exists')
|
|
42
|
+
return test.exists === (reached !== undefined);
|
|
43
|
+
if (reached === undefined)
|
|
44
|
+
return test.op === 'ne' || test.op === 'nin';
|
|
45
|
+
return reached.some((held) => satisfied(test, held));
|
|
45
46
|
}
|
|
46
47
|
function conditioned(condition, row) {
|
|
47
48
|
if ('every' in condition)
|
|
48
|
-
return
|
|
49
|
+
return condition.every.every((item) => conditioned(item, row));
|
|
49
50
|
if ('some' in condition)
|
|
50
|
-
return
|
|
51
|
-
return tested(condition.test, row.
|
|
51
|
+
return condition.some.some((item) => conditioned(item, row));
|
|
52
|
+
return tested(condition.test, row.reached[condition.field]);
|
|
53
|
+
}
|
|
54
|
+
function narrowed(query, where, alias) {
|
|
55
|
+
return where === null ? query : query.fn.where((row) => conditioned(where, row[alias]));
|
|
52
56
|
}
|
|
53
57
|
function reached(reach, room, document) {
|
|
54
58
|
return reach === null
|
|
@@ -62,7 +66,6 @@ function scoped(scope, row, rooms, reach) {
|
|
|
62
66
|
...reached(reach, row.room, row.key),
|
|
63
67
|
...(scope.types === null ? [] : [inArray(row.type, [...scope.types])]),
|
|
64
68
|
...(scope.pathPrefix === null ? [] : [inArray(scope.pathPrefix, row.directories)]),
|
|
65
|
-
...(scope.where === null ? [] : [conditioned(scope.where, row)]),
|
|
66
69
|
]);
|
|
67
70
|
}
|
|
68
71
|
function keyed(key, row) {
|
|
@@ -77,16 +80,17 @@ function live(query) {
|
|
|
77
80
|
function related(q, rows, scope, field, kept, reach) {
|
|
78
81
|
const matched = kept === 'source' ? 'target' : 'source';
|
|
79
82
|
const from = q.from({ r: rows });
|
|
80
|
-
|
|
81
|
-
.where(({ r }) => every([eq(r.kind, 'reference'), ...(field === null ? [] : [
|
|
83
|
+
const joined = from
|
|
84
|
+
.where(({ r }) => every([eq(r.kind, 'reference'), ...(field === null ? [] : [inArray(field, r.forms)])]))
|
|
82
85
|
.innerJoin({ m: rows }, ({ r, m }) => eq(r[matched], m.key))
|
|
83
|
-
.where(({ m }) => scoped(scope, m, null, reach))
|
|
86
|
+
.where(({ m }) => scoped(scope, m, null, reach));
|
|
87
|
+
return narrowed(joined, scope.where, 'm')
|
|
84
88
|
.groupBy(({ r }) => r[kept])
|
|
85
89
|
.select(({ r }) => ({ key: r[kept] }));
|
|
86
90
|
}
|
|
87
91
|
function filtered(q, rows, plan) {
|
|
88
92
|
const from = q.from({ d: rows });
|
|
89
|
-
let query = from.where(({ d }) => scoped(plan.root, d, plan.rooms, plan.reach));
|
|
93
|
+
let query = narrowed(from.where(({ d }) => scoped(plan.root, d, plan.rooms, plan.reach)), plan.root.where, 'd');
|
|
90
94
|
if (plan.hop !== null) {
|
|
91
95
|
const hop = related(q, rows, plan.hop, plan.hop.field, 'source', plan.reach);
|
|
92
96
|
query = query.innerJoin({ h: hop }, ({ d, h }) => eq(d.key, h.key));
|
|
@@ -117,8 +121,7 @@ function documents(q, rows, plan, shape) {
|
|
|
117
121
|
room: d.room,
|
|
118
122
|
path: d.path,
|
|
119
123
|
type: d.type,
|
|
120
|
-
...(shape.fields ===
|
|
121
|
-
...(Array.isArray(shape.fields) ? named('field', shape.fields, d.fields) : {}),
|
|
124
|
+
...(shape.fields === null ? {} : { fields: d.fields }),
|
|
122
125
|
...(shape.sections === 'all' ? { sections: b.sections } : {}),
|
|
123
126
|
...(Array.isArray(shape.sections) ? named('section', shape.sections, b.sections) : {}),
|
|
124
127
|
...(shape.preamble ? { preamble: b.preamble } : {}),
|
|
@@ -176,6 +179,55 @@ function part(row, prefix, names, whole) {
|
|
|
176
179
|
return whole;
|
|
177
180
|
return present(names.map((name, index) => [name, row[`${prefix}${index}`]]));
|
|
178
181
|
}
|
|
182
|
+
function masked(pointers) {
|
|
183
|
+
const root = { whole: false, members: new Map() };
|
|
184
|
+
for (const pointer of pointers) {
|
|
185
|
+
let mask = root;
|
|
186
|
+
for (const token of pointerSegments(pointer)) {
|
|
187
|
+
const next = mask.members.get(token) ?? { whole: false, members: new Map() };
|
|
188
|
+
mask.members.set(token, next);
|
|
189
|
+
mask = next;
|
|
190
|
+
}
|
|
191
|
+
mask.whole = true;
|
|
192
|
+
}
|
|
193
|
+
return root;
|
|
194
|
+
}
|
|
195
|
+
function merged(left, right) {
|
|
196
|
+
if (left === undefined)
|
|
197
|
+
return right;
|
|
198
|
+
const members = new Map(left.members);
|
|
199
|
+
for (const [token, mask] of right.members)
|
|
200
|
+
members.set(token, merged(members.get(token), mask));
|
|
201
|
+
return { whole: left.whole || right.whole, members };
|
|
202
|
+
}
|
|
203
|
+
function cut(value, mask) {
|
|
204
|
+
if (mask.whole)
|
|
205
|
+
return value;
|
|
206
|
+
if (Array.isArray(value)) {
|
|
207
|
+
const each = {
|
|
208
|
+
whole: false,
|
|
209
|
+
members: new Map([...mask.members].filter(([token]) => !ARRAY_INDEX.test(token))),
|
|
210
|
+
};
|
|
211
|
+
const kept = [];
|
|
212
|
+
value.forEach((item, index) => {
|
|
213
|
+
const part = cut(item, merged(mask.members.get(String(index)), each));
|
|
214
|
+
if (part !== undefined)
|
|
215
|
+
kept[index] = part;
|
|
216
|
+
});
|
|
217
|
+
return kept.length === 0 ? undefined : kept;
|
|
218
|
+
}
|
|
219
|
+
if (typeof value !== 'object' || value === null)
|
|
220
|
+
return undefined;
|
|
221
|
+
const kept = Object.entries(value).flatMap(([key, held]) => {
|
|
222
|
+
const member = mask.members.get(key);
|
|
223
|
+
const part = member === undefined ? undefined : cut(held, member);
|
|
224
|
+
return part === undefined ? [] : [[key, part]];
|
|
225
|
+
});
|
|
226
|
+
return kept.length === 0 ? undefined : Object.fromEntries(kept);
|
|
227
|
+
}
|
|
228
|
+
function selected(fields, pointers) {
|
|
229
|
+
return (cut(fields, masked(pointers)) ?? {});
|
|
230
|
+
}
|
|
179
231
|
function documentOf(row, shape) {
|
|
180
232
|
if (row.type === null)
|
|
181
233
|
return { room: row.room, path: row.path };
|
|
@@ -185,7 +237,11 @@ function documentOf(row, shape) {
|
|
|
185
237
|
type: row.type,
|
|
186
238
|
...(shape.fields === null
|
|
187
239
|
? {}
|
|
188
|
-
: {
|
|
240
|
+
: {
|
|
241
|
+
fields: shape.fields === 'all'
|
|
242
|
+
? row.fields
|
|
243
|
+
: selected(row.fields, shape.fields),
|
|
244
|
+
}),
|
|
189
245
|
...(shape.sections === null
|
|
190
246
|
? {}
|
|
191
247
|
: {
|
package/dist/replica.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare function readReclassified(record: ReplicaRecord, previous: Confir
|
|
|
37
37
|
};
|
|
38
38
|
export declare function applyReturned(confirmed: ConfirmedLayer, documents: Readonly<Record<string, string>>, revisions: Readonly<Record<string, string>>, removals: readonly string[], attachments: readonly RoomAttachment[] | undefined, roomVersion: string, writtenAt: string): Staged;
|
|
39
39
|
export declare function replicaOf(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], previous?: Replica): Replica;
|
|
40
|
-
export declare function landed(batch: ChangeBatch, confirmed: ConfirmedLayer): boolean;
|
|
40
|
+
export declare function landed(batch: ChangeBatch, confirmed: ConfirmedLayer, current?: Readonly<Record<string, string>>): boolean;
|
|
41
41
|
export declare function withdrawals(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], withdrawable: (batch: ChangeBatch) => boolean): readonly ChangeBatch[];
|
|
42
42
|
export {};
|
|
43
43
|
//# sourceMappingURL=replica.d.ts.map
|
package/dist/replica.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,KAAK,WAAW,EAAqB,MAAM,aAAa,CAAC;AAC1F,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA0C,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAGlF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IACjC,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GAAG,OAAO,CAAC;AAE7E,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;CAC/B,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAQhE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAWtF;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAKnF;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAkBnF;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,cAAc,GACvB,MAAM,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAM/B;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,EAAE,SAAS,cAAc,EAAE,GAAG,SAAS,EAClD,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAmCR;AAsDD,wBAAgB,SAAS,CACvB,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,QAAQ,CAAC,EAAE,OAAO,GACjB,OAAO,CAgCT;AAkFD,wBAAgB,MAAM,
|
|
1
|
+
{"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,KAAK,WAAW,EAAqB,MAAM,aAAa,CAAC;AAC1F,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA0C,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAGlF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IACjC,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GAAG,OAAO,CAAC;AAE7E,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;CAC/B,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAQhE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAWtF;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAKnF;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAkBnF;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,cAAc,GACvB,MAAM,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAM/B;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,EAAE,SAAS,cAAc,EAAE,GAAG,SAAS,EAClD,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAmCR;AAsDD,wBAAgB,SAAS,CACvB,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,QAAQ,CAAC,EAAE,OAAO,GACjB,OAAO,CAgCT;AAkFD,wBAAgB,MAAM,CACpB,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,cAAc,EACzB,OAAO,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,GAC7C,OAAO,CAaT;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,GAC5C,SAAS,WAAW,EAAE,CAmBxB"}
|
package/dist/replica.js
CHANGED
|
@@ -229,8 +229,8 @@ function after(changes, index, path) {
|
|
|
229
229
|
}
|
|
230
230
|
return at;
|
|
231
231
|
}
|
|
232
|
-
export function landed(batch, confirmed) {
|
|
233
|
-
const layer = confirmed.record;
|
|
232
|
+
export function landed(batch, confirmed, current = {}) {
|
|
233
|
+
const layer = { ...confirmed.record, documents: { ...confirmed.record.documents, ...current } };
|
|
234
234
|
return batch.changes.every((change, index) => {
|
|
235
235
|
if (change.kind === 'replace' || (change.kind === 'create' && 'content' in change)) {
|
|
236
236
|
const at = after(batch.changes, index, change.path);
|
package/dist/rows.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type DocumentRow = {
|
|
|
10
10
|
type: string | null;
|
|
11
11
|
fields: Fields;
|
|
12
12
|
values: Fields;
|
|
13
|
-
|
|
13
|
+
reached: Readonly<Record<string, readonly unknown[]>>;
|
|
14
14
|
directories: readonly string[];
|
|
15
15
|
body: string;
|
|
16
16
|
change: HeadChange | null;
|
|
@@ -31,6 +31,7 @@ export type ReferenceRow = {
|
|
|
31
31
|
source: string;
|
|
32
32
|
target: string;
|
|
33
33
|
field: string;
|
|
34
|
+
forms: readonly string[];
|
|
34
35
|
path: string;
|
|
35
36
|
type: string;
|
|
36
37
|
};
|
package/dist/rows.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../src/rows.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../src/rows.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9D,KAAK,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEhD,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC,CAAC;IACtD,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG,WAAW,GAAG,OAAO,GAAG,YAAY,CAAC;AAMvD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAmFD,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,UAAU,GAAG,IAAI,GACxB,SAAS,GAAG,EAAE,CAuEhB"}
|
package/dist/rows.js
CHANGED
|
@@ -1,21 +1,65 @@
|
|
|
1
|
-
import { target } from '@agentshouse/mdmodel';
|
|
1
|
+
import { ARRAY_INDEX, escapePointer, references, target, } from '@agentshouse/mdmodel';
|
|
2
2
|
import { governing } from './collection.js';
|
|
3
|
-
import { definitionOf
|
|
3
|
+
import { definitionOf } from './model.js';
|
|
4
4
|
function keyOf(...parts) {
|
|
5
5
|
return `${parts.join('\u0000')}\u0000`;
|
|
6
6
|
}
|
|
7
7
|
export function documentKey(room, path) {
|
|
8
8
|
return keyOf('d', room, path);
|
|
9
9
|
}
|
|
10
|
-
function
|
|
11
|
-
return typeof value === '
|
|
10
|
+
function plainObject(value) {
|
|
11
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
12
12
|
}
|
|
13
|
-
function
|
|
14
|
-
if (
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
function compared(reading, exact, value) {
|
|
14
|
+
if (!reading.references.has(exact))
|
|
15
|
+
return value;
|
|
16
|
+
return (typeof value === 'string' ? target(reading.path, value) : null) ?? undefined;
|
|
17
|
+
}
|
|
18
|
+
function record(reading, node, forms, exact) {
|
|
19
|
+
const value = Array.isArray(node)
|
|
20
|
+
? node.map((item, index) => compared(reading, `${exact}/${index}`, item))
|
|
21
|
+
: compared(reading, exact, node);
|
|
22
|
+
for (const form of forms) {
|
|
23
|
+
if (form.pending)
|
|
24
|
+
continue;
|
|
25
|
+
(reading.reached[form.text] ??= []).push(value);
|
|
26
|
+
if (!form.through && value !== undefined && !plainObject(value)) {
|
|
27
|
+
reading.values[form.text] = value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(node) || plainObject(node) || !reading.references.has(exact))
|
|
31
|
+
return;
|
|
32
|
+
const found = compared(reading, exact, node);
|
|
33
|
+
if (typeof found !== 'string')
|
|
34
|
+
return;
|
|
35
|
+
const field = forms
|
|
36
|
+
.map((form) => form.text)
|
|
37
|
+
.reduce((left, right) => (right.length < left.length ? right : left));
|
|
38
|
+
const known = reading.targets.get(`${field}\u0000${found}`);
|
|
39
|
+
const kept = known ?? { field, target: found, forms: new Set() };
|
|
40
|
+
for (const form of forms)
|
|
41
|
+
kept.forms.add(form.text);
|
|
42
|
+
reading.targets.set(`${field}\u0000${found}`, kept);
|
|
43
|
+
}
|
|
44
|
+
function walk(reading, node, forms, exact) {
|
|
45
|
+
record(reading, node, forms, exact);
|
|
46
|
+
if (Array.isArray(node)) {
|
|
47
|
+
node.forEach((item, index) => walk(reading, item, forms.flatMap((form) => [
|
|
48
|
+
...(form.pending
|
|
49
|
+
? []
|
|
50
|
+
: [{ text: `${form.text}/${index}`, through: form.through, pending: false }]),
|
|
51
|
+
{ text: form.text, through: true, pending: true },
|
|
52
|
+
]), `${exact}/${index}`));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!plainObject(node))
|
|
56
|
+
return;
|
|
57
|
+
for (const [key, value] of Object.entries(node)) {
|
|
58
|
+
const segment = escapePointer(key);
|
|
59
|
+
walk(reading, value, forms.flatMap((form) => form.pending && ARRAY_INDEX.test(key)
|
|
60
|
+
? []
|
|
61
|
+
: [{ text: `${form.text}/${segment}`, through: form.through, pending: false }]), `${exact}/${segment}`);
|
|
62
|
+
}
|
|
19
63
|
}
|
|
20
64
|
function directoriesOf(path) {
|
|
21
65
|
const parts = path.split('/').slice(0, -1);
|
|
@@ -34,7 +78,7 @@ export function rowsOf(room, path, document, composition, change) {
|
|
|
34
78
|
type: null,
|
|
35
79
|
fields: {},
|
|
36
80
|
values: {},
|
|
37
|
-
|
|
81
|
+
reached: {},
|
|
38
82
|
directories: directoriesOf(path),
|
|
39
83
|
body,
|
|
40
84
|
change,
|
|
@@ -43,32 +87,18 @@ export function rowsOf(room, path, document, composition, change) {
|
|
|
43
87
|
}
|
|
44
88
|
const type = document.type ?? 'any';
|
|
45
89
|
const definition = definitionOf(governing(composition, path), document.type);
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
90
|
+
const reading = {
|
|
91
|
+
path,
|
|
92
|
+
references: new Set(definition === undefined ? [] : references(document, definition).map((one) => one.pointer)),
|
|
93
|
+
values: {},
|
|
94
|
+
reached: {},
|
|
95
|
+
targets: new Map(),
|
|
96
|
+
};
|
|
49
97
|
for (const [name, value] of Object.entries(document.fields)) {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
if (compared !== undefined)
|
|
53
|
-
values[name] = compared;
|
|
54
|
-
if (Array.isArray(value))
|
|
55
|
-
sizes[name] = value.length;
|
|
56
|
-
if (!reference)
|
|
57
|
-
continue;
|
|
58
|
-
const targets = [compared].flat().filter((found) => typeof found === 'string');
|
|
59
|
-
for (const found of new Set(targets)) {
|
|
60
|
-
references.push({
|
|
61
|
-
key: keyOf('r', room, path, name, found),
|
|
62
|
-
kind: 'reference',
|
|
63
|
-
room,
|
|
64
|
-
source: key,
|
|
65
|
-
target: documentKey(room, found),
|
|
66
|
-
field: name,
|
|
67
|
-
path,
|
|
68
|
-
type,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
98
|
+
const segment = escapePointer(name);
|
|
99
|
+
walk(reading, value, [{ text: `/${segment}`, through: false, pending: false }], `/${segment}`);
|
|
71
100
|
}
|
|
101
|
+
const { values, reached } = reading;
|
|
72
102
|
return [
|
|
73
103
|
{
|
|
74
104
|
key,
|
|
@@ -78,7 +108,7 @@ export function rowsOf(room, path, document, composition, change) {
|
|
|
78
108
|
type,
|
|
79
109
|
fields: document.fields,
|
|
80
110
|
values,
|
|
81
|
-
|
|
111
|
+
reached,
|
|
82
112
|
directories: directoriesOf(path),
|
|
83
113
|
body,
|
|
84
114
|
change,
|
|
@@ -92,6 +122,16 @@ export function rowsOf(room, path, document, composition, change) {
|
|
|
92
122
|
sections: document.sections,
|
|
93
123
|
markdown: document.content,
|
|
94
124
|
},
|
|
95
|
-
...
|
|
125
|
+
...[...reading.targets.values()].map(({ field, target: found, forms }) => ({
|
|
126
|
+
key: keyOf('r', room, path, field, found),
|
|
127
|
+
kind: 'reference',
|
|
128
|
+
room,
|
|
129
|
+
source: key,
|
|
130
|
+
target: documentKey(room, found),
|
|
131
|
+
field,
|
|
132
|
+
forms: [...forms].sort(),
|
|
133
|
+
path,
|
|
134
|
+
type,
|
|
135
|
+
})),
|
|
96
136
|
];
|
|
97
137
|
}
|
package/dist/save.d.ts
CHANGED