@agentshouse/mdmodel 0.1.0-c64dbada0730d → 0.1.0-c679f403bf3fb

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.
Files changed (53) hide show
  1. package/API.md +230 -216
  2. package/README.md +15 -18
  3. package/dist/blocks.d.ts.map +1 -1
  4. package/dist/blocks.js +7 -14
  5. package/dist/condition.d.ts +21 -8
  6. package/dist/condition.d.ts.map +1 -1
  7. package/dist/condition.js +208 -89
  8. package/dist/definition.d.ts +16 -1
  9. package/dist/definition.d.ts.map +1 -1
  10. package/dist/definition.js +255 -29
  11. package/dist/divide.d.ts.map +1 -1
  12. package/dist/divide.js +27 -17
  13. package/dist/document.d.ts +6 -3
  14. package/dist/document.d.ts.map +1 -1
  15. package/dist/document.js +315 -167
  16. package/dist/fields.d.ts +2 -0
  17. package/dist/fields.d.ts.map +1 -1
  18. package/dist/fields.js +7 -0
  19. package/dist/index.d.ts +14 -8
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +7 -5
  22. package/dist/links.d.ts +3 -0
  23. package/dist/links.d.ts.map +1 -1
  24. package/dist/links.js +66 -40
  25. package/dist/paths.d.ts +10 -1
  26. package/dist/paths.d.ts.map +1 -1
  27. package/dist/paths.js +115 -12
  28. package/dist/project.d.ts +1 -0
  29. package/dist/project.d.ts.map +1 -1
  30. package/dist/project.js +38 -15
  31. package/dist/references.d.ts +2 -2
  32. package/dist/references.d.ts.map +1 -1
  33. package/dist/references.js +6 -1
  34. package/dist/schema.js +2 -2
  35. package/dist/types.d.ts +49 -2
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/validate.d.ts +30 -2
  38. package/dist/validate.d.ts.map +1 -1
  39. package/dist/validate.js +290 -115
  40. package/dist/yaml.d.ts +7 -3
  41. package/dist/yaml.d.ts.map +1 -1
  42. package/dist/yaml.js +72 -43
  43. package/fixtures/README.md +6 -5
  44. package/fixtures/cases/cross-room-link/context.json +1 -0
  45. package/fixtures/cases/cross-room-link/expected.json +1 -0
  46. package/fixtures/cases/cross-room-link/library/clients/acme.md +6 -0
  47. package/fixtures/cases/cross-room-link/schema.yaml +3 -0
  48. package/fixtures/cases/cross-room-reference/context.json +1 -0
  49. package/fixtures/cases/cross-room-reference/expected.json +1 -0
  50. package/fixtures/cases/cross-room-reference/library/clients/acme.md +9 -0
  51. package/fixtures/cases/cross-room-reference/schema.yaml +9 -0
  52. package/fixtures/division.json +26 -26
  53. package/package.json +4 -2
