@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.
- package/API.md +230 -216
- package/README.md +15 -18
- package/dist/blocks.d.ts.map +1 -1
- package/dist/blocks.js +7 -14
- package/dist/condition.d.ts +21 -8
- package/dist/condition.d.ts.map +1 -1
- package/dist/condition.js +208 -89
- package/dist/definition.d.ts +16 -1
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +255 -29
- package/dist/divide.d.ts.map +1 -1
- package/dist/divide.js +27 -17
- package/dist/document.d.ts +6 -3
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +315 -167
- package/dist/fields.d.ts +2 -0
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +7 -0
- package/dist/index.d.ts +14 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -5
- package/dist/links.d.ts +3 -0
- package/dist/links.d.ts.map +1 -1
- package/dist/links.js +66 -40
- package/dist/paths.d.ts +10 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +115 -12
- package/dist/project.d.ts +1 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +38 -15
- package/dist/references.d.ts +2 -2
- package/dist/references.d.ts.map +1 -1
- package/dist/references.js +6 -1
- package/dist/schema.js +2 -2
- package/dist/types.d.ts +49 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/validate.d.ts +30 -2
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +290 -115
- package/dist/yaml.d.ts +7 -3
- package/dist/yaml.d.ts.map +1 -1
- package/dist/yaml.js +72 -43
- package/fixtures/README.md +6 -5
- package/fixtures/cases/cross-room-link/context.json +1 -0
- package/fixtures/cases/cross-room-link/expected.json +1 -0
- package/fixtures/cases/cross-room-link/library/clients/acme.md +6 -0
- package/fixtures/cases/cross-room-link/schema.yaml +3 -0
- package/fixtures/cases/cross-room-reference/context.json +1 -0
- package/fixtures/cases/cross-room-reference/expected.json +1 -0
- package/fixtures/cases/cross-room-reference/library/clients/acme.md +9 -0
- package/fixtures/cases/cross-room-reference/schema.yaml +9 -0
- package/fixtures/division.json +26 -26
- 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
|
-
|
|
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
|
|
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).
|
package/dist/blocks.d.ts.map
CHANGED
|
@@ -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;
|
|
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]
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
37
|
-
|
|
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];
|
package/dist/condition.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
146
|
-
export declare function
|
|
147
|
-
export declare function
|
|
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
|
package/dist/condition.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
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 {
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
209
|
-
if (!
|
|
215
|
+
export function valuedChange(definition, field) {
|
|
216
|
+
if (!field.startsWith('/fields/'))
|
|
210
217
|
return false;
|
|
211
|
-
const
|
|
212
|
-
return
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
424
|
+
return value === held.value;
|
|
323
425
|
const left = instant(held.value);
|
|
324
|
-
const right = instant(
|
|
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
|
|
463
|
+
function compared(test, held) {
|
|
362
464
|
if ('eq' in test)
|
|
363
|
-
return equal(held, test.eq
|
|
465
|
+
return equal(held, test.eq);
|
|
364
466
|
if ('in' in test)
|
|
365
|
-
return anyOf(test.in.map((value) => equal(held, value
|
|
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
|
|
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
|
|
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
|
|
498
|
+
return anyOf(read.values.map((value) => (value === undefined ? undefined : compared(test, value))));
|
|
397
499
|
}
|
|
398
|
-
function evaluated(test, read
|
|
500
|
+
function evaluated(test, read) {
|
|
399
501
|
if ('all' in test)
|
|
400
|
-
return allOf(test.all.map((part) => evaluated(part, read
|
|
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
|
|
504
|
+
return anyOf(test.any.map((part) => evaluated(part, read)));
|
|
403
505
|
if ('not' in test) {
|
|
404
|
-
const truth = evaluated(test.not, read
|
|
506
|
+
const truth = evaluated(test.not, read);
|
|
405
507
|
return truth === undefined ? undefined : !truth;
|
|
406
508
|
}
|
|
407
|
-
return leaf(test, read(test.path)
|
|
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
|
|
410
|
-
return evaluated(test, (path) => readDocument(document, path)
|
|
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
|
|
534
|
+
function matched(condition, test, document) {
|
|
422
535
|
if (!inScope(condition.scope, document))
|
|
423
536
|
return false;
|
|
424
|
-
return test === undefined || holds(test, document
|
|
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
|
|
453
|
-
return holds({ path: field, in: values }, document
|
|
570
|
+
function among(values, document, field) {
|
|
571
|
+
return holds({ path: field, in: values }, document) === true;
|
|
454
572
|
}
|
|
455
|
-
function fieldChanged(condition, event
|
|
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
|
|
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
|
|
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
|
|
478
|
-
if (condition.
|
|
479
|
-
|
|
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
|
|
485
|
-
!matched(condition, condition.match, event.before
|
|
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
|
|
608
|
+
return matched(condition, condition.match, side) && fieldChanged(condition, event);
|
|
489
609
|
}
|
|
490
|
-
export function itemFires(condition, item
|
|
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
|
}
|