@agentshouse/mdmodel 0.1.0-ce8ce7ff57e88 → 0.1.0-cf26f43c2e4d9
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 +85 -75
- package/README.md +1 -1
- package/dist/blocks.d.ts.map +1 -1
- package/dist/blocks.js +29 -7
- package/dist/condition.d.ts +23 -9
- package/dist/condition.d.ts.map +1 -1
- package/dist/condition.js +202 -86
- package/dist/definition.d.ts +2 -1
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +96 -20
- package/dist/divide.js +9 -9
- package/dist/document.d.ts +4 -4
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +38 -38
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/links.d.ts +1 -0
- package/dist/links.d.ts.map +1 -1
- package/dist/links.js +85 -39
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +4 -1
- package/dist/pattern.d.ts +10 -0
- package/dist/pattern.d.ts.map +1 -0
- package/dist/pattern.js +355 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +3 -5
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +55 -4
- package/dist/types.d.ts +9 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/validate.d.ts +25 -4
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +163 -65
- package/dist/yaml.d.ts.map +1 -1
- package/dist/yaml.js +27 -1
- package/fixtures/README.md +9 -4
- package/fixtures/cases/conditional-section/context.json +1 -0
- package/fixtures/cases/conditional-section/expected.json +6 -0
- package/fixtures/cases/conditional-section/library/questions/hosting.md +9 -0
- package/fixtures/cases/conditional-section/library/questions/payments.md +12 -0
- package/fixtures/cases/conditional-section/schema.yaml +14 -0
- package/fixtures/division.json +26 -26
- package/package.json +7 -2
package/dist/condition.js
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
import { ARRAY_INDEX, escapePointer, fieldFacts, itemFacts, memberFacts, pointerSegments, } from './definition.js';
|
|
1
|
+
import { ARRAY_INDEX, escapePointer, fieldFacts, itemFacts, memberFacts, pointerFacts, pointerSegments, } from './definition.js';
|
|
2
2
|
import { roomPath, target } from './paths.js';
|
|
3
|
-
import {
|
|
4
|
-
export const
|
|
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
|
+
];
|
|
15
|
+
export const TEXT_FIELD = '/text';
|
|
16
|
+
export const WRITE_DOORS = ['browser', 'agent', 'client', 'function'];
|
|
5
17
|
const PROSE = { kind: 'prose' };
|
|
6
18
|
const NULL = { kind: 'null' };
|
|
7
19
|
const UNREADABLE = { kind: 'unreadable' };
|
|
8
20
|
const UNREAD = { present: undefined, values: [undefined], items: [undefined] };
|
|
9
21
|
const NO_ITEM = { present: false, values: [], items: [] };
|
|
10
22
|
const DATE = /^\d{4}-\d{2}-\d{2}$/u;
|
|
23
|
+
const HEADER = /^\/headers\/[!#$%&'*+.^_`|~0-9a-z-]+$/u;
|
|
11
24
|
const DATE_TIME = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(?:[Zz]|([+-])(\d{2}):(\d{2}))$/u;
|
|
12
25
|
export function factKind(facts) {
|
|
13
26
|
if (facts.reference !== undefined)
|
|
@@ -71,8 +84,7 @@ function factOf(value, declared, place) {
|
|
|
71
84
|
return UNREADABLE;
|
|
72
85
|
if (kind !== 'reference')
|
|
73
86
|
return { kind, value };
|
|
74
|
-
const reached = target(place.path, value) ??
|
|
75
|
-
(declared.crossRoom === true ? roomPath(value) : null);
|
|
87
|
+
const reached = target(place.path, value) ?? roomPath(value);
|
|
76
88
|
const resolved = reached === null ? undefined : place.resolve(reached);
|
|
77
89
|
if (resolved === undefined)
|
|
78
90
|
return UNREADABLE;
|
|
@@ -182,10 +194,9 @@ function documentRead({ reached, several, missing }, held) {
|
|
|
182
194
|
};
|
|
183
195
|
}
|
|
184
196
|
function readDocument(facts, path) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return facts.type === null ? undefined : single({ kind: 'string', value: facts.type });
|
|
197
|
+
const own = tested(DOCUMENT_TESTS, path);
|
|
198
|
+
if (own !== undefined)
|
|
199
|
+
return own.read(facts, path);
|
|
189
200
|
if (path.startsWith('/sections/'))
|
|
190
201
|
return facts.sections.includes(path.slice('/sections/'.length))
|
|
191
202
|
? single({ kind: 'prose' })
|
|
@@ -196,22 +207,147 @@ function readDocument(facts, path) {
|
|
|
196
207
|
return documentRead(walked(rootOf(facts, '/members'), path.slice('/members'.length)), memberHeld);
|
|
197
208
|
return undefined;
|
|
198
209
|
}
|
|
199
|
-
function readActor(actor, path) {
|
|
200
|
-
const value = path === '/user'
|
|
201
|
-
? actor.user
|
|
202
|
-
: path === '/site'
|
|
203
|
-
? actor.site
|
|
204
|
-
: path === '/door'
|
|
205
|
-
? actor.door
|
|
206
|
-
: undefined;
|
|
207
|
-
return value === undefined ? undefined : single({ kind: 'actor', value });
|
|
208
|
-
}
|
|
209
210
|
export function datePointers(fields) {
|
|
210
211
|
return Object.entries(fields)
|
|
211
212
|
.filter(([, facts]) => facts.type === 'string' && facts.format === 'date')
|
|
212
|
-
.map(([name]) => `/fields/${name}`)
|
|
213
|
+
.map(([name]) => `/fields/${escapePointer(name)}`)
|
|
213
214
|
.sort();
|
|
214
215
|
}
|
|
216
|
+
export function valuedChange(definition, field) {
|
|
217
|
+
if (!field.startsWith('/fields/'))
|
|
218
|
+
return false;
|
|
219
|
+
const reached = pointerFacts(definition, field.slice('/fields'.length));
|
|
220
|
+
return (reached !== undefined &&
|
|
221
|
+
!reached.through &&
|
|
222
|
+
reached.facts.type !== 'array' &&
|
|
223
|
+
!reached.facts.prose &&
|
|
224
|
+
factKind(reached.facts) !== null);
|
|
225
|
+
}
|
|
226
|
+
export function changeFields(definition) {
|
|
227
|
+
return [
|
|
228
|
+
...Object.keys(definition.fields).map((name) => `/fields/${escapePointer(name)}`),
|
|
229
|
+
...Object.keys(definition.sections).map((heading) => `/sections/${heading}`),
|
|
230
|
+
];
|
|
231
|
+
}
|
|
232
|
+
export function memberPointers(definition, memberType) {
|
|
233
|
+
return Object.entries(definition.fields)
|
|
234
|
+
.filter(([, facts]) => (facts.type === 'array' ? facts.items : facts)?.reference?.includes(memberType) === true)
|
|
235
|
+
.map(([name]) => `/members/${escapePointer(name)}`);
|
|
236
|
+
}
|
|
237
|
+
function kindOperators(kind) {
|
|
238
|
+
switch (kind) {
|
|
239
|
+
case 'string':
|
|
240
|
+
return ['eq', 'in', 'prefix', 'exists'];
|
|
241
|
+
case 'boolean':
|
|
242
|
+
return ['eq', 'exists'];
|
|
243
|
+
case 'number':
|
|
244
|
+
case 'date':
|
|
245
|
+
case 'time':
|
|
246
|
+
return ['eq', 'in', 'gt', 'gte', 'lt', 'lte', 'exists'];
|
|
247
|
+
default:
|
|
248
|
+
return ['eq', 'in', 'exists'];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function pointerOperators({ facts, through }) {
|
|
252
|
+
const scalar = facts.type === 'array' ? facts.items : facts;
|
|
253
|
+
const kind = scalar === undefined || scalar.prose ? null : factKind(scalar);
|
|
254
|
+
if (kind === null)
|
|
255
|
+
return ['exists'];
|
|
256
|
+
if (facts.type === 'array')
|
|
257
|
+
return ['contains', 'exists'];
|
|
258
|
+
const own = kindOperators(kind);
|
|
259
|
+
return through ? [...own.filter((operator) => operator !== 'exists'), 'contains', 'exists'] : own;
|
|
260
|
+
}
|
|
261
|
+
function typeOperators(definition, path, memberType) {
|
|
262
|
+
if (path.startsWith('/sections/'))
|
|
263
|
+
return Object.hasOwn(definition.sections, path.slice('/sections/'.length)) ? ['exists'] : [];
|
|
264
|
+
const pointer = path.startsWith('/fields/')
|
|
265
|
+
? path.slice('/fields'.length)
|
|
266
|
+
: memberType !== null && memberPointers(definition, memberType).includes(path)
|
|
267
|
+
? path.slice('/members'.length)
|
|
268
|
+
: undefined;
|
|
269
|
+
const reached = pointer === undefined ? undefined : pointerFacts(definition, pointer);
|
|
270
|
+
return reached === undefined ? [] : pointerOperators(reached);
|
|
271
|
+
}
|
|
272
|
+
function envelope(path, kind, value) {
|
|
273
|
+
return {
|
|
274
|
+
path,
|
|
275
|
+
names: (named) => named === path,
|
|
276
|
+
kind,
|
|
277
|
+
operators: kindOperators(kind),
|
|
278
|
+
read: (facts) => {
|
|
279
|
+
const held = value(facts);
|
|
280
|
+
return held === null || held === undefined ? undefined : single({ kind, value: held });
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function tested(tests, path) {
|
|
285
|
+
return tests.find(({ names }) => names(path));
|
|
286
|
+
}
|
|
287
|
+
function reader(tests, facts) {
|
|
288
|
+
return (path) => tested(tests, path)?.read(facts, path);
|
|
289
|
+
}
|
|
290
|
+
const DOCUMENT_TESTS = [
|
|
291
|
+
{
|
|
292
|
+
path: '/path',
|
|
293
|
+
names: (named) => named === '/path',
|
|
294
|
+
kind: 'string',
|
|
295
|
+
operators: ['eq', 'in', 'prefix'],
|
|
296
|
+
read: (facts) => single({ kind: 'string', value: facts.path }),
|
|
297
|
+
},
|
|
298
|
+
envelope('/type', 'enum', (facts) => facts.type),
|
|
299
|
+
];
|
|
300
|
+
const ACTOR_TESTS = [
|
|
301
|
+
envelope('/user', 'enum', (actor) => actor.user),
|
|
302
|
+
envelope('/site', 'enum', (actor) => actor.site),
|
|
303
|
+
envelope('/app', 'enum', (actor) => actor.app),
|
|
304
|
+
envelope('/door', 'enum', (actor) => actor.door),
|
|
305
|
+
];
|
|
306
|
+
const ITEM_TESTS = [
|
|
307
|
+
envelope('/delivery', 'enum', (item) => item.delivery),
|
|
308
|
+
envelope('/source', 'enum', (item) => item.source),
|
|
309
|
+
envelope('/container', 'string', (item) => item.container),
|
|
310
|
+
envelope('/author', 'string', (item) => item.author),
|
|
311
|
+
{
|
|
312
|
+
path: '/headers/<lowercase name>',
|
|
313
|
+
names: (named) => HEADER.test(named),
|
|
314
|
+
kind: 'string',
|
|
315
|
+
operators: kindOperators('string'),
|
|
316
|
+
read: (item, path) => {
|
|
317
|
+
const name = path.slice('/headers/'.length);
|
|
318
|
+
return Object.hasOwn(item.headers, name)
|
|
319
|
+
? single({ kind: 'string', value: item.headers[name] })
|
|
320
|
+
: undefined;
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
path: '/json/<JSON Pointer>',
|
|
325
|
+
names: (named) => named.startsWith('/json/'),
|
|
326
|
+
kind: null,
|
|
327
|
+
operators: CONDITION_OPERATORS,
|
|
328
|
+
read: (item, path) => item.json === null ? UNREAD : jsonRead(pointed(item.json.value, path.slice('/json'.length))),
|
|
329
|
+
},
|
|
330
|
+
];
|
|
331
|
+
export const DOCUMENT_PATHS = DOCUMENT_TESTS.map(({ path }) => path);
|
|
332
|
+
export const ACTOR_PATHS = ACTOR_TESTS.map(({ path }) => path);
|
|
333
|
+
export const ITEM_PATHS = ITEM_TESTS.map(({ path }) => path);
|
|
334
|
+
export function testOperators(definitions, path, memberType) {
|
|
335
|
+
const own = tested(DOCUMENT_TESTS, path);
|
|
336
|
+
if (own !== undefined)
|
|
337
|
+
return own.operators;
|
|
338
|
+
return [
|
|
339
|
+
...new Set(definitions.flatMap((definition) => typeOperators(definition, path, memberType))),
|
|
340
|
+
];
|
|
341
|
+
}
|
|
342
|
+
export function actorOperators(path) {
|
|
343
|
+
return tested(ACTOR_TESTS, path)?.operators ?? [];
|
|
344
|
+
}
|
|
345
|
+
export function itemOperators(path) {
|
|
346
|
+
return tested(ITEM_TESTS, path)?.operators ?? [];
|
|
347
|
+
}
|
|
348
|
+
export function itemKind(path) {
|
|
349
|
+
return tested(ITEM_TESTS, path)?.kind ?? null;
|
|
350
|
+
}
|
|
215
351
|
export function dated(value) {
|
|
216
352
|
return (typeof value === 'string' && DATE.test(value) && instant(`${value}T00:00:00Z`) !== undefined);
|
|
217
353
|
}
|
|
@@ -240,11 +376,8 @@ export function instant(value) {
|
|
|
240
376
|
return (BigInt(at.getTime()) - BigInt(offset) * 60000n) * 1000000n + BigInt(fraction);
|
|
241
377
|
}
|
|
242
378
|
export function pointed(value, pointer) {
|
|
243
|
-
if (pointer === '')
|
|
244
|
-
return value;
|
|
245
379
|
let reached = value;
|
|
246
|
-
for (const
|
|
247
|
-
const token = part.replaceAll('~1', '/').replaceAll('~0', '~');
|
|
380
|
+
for (const token of pointerSegments(pointer)) {
|
|
248
381
|
if (Array.isArray(reached)) {
|
|
249
382
|
if (!ARRAY_INDEX.test(token))
|
|
250
383
|
return undefined;
|
|
@@ -283,44 +416,15 @@ function jsonRead(value) {
|
|
|
283
416
|
return single({ kind: 'prose' });
|
|
284
417
|
return { present: true, values: [], items: value.filter(scalar).map(jsonHeld), loose: true };
|
|
285
418
|
}
|
|
286
|
-
function
|
|
287
|
-
if (path.startsWith('/json/')) {
|
|
288
|
-
if (item.json === null)
|
|
289
|
-
return UNREAD;
|
|
290
|
-
return jsonRead(pointed(item.json.value, path.slice('/json'.length)));
|
|
291
|
-
}
|
|
292
|
-
if (path.startsWith('/headers/')) {
|
|
293
|
-
const name = path.slice('/headers/'.length);
|
|
294
|
-
return Object.hasOwn(item.headers, name)
|
|
295
|
-
? single({ kind: 'string', value: item.headers[name] })
|
|
296
|
-
: undefined;
|
|
297
|
-
}
|
|
298
|
-
if (path === '/has_attachment')
|
|
299
|
-
return single({ kind: 'boolean', value: item.has_attachment });
|
|
300
|
-
const value = path === '/delivery'
|
|
301
|
-
? item.delivery
|
|
302
|
-
: path === '/source'
|
|
303
|
-
? item.source
|
|
304
|
-
: path === '/container'
|
|
305
|
-
? item.container
|
|
306
|
-
: path === '/author'
|
|
307
|
-
? item.author
|
|
308
|
-
: null;
|
|
309
|
-
return value === null ? undefined : single({ kind: 'string', value });
|
|
310
|
-
}
|
|
311
|
-
function wanted(value, owner) {
|
|
312
|
-
return isRecord(value) && value.owner === true ? owner : value;
|
|
313
|
-
}
|
|
314
|
-
function equal(held, value, owner) {
|
|
419
|
+
function equal(held, value) {
|
|
315
420
|
if (!('value' in held))
|
|
316
421
|
return undefined;
|
|
317
|
-
|
|
318
|
-
if (typeof expected !== typeof held.value)
|
|
422
|
+
if (typeof value !== typeof held.value)
|
|
319
423
|
return undefined;
|
|
320
424
|
if (held.kind !== 'time')
|
|
321
|
-
return
|
|
425
|
+
return value === held.value;
|
|
322
426
|
const left = instant(held.value);
|
|
323
|
-
const right = instant(
|
|
427
|
+
const right = instant(value);
|
|
324
428
|
return left === undefined || right === undefined ? undefined : left === right;
|
|
325
429
|
}
|
|
326
430
|
function sign(left, right) {
|
|
@@ -357,11 +461,11 @@ function allOf(truths) {
|
|
|
357
461
|
return false;
|
|
358
462
|
return truths.some((truth) => truth === undefined) ? undefined : true;
|
|
359
463
|
}
|
|
360
|
-
function compared(test, held
|
|
464
|
+
function compared(test, held) {
|
|
361
465
|
if ('eq' in test)
|
|
362
|
-
return equal(held, test.eq
|
|
466
|
+
return equal(held, test.eq);
|
|
363
467
|
if ('in' in test)
|
|
364
|
-
return anyOf(test.in.map((value) => equal(held, value
|
|
468
|
+
return anyOf(test.in.map((value) => equal(held, value)));
|
|
365
469
|
if ('prefix' in test) {
|
|
366
470
|
if (!('value' in held) || typeof held.value !== 'string')
|
|
367
471
|
return undefined;
|
|
@@ -377,7 +481,7 @@ function compared(test, held, owner) {
|
|
|
377
481
|
return ordered(held, test.lt, (sign) => sign < 0);
|
|
378
482
|
return ordered(held, test.lte, (sign) => sign <= 0);
|
|
379
483
|
}
|
|
380
|
-
function leaf(test, read
|
|
484
|
+
function leaf(test, read) {
|
|
381
485
|
if ('exists' in test) {
|
|
382
486
|
const present = read === undefined ? false : read.present;
|
|
383
487
|
return present === undefined ? undefined : present === test.exists;
|
|
@@ -387,26 +491,37 @@ function leaf(test, read, owner) {
|
|
|
387
491
|
if ('contains' in test) {
|
|
388
492
|
if (read.items === null)
|
|
389
493
|
return undefined;
|
|
390
|
-
const truths = read.items.map((item) => item === undefined ? undefined : equal(item, test.contains
|
|
494
|
+
const truths = read.items.map((item) => item === undefined ? undefined : equal(item, test.contains));
|
|
391
495
|
return read.loose === true && !truths.includes(true) ? false : anyOf(truths);
|
|
392
496
|
}
|
|
393
497
|
if (read.values.length === 0)
|
|
394
498
|
return read === NO_ITEM ? false : undefined;
|
|
395
|
-
return anyOf(read.values.map((value) => (value === undefined ? undefined : compared(test, value
|
|
499
|
+
return anyOf(read.values.map((value) => (value === undefined ? undefined : compared(test, value))));
|
|
396
500
|
}
|
|
397
|
-
function evaluated(test, read
|
|
501
|
+
function evaluated(test, read) {
|
|
398
502
|
if ('all' in test)
|
|
399
|
-
return allOf(test.all.map((part) => evaluated(part, read
|
|
503
|
+
return allOf(test.all.map((part) => evaluated(part, read)));
|
|
400
504
|
if ('any' in test)
|
|
401
|
-
return anyOf(test.any.map((part) => evaluated(part, read
|
|
505
|
+
return anyOf(test.any.map((part) => evaluated(part, read)));
|
|
402
506
|
if ('not' in test) {
|
|
403
|
-
const truth = evaluated(test.not, read
|
|
507
|
+
const truth = evaluated(test.not, read);
|
|
404
508
|
return truth === undefined ? undefined : !truth;
|
|
405
509
|
}
|
|
406
|
-
return leaf(test, read(test.path)
|
|
510
|
+
return leaf(test, read(test.path));
|
|
407
511
|
}
|
|
408
|
-
export function
|
|
409
|
-
|
|
512
|
+
export function members(document, path) {
|
|
513
|
+
if (!path.startsWith('/members/'))
|
|
514
|
+
return [];
|
|
515
|
+
const read = readDocument(document, path);
|
|
516
|
+
const values = read === undefined ? [] : [...read.values, ...(read.items ?? [])];
|
|
517
|
+
return [
|
|
518
|
+
...new Set(values.flatMap((value) => value !== undefined && value.kind === 'member' && 'value' in value
|
|
519
|
+
? [String(value.value)]
|
|
520
|
+
: [])),
|
|
521
|
+
].sort();
|
|
522
|
+
}
|
|
523
|
+
export function holds(test, document) {
|
|
524
|
+
return evaluated(test, (path) => readDocument(document, path));
|
|
410
525
|
}
|
|
411
526
|
function inScope(scope, document) {
|
|
412
527
|
if (document === null)
|
|
@@ -417,10 +532,10 @@ function inScope(scope, document) {
|
|
|
417
532
|
return document.id === scope.document;
|
|
418
533
|
return scope.folder === '/' || document.path.startsWith(`${scope.folder}/`);
|
|
419
534
|
}
|
|
420
|
-
function matched(condition, test, document
|
|
535
|
+
function matched(condition, test, document) {
|
|
421
536
|
if (!inScope(condition.scope, document))
|
|
422
537
|
return false;
|
|
423
|
-
return test === undefined || holds(test, document
|
|
538
|
+
return test === undefined || holds(test, document) === true;
|
|
424
539
|
}
|
|
425
540
|
function reachedAt(document, field) {
|
|
426
541
|
if (document === null)
|
|
@@ -453,10 +568,10 @@ function valueOf(fact) {
|
|
|
453
568
|
function signature(reached) {
|
|
454
569
|
return JSON.stringify(reached.map(({ fact }) => valueOf(fact)));
|
|
455
570
|
}
|
|
456
|
-
function among(values, document, field
|
|
457
|
-
return holds({ path: field, in: values }, document
|
|
571
|
+
function among(values, document, field) {
|
|
572
|
+
return holds({ path: field, in: values }, document) === true;
|
|
458
573
|
}
|
|
459
|
-
function fieldChanged(condition, event
|
|
574
|
+
function fieldChanged(condition, event) {
|
|
460
575
|
const { field, from, to } = condition;
|
|
461
576
|
const before = reachedAt(event.before, field);
|
|
462
577
|
const after = reachedAt(event.after, field);
|
|
@@ -470,32 +585,33 @@ function fieldChanged(condition, event, owner) {
|
|
|
470
585
|
return false;
|
|
471
586
|
if (from === 'new'
|
|
472
587
|
? event.before !== null
|
|
473
|
-
: from !== undefined && (event.before === null || !among(from, event.before, field
|
|
588
|
+
: from !== undefined && (event.before === null || !among(from, event.before, field)))
|
|
474
589
|
return false;
|
|
475
590
|
if (to === 'deleted'
|
|
476
591
|
? event.after !== null
|
|
477
|
-
: to !== undefined && (event.after === null || !among(to, event.after, field
|
|
592
|
+
: to !== undefined && (event.after === null || !among(to, event.after, field)))
|
|
478
593
|
return false;
|
|
479
594
|
return true;
|
|
480
595
|
}
|
|
481
|
-
export function fires(condition, event
|
|
482
|
-
if (condition.
|
|
483
|
-
|
|
596
|
+
export function fires(condition, event) {
|
|
597
|
+
if (condition.moved_between_rooms !== undefined &&
|
|
598
|
+
condition.moved_between_rooms !== event.moved_between_rooms)
|
|
599
|
+
return false;
|
|
600
|
+
if (condition.by !== undefined && evaluated(condition.by, reader(ACTOR_TESTS, event.by)) !== true)
|
|
484
601
|
return false;
|
|
485
602
|
if (condition.mode === 'starts_matching') {
|
|
486
603
|
if (event.before === null && !condition.new_documents)
|
|
487
604
|
return false;
|
|
488
|
-
return (matched(condition, condition.match, event.after
|
|
489
|
-
!matched(condition, condition.match, event.before
|
|
605
|
+
return (matched(condition, condition.match, event.after) &&
|
|
606
|
+
!matched(condition, condition.match, event.before));
|
|
490
607
|
}
|
|
491
608
|
const side = event.after ?? event.before;
|
|
492
|
-
return matched(condition, condition.match, side
|
|
609
|
+
return matched(condition, condition.match, side) && fieldChanged(condition, event);
|
|
493
610
|
}
|
|
494
|
-
export function itemFires(condition, item
|
|
611
|
+
export function itemFires(condition, item) {
|
|
495
612
|
if (condition.source !== undefined && item.source !== condition.source)
|
|
496
613
|
return false;
|
|
497
614
|
if (condition.address !== undefined && item.address !== condition.address)
|
|
498
615
|
return false;
|
|
499
|
-
return (condition.match === undefined ||
|
|
500
|
-
evaluated(condition.match, (path) => readItem(item, path), owner) === true);
|
|
616
|
+
return (condition.match === undefined || evaluated(condition.match, reader(ITEM_TESTS, item)) === true);
|
|
501
617
|
}
|
package/dist/definition.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ export declare const JSON_TYPES: readonly JsonType[];
|
|
|
60
60
|
export declare const BUILT_IN_TYPE = "any";
|
|
61
61
|
export declare const ATTACHMENT = "attachment";
|
|
62
62
|
export declare const ARRAY_INDEX: RegExp;
|
|
63
|
+
export declare const JSON_POINTER: RegExp;
|
|
63
64
|
export declare function escapePointer(key: string): string;
|
|
64
65
|
export declare function pointerSegments(pointer: string): string[];
|
|
65
66
|
export declare function refTarget(reference: string, defs: Readonly<Record<string, unknown>>): {
|
|
@@ -77,5 +78,5 @@ export type PointerFacts = {
|
|
|
77
78
|
export declare function crossedFacts(facts: ValueFacts): ValueFacts[];
|
|
78
79
|
export declare function fieldFacts(definition: Definition, key: string): ValueFacts | undefined;
|
|
79
80
|
export declare function pointerFacts(definition: Definition, pointer: string): PointerFacts | undefined;
|
|
80
|
-
export declare function readSchema(text: string): VerifiedModel | Failure;
|
|
81
|
+
export declare function readSchema(text: string, provided?: VerifiedModel): VerifiedModel | Failure;
|
|
81
82
|
//# sourceMappingURL=definition.d.ts.map
|
package/dist/definition.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"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"}
|
package/dist/definition.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MEMBER_FIELD, RECEIVED_FIELD, SITE_FIELD, TYPE_FIELD } from './fields.js';
|
|
2
|
+
import { linearPattern } from './pattern.js';
|
|
2
3
|
import { equalValue, isRecord, jsValue, parseYamlMapping, YamlError } from './yaml.js';
|
|
3
4
|
export const JSON_TYPES = [
|
|
4
5
|
'string',
|
|
@@ -24,9 +25,13 @@ const ANNOTATIONS = new Set([
|
|
|
24
25
|
'writeOnly',
|
|
25
26
|
]);
|
|
26
27
|
const FIELD_RULES = ['change_roles', 'initial_roles', 'transitions'];
|
|
28
|
+
const PROVIDED_KEYWORDS = ['create_roles', 'delete_roles'];
|
|
29
|
+
const NO_TYPES = Object.freeze({ types: Object.freeze({}) });
|
|
27
30
|
const DEFS_REFERENCE = '#/$defs/';
|
|
31
|
+
const UNBOUNDED_FORMAT = 'url';
|
|
28
32
|
const UNRESOLVED = /[\u0000-\u001f\u007f%[\]\\^{|}]|\s$/u;
|
|
29
33
|
export const ARRAY_INDEX = /^(?:0|[1-9][0-9]*)$/u;
|
|
34
|
+
export const JSON_POINTER = /^(?:\/(?:[^~/]|~[01])*)*$/u;
|
|
30
35
|
const HOUSE_KEYS = {
|
|
31
36
|
[TYPE_FIELD]: { prose: false },
|
|
32
37
|
[SITE_FIELD]: { prose: false },
|
|
@@ -45,12 +50,12 @@ export function pointerSegments(pointer) {
|
|
|
45
50
|
return pointer.split('/').slice(1).map(unescapePointer);
|
|
46
51
|
}
|
|
47
52
|
export function refTarget(reference, defs) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (segments.some((segment) => escapePointer(unescapePointer(segment)) !== segment))
|
|
53
|
+
const pointer = reference.slice('#'.length);
|
|
54
|
+
if (!reference.startsWith(DEFS_REFERENCE) ||
|
|
55
|
+
UNRESOLVED.test(reference) ||
|
|
56
|
+
!JSON_POINTER.test(pointer))
|
|
53
57
|
return undefined;
|
|
58
|
+
const [, name = '', ...rest] = pointerSegments(pointer);
|
|
54
59
|
if (!Object.hasOwn(defs, name))
|
|
55
60
|
return undefined;
|
|
56
61
|
let node = defs[name];
|
|
@@ -81,15 +86,7 @@ export function refTarget(reference, defs) {
|
|
|
81
86
|
return { name, node };
|
|
82
87
|
}
|
|
83
88
|
function compiles(pattern) {
|
|
84
|
-
|
|
85
|
-
return false;
|
|
86
|
-
try {
|
|
87
|
-
new RegExp(pattern, 'u');
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
89
|
+
return typeof pattern === 'string' && linearPattern(pattern) !== null;
|
|
93
90
|
}
|
|
94
91
|
function finite(value) {
|
|
95
92
|
return typeof value === 'number' && Number.isFinite(value);
|
|
@@ -199,7 +196,7 @@ const KEYWORDS = {
|
|
|
199
196
|
uniqueItems: FLAG,
|
|
200
197
|
required: strings,
|
|
201
198
|
dependentRequired: (value) => isRecord(value) && Object.values(value).every(strings),
|
|
202
|
-
format:
|
|
199
|
+
format: (value) => typeof value === 'string' && value !== UNBOUNDED_FORMAT,
|
|
203
200
|
contentEncoding: TEXT,
|
|
204
201
|
contentMediaType: TEXT,
|
|
205
202
|
title: TEXT,
|
|
@@ -447,7 +444,7 @@ export function itemFacts(facts, index) {
|
|
|
447
444
|
export function memberFacts(facts, key) {
|
|
448
445
|
if (facts.properties !== undefined && Object.hasOwn(facts.properties, key))
|
|
449
446
|
return facts.properties[key];
|
|
450
|
-
const pattern = facts.patterns?.find((one) =>
|
|
447
|
+
const pattern = facts.patterns?.find((one) => linearPattern(one.pattern).test(key));
|
|
451
448
|
return pattern === undefined ? facts.additional : pattern.facts;
|
|
452
449
|
}
|
|
453
450
|
export function crossedFacts(facts) {
|
|
@@ -550,6 +547,56 @@ function readSections(value, at, context) {
|
|
|
550
547
|
}
|
|
551
548
|
return { sections };
|
|
552
549
|
}
|
|
550
|
+
function branchSectionsFailure(sections, declared, where) {
|
|
551
|
+
if (!isRecord(sections))
|
|
552
|
+
return refuse('sections', where);
|
|
553
|
+
for (const [name, spec] of Object.entries(sections)) {
|
|
554
|
+
const place = `${where}/${escapePointer(name)}`;
|
|
555
|
+
const own = isRecord(declared) && Object.hasOwn(declared, name) ? declared[name] : undefined;
|
|
556
|
+
if (!isRecord(spec) || !isRecord(own))
|
|
557
|
+
return refuse('sections', place);
|
|
558
|
+
const { required, ...kind } = spec;
|
|
559
|
+
const { required: _required, ...ownKind } = own;
|
|
560
|
+
if (required !== undefined && typeof required !== 'boolean')
|
|
561
|
+
return refuse('sections', `${place}/required`);
|
|
562
|
+
if (!equalValue(kind, ownKind))
|
|
563
|
+
return refuse('sections', place);
|
|
564
|
+
}
|
|
565
|
+
return undefined;
|
|
566
|
+
}
|
|
567
|
+
function withoutBranchSections(schema, declared, at) {
|
|
568
|
+
const kept = { ...schema };
|
|
569
|
+
if (Array.isArray(schema.allOf)) {
|
|
570
|
+
const entries = [];
|
|
571
|
+
for (const [index, entry] of schema.allOf.entries()) {
|
|
572
|
+
const read = isRecord(entry)
|
|
573
|
+
? withoutBranchSections(entry, declared, `${at}/allOf/${index}`)
|
|
574
|
+
: { schema: entry };
|
|
575
|
+
if ('failure' in read)
|
|
576
|
+
return read;
|
|
577
|
+
entries.push(read.schema);
|
|
578
|
+
}
|
|
579
|
+
kept.allOf = entries;
|
|
580
|
+
}
|
|
581
|
+
if (schema.if === undefined)
|
|
582
|
+
return { schema: kept };
|
|
583
|
+
for (const branch of ['then', 'else']) {
|
|
584
|
+
const held = schema[branch];
|
|
585
|
+
if (!isRecord(held))
|
|
586
|
+
continue;
|
|
587
|
+
const { sections, ...rest } = held;
|
|
588
|
+
const failure = sections === undefined
|
|
589
|
+
? undefined
|
|
590
|
+
: branchSectionsFailure(sections, declared, `${at}/${branch}/sections`);
|
|
591
|
+
if (failure !== undefined)
|
|
592
|
+
return { failure };
|
|
593
|
+
const read = withoutBranchSections(rest, declared, `${at}/${branch}`);
|
|
594
|
+
if ('failure' in read)
|
|
595
|
+
return read;
|
|
596
|
+
kept[branch] = read.schema;
|
|
597
|
+
}
|
|
598
|
+
return { schema: kept };
|
|
599
|
+
}
|
|
553
600
|
function deepFreeze(value) {
|
|
554
601
|
if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
555
602
|
Object.freeze(value);
|
|
@@ -657,6 +704,26 @@ function unruled(schema) {
|
|
|
657
704
|
}
|
|
658
705
|
return { schema: written.size === 0 ? schema : { ...schema, properties }, written };
|
|
659
706
|
}
|
|
707
|
+
function providedType(name, value, provided) {
|
|
708
|
+
const at = `/${escapePointer(name)}`;
|
|
709
|
+
if (provided.nameable?.includes(name) !== true)
|
|
710
|
+
return refuse('provided-type', at);
|
|
711
|
+
if (!isRecord(value))
|
|
712
|
+
return refuse('schema', at);
|
|
713
|
+
const declared = Object.keys(value).find((key) => !PROVIDED_KEYWORDS.includes(key));
|
|
714
|
+
if (declared !== undefined)
|
|
715
|
+
return refuse('provided-type', `${at}/${escapePointer(declared)}`);
|
|
716
|
+
const { create_roles: createRoles, delete_roles: deleteRoles } = value;
|
|
717
|
+
if (createRoles !== undefined && !roleNames(createRoles))
|
|
718
|
+
return refuse('create_roles', `${at}/create_roles`);
|
|
719
|
+
if (deleteRoles !== undefined && !roleNames(deleteRoles))
|
|
720
|
+
return refuse('delete_roles', `${at}/delete_roles`);
|
|
721
|
+
return {
|
|
722
|
+
...provided.types[name],
|
|
723
|
+
...(createRoles === undefined ? {} : { createRoles }),
|
|
724
|
+
...(deleteRoles === undefined ? {} : { deleteRoles }),
|
|
725
|
+
};
|
|
726
|
+
}
|
|
660
727
|
function readType(name, value, context) {
|
|
661
728
|
const at = `/${escapePointer(name)}`;
|
|
662
729
|
if (!isRecord(value))
|
|
@@ -673,7 +740,10 @@ function readType(name, value, context) {
|
|
|
673
740
|
: readSections(declared, `${at}/sections`, context);
|
|
674
741
|
if ('failure' in read)
|
|
675
742
|
return read.failure;
|
|
676
|
-
const
|
|
743
|
+
const unbranched = withoutBranchSections(ruled, declared, at);
|
|
744
|
+
if ('failure' in unbranched)
|
|
745
|
+
return unbranched.failure;
|
|
746
|
+
const { schema, written } = unruled(unbranched.schema);
|
|
677
747
|
const failure = schemaFailure(schema, at, context);
|
|
678
748
|
if (failure !== undefined)
|
|
679
749
|
return failure;
|
|
@@ -712,7 +782,7 @@ function readType(name, value, context) {
|
|
|
712
782
|
function lineAt(text, offset) {
|
|
713
783
|
return text.slice(0, offset).split(/\r\n|\r|\n/).length;
|
|
714
784
|
}
|
|
715
|
-
export function readSchema(text) {
|
|
785
|
+
export function readSchema(text, provided = NO_TYPES) {
|
|
716
786
|
let root;
|
|
717
787
|
try {
|
|
718
788
|
root = jsValue(parseYamlMapping(text, 0, text.length));
|
|
@@ -730,7 +800,7 @@ export function readSchema(text) {
|
|
|
730
800
|
if (name === '' || name.startsWith('$') || name === BUILT_IN_TYPE || name === ATTACHMENT)
|
|
731
801
|
return refuse('schema-type-name', `/${escapePointer(name)}`);
|
|
732
802
|
}
|
|
733
|
-
const context = { defs, types: new Set(names) };
|
|
803
|
+
const context = { defs, types: new Set([...names, ...Object.keys(provided.types)]) };
|
|
734
804
|
for (const [name, def] of Object.entries(defs)) {
|
|
735
805
|
const failure = schemaFailure(def, `/$defs/${escapePointer(name)}`, context);
|
|
736
806
|
if (failure !== undefined)
|
|
@@ -739,7 +809,9 @@ export function readSchema(text) {
|
|
|
739
809
|
const types = Object.create(null);
|
|
740
810
|
let marked = false;
|
|
741
811
|
for (const name of names) {
|
|
742
|
-
const definition =
|
|
812
|
+
const definition = Object.hasOwn(provided.types, name)
|
|
813
|
+
? providedType(name, root[name], provided)
|
|
814
|
+
: readType(name, root[name], context);
|
|
743
815
|
if ('rule' in definition)
|
|
744
816
|
return definition;
|
|
745
817
|
if (definition.memberDocument) {
|
|
@@ -749,5 +821,9 @@ export function readSchema(text) {
|
|
|
749
821
|
}
|
|
750
822
|
types[name] = deepFreeze(definition);
|
|
751
823
|
}
|
|
824
|
+
for (const [name, definition] of Object.entries(provided.types)) {
|
|
825
|
+
if (!Object.hasOwn(types, name))
|
|
826
|
+
types[name] = definition;
|
|
827
|
+
}
|
|
752
828
|
return Object.freeze({ types: Object.freeze(types) });
|
|
753
829
|
}
|