package/README.md CHANGED
@@ -26,30 +26,27 @@ if (checked.verdict === 'accept') {
26
26
 
27
27
  const parsed = parse('---\ntype: note\ntitle: Hello\n---\n');
28
28
  if (parsed.ok) {
29
- const next = apply(parsed.document, {
30
- kind: 'field',
31
- name: 'title',
32
- value: 'World',
33
- prior: 'Hello',
34
- });
29
+ const next = apply(parsed.document, [
30
+ { kind: 'field', name: 'title', value: 'World', prior: 'Hello' },
31
+ ]);
35
32
  if (next.outcome === 'applied') serialize(next.document);
36
33
  }
37
34
  ```
38
35
 
39
36
  ## API
40
37
 
41
- | Export | Purpose |
42
- | ---------------------------------------------- | ----------------------------------------------------------------- |
43
- | `verify` | Verify one schema text into a model of MD Types |
44
- | `validate` | Validate a text Library; returns acceptance or one refusal |
45
- | `parse`, `serialize` | Read and write one Document |
46
- | `apply` | Apply one field, section, preamble, or link change |
47
- | `links`, `target`, `retarget` | Inventory and rewrite link destinations |
48
- | `escapePointer` | Write one key as a JSON Pointer token |
49
- | `project`, `divide` | Embedding projection input and its division into Spans |
50
- | `facts`, `factKind`, `holds`, `fires` | A condition over a Document and over one of its changes |
51
- | `MARKDOWN_SYNTAX_PROFILE`, `VERSION` | The pinned Markdown profile (GFM 0.29) and MD model version |
52
- | `MEMBER_FIELD`, `SITE_FIELD`, `RECEIVED_FIELD` | The field names validation counts as declared beyond a type's own |
38
+ | Export | Purpose |
39
+ | ---------------------------------------------- | ------------------------------------------------------------------ |
40
+ | `verify` | Verify one schema text into a model of MD Types |
41
+ | `validate` | Validate a text Library; returns acceptance or one refusal |
42
+ | `parse`, `serialize` | Read and write one Document |
43
+ | `apply` | Apply field, section, preamble, link and reference changes at once |
44
+ | `links`, `target`, `retarget` | Inventory and rewrite link destinations |
45
+ | `escapePointer` | Write one key as a JSON Pointer token |
46
+ | `project`, `divide` | Embedding projection input and its division into Spans |
47
+ | `facts`, `factKind`, `holds`, `fires` | A condition over a Document and over one of its changes |
48
+ | `MARKDOWN_SYNTAX_PROFILE`, `VERSION` | The pinned Markdown profile (GFM 0.29) and MD model version |
49
+ | `MEMBER_FIELD`, `SITE_FIELD`, `RECEIVED_FIELD` | The field names validation counts as declared beyond a type's own |
53
50
 
54
51
  The full reference is in [`API.md`](API.md). The conformance corpus and its
55
52
  verdict format and rule ids are described in [`fixtures/README.md`](fixtures/README.md).
@@ -1 +1 @@
1
- {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../src/blocks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAqCF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,EAAE,CA+BrF;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAe/E"}
1
+ {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../src/blocks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AA+BF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,EAAE,CA8BrF;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAe/E"}
package/dist/blocks.js CHANGED
@@ -1,5 +1,5 @@
1
- import { fenceSpans } from './links.js';
2
- const HEADING = /^(#{1,6})(?!#)[ \t]+(.+?)[ \t]*#*[ \t]*$/;
1
+ import { fenceSpans, spanCursor } from './links.js';
2
+ const HEADING = /^(#{1,6})(?!#)[ \t]+(.+?)(?:[ \t]+#+)?[ \t]*$/;
3
3
  function lineAt(content, from, to) {
4
4
  const nl = content.indexOf('\n', from);
5
5
  const end = nl === -1 || nl >= to ? to : nl;
@@ -7,17 +7,11 @@ function lineAt(content, from, to) {
7
7
  return { text: raw.endsWith('\r') ? raw.slice(0, -1) : raw, next: end === to ? to : end + 1 };
8
8
  }
9
9
  function scan(content, from, to, visit) {
10
- const fences = fenceSpans(content.slice(from, to));
10
+ const fenced = spanCursor(fenceSpans(content.slice(from, to)));
11
11
  let i = from;
12
12
  while (i < to) {
13
13
  const { text, next } = lineAt(content, i, to);
14
- const at = i - from;
15
- visit({
16
- text,
17
- start: i,
18
- next,
19
- fenced: fences.some(([start, end]) => at >= start && at < end),
20
- });
14
+ visit({ text, start: i, next, fenced: fenced(i - from) !== undefined });
21
15
  if (next === i)
22
16
  break;
23
17
  i = next;
@@ -26,16 +20,15 @@ function scan(content, from, to, visit) {
26
20
  const HASH = 0x23;
27
21
  export function headingLines(content, from, to) {
28
22
  const found = [];
29
- let fences = null;
23
+ let fenced = null;
30
24
  let i = from;
31
25
  while (i < to) {
32
26
  const nl = content.indexOf('\n', i);
33
27
  const end = nl === -1 || nl >= to ? to : nl;
34
28
  const next = end === to ? to : end + 1;
35
29
  if (content.charCodeAt(i) === HASH) {
36
- fences ??= fenceSpans(content.slice(from, to));
37
- const at = i - from;
38
- if (!fences.some(([start, stop]) => at >= start && at < stop)) {
30
+ fenced ??= spanCursor(fenceSpans(content.slice(from, to)));
31
+ if (fenced(i - from) === undefined) {
39
32
  const { text } = lineAt(content, i, to);
40
33
  const match = HEADING.exec(text);
41
34
  const hashes = match?.[1];
@@ -1,8 +1,8 @@
1
- import { type ValueFacts } from './definition.js';
1
+ import { type Definition, type ValueFacts } from './definition.js';
2
2
  import type { Document, VerifiedModel } from './types.js';
3
- export type ConditionValue = string | number | boolean | {
4
- readonly owner: true;
5
- };
3
+ export type ConditionValue = string | number | boolean;
4
+ export declare const CONDITION_OPERATORS: readonly ['eq', 'in', 'exists', 'contains', 'gt', 'gte', 'lt', 'lte', 'prefix'];
5
+ export type ConditionOperator = (typeof CONDITION_OPERATORS)[number];
6
6
  export type ConditionTest = {
7
7
  readonly all: readonly ConditionTest[];
8
8
  } | {
@@ -41,6 +41,7 @@ type DocumentEventBase = {
41
41
  readonly on: 'documents';
42
42
  readonly scope: ConditionScope;
43
43
  readonly by?: ConditionTest;
44
+ readonly moved_between_rooms?: boolean;
44
45
  };
45
46
  export type DocumentCondition = (DocumentEventBase & {
46
47
  readonly mode: 'starts_matching';
@@ -114,13 +115,13 @@ export type DocumentEvent = {
114
115
  readonly after: DocumentFacts | null;
115
116
  readonly changed: readonly string[];
116
117
  readonly by: Actor;
118
+ readonly moved_between_rooms: boolean;
117
119
  };
118
120
  export type ItemFacts = {
119
121
  readonly delivery: string;
120
122
  readonly source: string | null;
121
123
  readonly address: string | null;
122
124
  readonly has_attachment: boolean;
123
- readonly provider: string | null;
124
125
  readonly container: string | null;
125
126
  readonly author: string | null;
126
127
  readonly headers: Readonly<Record<string, string>>;
@@ -139,11 +140,23 @@ export declare function facts(document: Document, at: {
139
140
  readonly path: string;
140
141
  }, model: VerifiedModel, resolve: (target: string) => Resolved | undefined): DocumentFacts;
141
142
  export declare function prosePaths(facts: DocumentFacts): string[];
143
+ export declare function datePointers(fields: Readonly<Record<string, ValueFacts>>): string[];
144
+ export declare function valuedChange(definition: Definition, field: string): boolean;
145
+ export declare function changeFields(definition: Definition): string[];
146
+ export declare function memberPointers(definition: Definition, memberType: string): string[];
147
+ export declare const DOCUMENT_PATHS: readonly string[];
148
+ export declare const ACTOR_PATHS: readonly string[];
149
+ export declare const ITEM_PATHS: readonly string[];
150
+ export declare function testOperators(definitions: readonly Definition[], path: string, memberType: string | null): readonly ConditionOperator[];
151
+ export declare function actorOperators(path: string): readonly ConditionOperator[];
152
+ export declare function itemOperators(path: string): readonly ConditionOperator[];
153
+ export declare function itemKind(path: string): FactKind | null;
142
154
  export declare function dated(value: unknown): value is string;
143
155
  export declare function instant(value: unknown): bigint | undefined;
144
156
  export declare function pointed(value: unknown, pointer: string): unknown;
145
- export declare function holds(test: ConditionTest, document: DocumentFacts, owner: string): Truth;
146
- export declare function fires(condition: DocumentCondition, event: DocumentEvent, owner: string): boolean;
147
- export declare function itemFires(condition: ItemCondition, item: ItemFacts, owner: string): boolean;
157
+ export declare function members(document: DocumentFacts, path: string): readonly string[];
158
+ export declare function holds(test: ConditionTest, document: DocumentFacts): Truth;
159
+ export declare function fires(condition: DocumentCondition, event: DocumentEvent): boolean;
160
+ export declare function itemFires(condition: ItemCondition, item: ItemFacts): boolean;
148
161
  export {};
149
162
  //# sourceMappingURL=condition.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":"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"}
package/dist/condition.js CHANGED
@@ -1,6 +1,17 @@
1
- import { ARRAY_INDEX, escapePointer, fieldFacts, itemFacts, memberFacts, pointerSegments, } from './definition.js';
2
- import { target } from './paths.js';
3
- import { isRecord } from './yaml.js';
1
+ import { ARRAY_INDEX, escapePointer, fieldFacts, itemFacts, memberFacts, pointerFacts, pointerSegments, } from './definition.js';
2
+ import { roomPath, target } from './paths.js';
3
+ import { plain } from './yaml.js';
4
+ export const CONDITION_OPERATORS = [
5
+ 'eq',
6
+ 'in',
7
+ 'exists',
8
+ 'contains',
9
+ 'gt',
10
+ 'gte',
11
+ 'lt',
12
+ 'lte',
13
+ 'prefix',
14
+ ];
4
15
  export const WRITE_DOORS = ['browser', 'agent', 'client'];
5
16
  const PROSE = { kind: 'prose' };
6
17
  const NULL = { kind: 'null' };
@@ -8,6 +19,7 @@ const UNREADABLE = { kind: 'unreadable' };
8
19
  const UNREAD = { present: undefined, values: [undefined], items: [undefined] };
9
20
  const NO_ITEM = { present: false, values: [], items: [] };
10
21
  const DATE = /^\d{4}-\d{2}-\d{2}$/u;
22
+ const HEADER = /^\/headers\/[!#$%&'*+.^_`|~0-9a-z-]+$/u;
11
23
  const DATE_TIME = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(?:[Zz]|([+-])(\d{2}):(\d{2}))$/u;
12
24
  export function factKind(facts) {
13
25
  if (facts.reference !== undefined)
@@ -71,7 +83,7 @@ function factOf(value, declared, place) {
71
83
  return UNREADABLE;
72
84
  if (kind !== 'reference')
73
85
  return { kind, value };
74
- const reached = target(place.path, value);
86
+ const reached = target(place.path, value) ?? roomPath(value);
75
87
  const resolved = reached === null ? undefined : place.resolve(reached);
76
88
  if (resolved === undefined)
77
89
  return UNREADABLE;
@@ -181,10 +193,9 @@ function documentRead({ reached, several, missing }, held) {
181
193
  };
182
194
  }
183
195
  function readDocument(facts, path) {
184
- if (path === '/path')
185
- return single({ kind: 'path', value: facts.path });
186
- if (path === '/type')
187
- return facts.type === null ? undefined : single({ kind: 'string', value: facts.type });
196
+ const own = tested(DOCUMENT_TESTS, path);
197
+ if (own !== undefined)
198
+ return own.read(facts, path);
188
199
  if (path.startsWith('/sections/'))
189
200
  return facts.sections.includes(path.slice('/sections/'.length))
190
201
  ? single({ kind: 'prose' })
@@ -195,21 +206,146 @@ function readDocument(facts, path) {
195
206
  return documentRead(walked(rootOf(facts, '/members'), path.slice('/members'.length)), memberHeld);
196
207
  return undefined;
197
208
  }
198
- function readActor(actor, path) {
199
- const value = path === '/user'
200
- ? actor.user
201
- : path === '/site'
202
- ? actor.site
203
- : path === '/door'
204
- ? actor.door
205
- : undefined;
206
- return value === undefined ? undefined : single({ kind: 'actor', value });
209
+ export function datePointers(fields) {
210
+ return Object.entries(fields)
211
+ .filter(([, facts]) => facts.type === 'string' && facts.format === 'date')
212
+ .map(([name]) => `/fields/${escapePointer(name)}`)
213
+ .sort();
207
214
  }
208
- function plain(value) {
209
- if (!isRecord(value))
215
+ export function valuedChange(definition, field) {
216
+ if (!field.startsWith('/fields/'))
210
217
  return false;
211
- const prototype = Object.getPrototypeOf(value);
212
- return prototype === Object.prototype || prototype === null;
218
+ const reached = pointerFacts(definition, field.slice('/fields'.length));
219
+ return (reached !== undefined &&
220
+ !reached.through &&
221
+ reached.facts.type !== 'array' &&
222
+ !reached.facts.prose &&
223
+ factKind(reached.facts) !== null);
224
+ }
225
+ export function changeFields(definition) {
226
+ return [
227
+ ...Object.keys(definition.fields).map((name) => `/fields/${escapePointer(name)}`),
228
+ ...Object.keys(definition.sections).map((heading) => `/sections/${heading}`),
229
+ ];
230
+ }
231
+ export function memberPointers(definition, memberType) {
232
+ return Object.entries(definition.fields)
233
+ .filter(([, facts]) => (facts.type === 'array' ? facts.items : facts)?.reference?.includes(memberType) === true)
234
+ .map(([name]) => `/members/${escapePointer(name)}`);
235
+ }
236
+ function kindOperators(kind) {
237
+ switch (kind) {
238
+ case 'string':
239
+ return ['eq', 'in', 'prefix', 'exists'];
240
+ case 'boolean':
241
+ return ['eq', 'exists'];
242
+ case 'number':
243
+ case 'date':
244
+ case 'time':
245
+ return ['eq', 'in', 'gt', 'gte', 'lt', 'lte', 'exists'];
246
+ default:
247
+ return ['eq', 'in', 'exists'];
248
+ }
249
+ }
250
+ function pointerOperators({ facts, through }) {
251
+ const scalar = facts.type === 'array' ? facts.items : facts;
252
+ const kind = scalar === undefined || scalar.prose ? null : factKind(scalar);
253
+ if (kind === null)
254
+ return ['exists'];
255
+ if (facts.type === 'array')
256
+ return ['contains', 'exists'];
257
+ const own = kindOperators(kind);
258
+ return through ? [...own.filter((operator) => operator !== 'exists'), 'contains', 'exists'] : own;
259
+ }
260
+ function typeOperators(definition, path, memberType) {
261
+ if (path.startsWith('/sections/'))
262
+ return Object.hasOwn(definition.sections, path.slice('/sections/'.length)) ? ['exists'] : [];
263
+ const pointer = path.startsWith('/fields/')
264
+ ? path.slice('/fields'.length)
265
+ : memberType !== null && memberPointers(definition, memberType).includes(path)
266
+ ? path.slice('/members'.length)
267
+ : undefined;
268
+ const reached = pointer === undefined ? undefined : pointerFacts(definition, pointer);
269
+ return reached === undefined ? [] : pointerOperators(reached);
270
+ }
271
+ function envelope(path, kind, value) {
272
+ return {
273
+ path,
274
+ names: (named) => named === path,
275
+ kind,
276
+ operators: kindOperators(kind),
277
+ read: (facts) => {
278
+ const held = value(facts);
279
+ return held === null || held === undefined ? undefined : single({ kind, value: held });
280
+ },
281
+ };
282
+ }
283
+ function tested(tests, path) {
284
+ return tests.find(({ names }) => names(path));
285
+ }
286
+ function reader(tests, facts) {
287
+ return (path) => tested(tests, path)?.read(facts, path);
288
+ }
289
+ const DOCUMENT_TESTS = [
290
+ {
291
+ path: '/path',
292
+ names: (named) => named === '/path',
293
+ kind: 'string',
294
+ operators: ['eq', 'in', 'prefix'],
295
+ read: (facts) => single({ kind: 'string', value: facts.path }),
296
+ },
297
+ envelope('/type', 'enum', (facts) => facts.type),
298
+ ];
299
+ const ACTOR_TESTS = [
300
+ envelope('/user', 'enum', (actor) => actor.user),
301
+ envelope('/site', 'enum', (actor) => actor.site),
302
+ envelope('/door', 'enum', (actor) => actor.door),
303
+ ];
304
+ const ITEM_TESTS = [
305
+ envelope('/delivery', 'enum', (item) => item.delivery),
306
+ envelope('/source', 'enum', (item) => item.source),
307
+ envelope('/has_attachment', 'boolean', (item) => item.has_attachment),
308
+ envelope('/container', 'string', (item) => item.container),
309
+ envelope('/author', 'string', (item) => item.author),
310
+ {
311
+ path: '/headers/<lowercase name>',
312
+ names: (named) => HEADER.test(named),
313
+ kind: 'string',
314
+ operators: kindOperators('string'),
315
+ read: (item, path) => {
316
+ const name = path.slice('/headers/'.length);
317
+ return Object.hasOwn(item.headers, name)
318
+ ? single({ kind: 'string', value: item.headers[name] })
319
+ : undefined;
320
+ },
321
+ },
322
+ {
323
+ path: '/json/<JSON Pointer>',
324
+ names: (named) => named.startsWith('/json/'),
325
+ kind: null,
326
+ operators: CONDITION_OPERATORS,
327
+ read: (item, path) => item.json === null ? UNREAD : jsonRead(pointed(item.json.value, path.slice('/json'.length))),
328
+ },
329
+ ];
330
+ export const DOCUMENT_PATHS = DOCUMENT_TESTS.map(({ path }) => path);
331
+ export const ACTOR_PATHS = ACTOR_TESTS.map(({ path }) => path);
332
+ export const ITEM_PATHS = ITEM_TESTS.map(({ path }) => path);
333
+ export function testOperators(definitions, path, memberType) {
334
+ const own = tested(DOCUMENT_TESTS, path);
335
+ if (own !== undefined)
336
+ return own.operators;
337
+ return [
338
+ ...new Set(definitions.flatMap((definition) => typeOperators(definition, path, memberType))),
339
+ ];
340
+ }
341
+ export function actorOperators(path) {
342
+ return tested(ACTOR_TESTS, path)?.operators ?? [];
343
+ }
344
+ export function itemOperators(path) {
345
+ return tested(ITEM_TESTS, path)?.operators ?? [];
346
+ }
347
+ export function itemKind(path) {
348
+ return tested(ITEM_TESTS, path)?.kind ?? null;
213
349
  }
214
350
  export function dated(value) {
215
351
  return (typeof value === 'string' && DATE.test(value) && instant(`${value}T00:00:00Z`) !== undefined);
@@ -239,11 +375,8 @@ export function instant(value) {
239
375
  return (BigInt(at.getTime()) - BigInt(offset) * 60000n) * 1000000n + BigInt(fraction);
240
376
  }
241
377
  export function pointed(value, pointer) {
242
- if (pointer === '')
243
- return value;
244
378
  let reached = value;
245
- for (const part of pointer.slice(1).split('/')) {
246
- const token = part.replaceAll('~1', '/').replaceAll('~0', '~');
379
+ for (const token of pointerSegments(pointer)) {
247
380
  if (Array.isArray(reached)) {
248
381
  if (!ARRAY_INDEX.test(token))
249
382
  return undefined;
@@ -282,46 +415,15 @@ function jsonRead(value) {
282
415
  return single({ kind: 'prose' });
283
416
  return { present: true, values: [], items: value.filter(scalar).map(jsonHeld), loose: true };
284
417
  }
285
- function readItem(item, path) {
286
- if (path.startsWith('/json/')) {
287
- if (item.json === null)
288
- return UNREAD;
289
- return jsonRead(pointed(item.json.value, path.slice('/json'.length)));
290
- }
291
- if (path.startsWith('/headers/')) {
292
- const name = path.slice('/headers/'.length);
293
- return Object.hasOwn(item.headers, name)
294
- ? single({ kind: 'string', value: item.headers[name] })
295
- : undefined;
296
- }
297
- if (path === '/has_attachment')
298
- return single({ kind: 'boolean', value: item.has_attachment });
299
- const value = path === '/delivery'
300
- ? item.delivery
301
- : path === '/source'
302
- ? item.source
303
- : path === '/provider'
304
- ? item.provider
305
- : path === '/container'
306
- ? item.container
307
- : path === '/author'
308
- ? item.author
309
- : null;
310
- return value === null ? undefined : single({ kind: 'string', value });
311
- }
312
- function wanted(value, owner) {
313
- return isRecord(value) && value.owner === true ? owner : value;
314
- }
315
- function equal(held, value, owner) {
418
+ function equal(held, value) {
316
419
  if (!('value' in held))
317
420
  return undefined;
318
- const expected = wanted(value, owner);
319
- if (typeof expected !== typeof held.value)
421
+ if (typeof value !== typeof held.value)
320
422
  return undefined;
321
423
  if (held.kind !== 'time')
322
- return expected === held.value;
424
+ return value === held.value;
323
425
  const left = instant(held.value);
324
- const right = instant(expected);
426
+ const right = instant(value);
325
427
  return left === undefined || right === undefined ? undefined : left === right;
326
428
  }
327
429
  function sign(left, right) {
@@ -358,11 +460,11 @@ function allOf(truths) {
358
460
  return false;
359
461
  return truths.some((truth) => truth === undefined) ? undefined : true;
360
462
  }
361
- function compared(test, held, owner) {
463
+ function compared(test, held) {
362
464
  if ('eq' in test)
363
- return equal(held, test.eq, owner);
465
+ return equal(held, test.eq);
364
466
  if ('in' in test)
365
- return anyOf(test.in.map((value) => equal(held, value, owner)));
467
+ return anyOf(test.in.map((value) => equal(held, value)));
366
468
  if ('prefix' in test) {
367
469
  if (!('value' in held) || typeof held.value !== 'string')
368
470
  return undefined;
@@ -378,7 +480,7 @@ function compared(test, held, owner) {
378
480
  return ordered(held, test.lt, (sign) => sign < 0);
379
481
  return ordered(held, test.lte, (sign) => sign <= 0);
380
482
  }
381
- function leaf(test, read, owner) {
483
+ function leaf(test, read) {
382
484
  if ('exists' in test) {
383
485
  const present = read === undefined ? false : read.present;
384
486
  return present === undefined ? undefined : present === test.exists;
@@ -388,26 +490,37 @@ function leaf(test, read, owner) {
388
490
  if ('contains' in test) {
389
491
  if (read.items === null)
390
492
  return undefined;
391
- const truths = read.items.map((item) => item === undefined ? undefined : equal(item, test.contains, owner));
493
+ const truths = read.items.map((item) => item === undefined ? undefined : equal(item, test.contains));
392
494
  return read.loose === true && !truths.includes(true) ? false : anyOf(truths);
393
495
  }
394
496
  if (read.values.length === 0)
395
497
  return read === NO_ITEM ? false : undefined;
396
- return anyOf(read.values.map((value) => (value === undefined ? undefined : compared(test, value, owner))));
498
+ return anyOf(read.values.map((value) => (value === undefined ? undefined : compared(test, value))));
397
499
  }
398
- function evaluated(test, read, owner) {
500
+ function evaluated(test, read) {
399
501
  if ('all' in test)
400
- return allOf(test.all.map((part) => evaluated(part, read, owner)));
502
+ return allOf(test.all.map((part) => evaluated(part, read)));
401
503
  if ('any' in test)
402
- return anyOf(test.any.map((part) => evaluated(part, read, owner)));
504
+ return anyOf(test.any.map((part) => evaluated(part, read)));
403
505
  if ('not' in test) {
404
- const truth = evaluated(test.not, read, owner);
506
+ const truth = evaluated(test.not, read);
405
507
  return truth === undefined ? undefined : !truth;
406
508
  }
407
- return leaf(test, read(test.path), owner);
509
+ return leaf(test, read(test.path));
510
+ }
511
+ export function members(document, path) {
512
+ if (!path.startsWith('/members/'))
513
+ return [];
514
+ const read = readDocument(document, path);
515
+ const values = read === undefined ? [] : [...read.values, ...(read.items ?? [])];
516
+ return [
517
+ ...new Set(values.flatMap((value) => value !== undefined && value.kind === 'member' && 'value' in value
518
+ ? [String(value.value)]
519
+ : [])),
520
+ ].sort();
408
521
  }
409
- export function holds(test, document, owner) {
410
- return evaluated(test, (path) => readDocument(document, path), owner);
522
+ export function holds(test, document) {
523
+ return evaluated(test, (path) => readDocument(document, path));
411
524
  }
412
525
  function inScope(scope, document) {
413
526
  if (document === null)
@@ -418,10 +531,10 @@ function inScope(scope, document) {
418
531
  return document.id === scope.document;
419
532
  return scope.folder === '/' || document.path.startsWith(`${scope.folder}/`);
420
533
  }
421
- function matched(condition, test, document, owner) {
534
+ function matched(condition, test, document) {
422
535
  if (!inScope(condition.scope, document))
423
536
  return false;
424
- return test === undefined || holds(test, document, owner) === true;
537
+ return test === undefined || holds(test, document) === true;
425
538
  }
426
539
  function reachedAt(document, field) {
427
540
  if (document === null)
@@ -444,15 +557,20 @@ function valueOf(fact) {
444
557
  .sort()
445
558
  .map((key) => [key, valueOf(fact.fields[key])]),
446
559
  };
560
+ if (fact.kind === 'time') {
561
+ const at = instant(fact.value);
562
+ if (at !== undefined)
563
+ return { kind: fact.kind, at: String(at) };
564
+ }
447
565
  return 'value' in fact ? { kind: fact.kind, value: fact.value } : fact;
448
566
  }
449
567
  function signature(reached) {
450
568
  return JSON.stringify(reached.map(({ fact }) => valueOf(fact)));
451
569
  }
452
- function among(values, document, field, owner) {
453
- return holds({ path: field, in: values }, document, owner) === true;
570
+ function among(values, document, field) {
571
+ return holds({ path: field, in: values }, document) === true;
454
572
  }
455
- function fieldChanged(condition, event, owner) {
573
+ function fieldChanged(condition, event) {
456
574
  const { field, from, to } = condition;
457
575
  const before = reachedAt(event.before, field);
458
576
  const after = reachedAt(event.after, field);
@@ -466,32 +584,33 @@ function fieldChanged(condition, event, owner) {
466
584
  return false;
467
585
  if (from === 'new'
468
586
  ? event.before !== null
469
- : from !== undefined && (event.before === null || !among(from, event.before, field, owner)))
587
+ : from !== undefined && (event.before === null || !among(from, event.before, field)))
470
588
  return false;
471
589
  if (to === 'deleted'
472
590
  ? event.after !== null
473
- : to !== undefined && (event.after === null || !among(to, event.after, field, owner)))
591
+ : to !== undefined && (event.after === null || !among(to, event.after, field)))
474
592
  return false;
475
593
  return true;
476
594
  }
477
- export function fires(condition, event, owner) {
478
- if (condition.by !== undefined &&
479
- evaluated(condition.by, (path) => readActor(event.by, path), owner) !== true)
595
+ export function fires(condition, event) {
596
+ if (condition.moved_between_rooms !== undefined &&
597
+ condition.moved_between_rooms !== event.moved_between_rooms)
598
+ return false;
599
+ if (condition.by !== undefined && evaluated(condition.by, reader(ACTOR_TESTS, event.by)) !== true)
480
600
  return false;
481
601
  if (condition.mode === 'starts_matching') {
482
602
  if (event.before === null && !condition.new_documents)
483
603
  return false;
484
- return (matched(condition, condition.match, event.after, owner) &&
485
- !matched(condition, condition.match, event.before, owner));
604
+ return (matched(condition, condition.match, event.after) &&
605
+ !matched(condition, condition.match, event.before));
486
606
  }
487
607
  const side = event.after ?? event.before;
488
- return matched(condition, condition.match, side, owner) && fieldChanged(condition, event, owner);
608
+ return matched(condition, condition.match, side) && fieldChanged(condition, event);
489
609
  }
490
- export function itemFires(condition, item, owner) {
610
+ export function itemFires(condition, item) {
491
611
  if (condition.source !== undefined && item.source !== condition.source)
492
612
  return false;
493
613
  if (condition.address !== undefined && item.address !== condition.address)
494
614
  return false;
495
- return (condition.match === undefined ||
496
- evaluated(condition.match, (path) => readItem(item, path), owner) === true);
615
+ return (condition.match === undefined || evaluated(condition.match, reader(ITEM_TESTS, item)) === true);
497
616
  }