@agentshouse/mdmodel 0.1.0-cc9fa0498a7f7 → 0.1.0-cd90851746292
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 +231 -225
- package/README.md +16 -19
- package/dist/blocks.d.ts.map +1 -1
- package/dist/blocks.js +35 -20
- package/dist/condition.d.ts +41 -11
- package/dist/condition.d.ts.map +1 -1
- package/dist/condition.js +223 -87
- package/dist/definition.d.ts +17 -1
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +319 -43
- 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 +326 -176
- package/dist/index.d.ts +13 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -6
- package/dist/links.d.ts +3 -0
- package/dist/links.d.ts.map +1 -1
- package/dist/links.js +108 -51
- package/dist/paths.d.ts +10 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +118 -12
- 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 +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.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +55 -4
- package/dist/types.d.ts +50 -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 +317 -114
- package/dist/yaml.d.ts.map +1 -1
- package/dist/yaml.js +66 -21
- package/fixtures/README.md +10 -5
- 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/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 +10 -3
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',
|
|
@@ -12,9 +13,25 @@ export const JSON_TYPES = [
|
|
|
12
13
|
export const BUILT_IN_TYPE = 'any';
|
|
13
14
|
export const ATTACHMENT = 'attachment';
|
|
14
15
|
const SCALAR_TYPES = new Set(['string', 'number', 'integer', 'boolean']);
|
|
16
|
+
const COMPOSITES = ['array', 'object'];
|
|
17
|
+
const ANNOTATIONS = new Set([
|
|
18
|
+
'$comment',
|
|
19
|
+
'title',
|
|
20
|
+
'description',
|
|
21
|
+
'default',
|
|
22
|
+
'examples',
|
|
23
|
+
'deprecated',
|
|
24
|
+
'readOnly',
|
|
25
|
+
'writeOnly',
|
|
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({}) });
|
|
15
30
|
const DEFS_REFERENCE = '#/$defs/';
|
|
31
|
+
const UNBOUNDED_FORMAT = 'url';
|
|
16
32
|
const UNRESOLVED = /[\u0000-\u001f\u007f%[\]\\^{|}]|\s$/u;
|
|
17
33
|
export const ARRAY_INDEX = /^(?:0|[1-9][0-9]*)$/u;
|
|
34
|
+
export const JSON_POINTER = /^(?:\/(?:[^~/]|~[01])*)*$/u;
|
|
18
35
|
const HOUSE_KEYS = {
|
|
19
36
|
[TYPE_FIELD]: { prose: false },
|
|
20
37
|
[SITE_FIELD]: { prose: false },
|
|
@@ -33,12 +50,12 @@ export function pointerSegments(pointer) {
|
|
|
33
50
|
return pointer.split('/').slice(1).map(unescapePointer);
|
|
34
51
|
}
|
|
35
52
|
export function refTarget(reference, defs) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
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))
|
|
41
57
|
return undefined;
|
|
58
|
+
const [, name = '', ...rest] = pointerSegments(pointer);
|
|
42
59
|
if (!Object.hasOwn(defs, name))
|
|
43
60
|
return undefined;
|
|
44
61
|
let node = defs[name];
|
|
@@ -69,15 +86,7 @@ export function refTarget(reference, defs) {
|
|
|
69
86
|
return { name, node };
|
|
70
87
|
}
|
|
71
88
|
function compiles(pattern) {
|
|
72
|
-
|
|
73
|
-
return false;
|
|
74
|
-
try {
|
|
75
|
-
new RegExp(pattern, 'u');
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
89
|
+
return typeof pattern === 'string' && linearPattern(pattern) !== null;
|
|
81
90
|
}
|
|
82
91
|
function finite(value) {
|
|
83
92
|
return typeof value === 'number' && Number.isFinite(value);
|
|
@@ -187,7 +196,7 @@ const KEYWORDS = {
|
|
|
187
196
|
uniqueItems: FLAG,
|
|
188
197
|
required: strings,
|
|
189
198
|
dependentRequired: (value) => isRecord(value) && Object.values(value).every(strings),
|
|
190
|
-
format:
|
|
199
|
+
format: (value) => typeof value === 'string' && value !== UNBOUNDED_FORMAT,
|
|
191
200
|
contentEncoding: TEXT,
|
|
192
201
|
contentMediaType: TEXT,
|
|
193
202
|
title: TEXT,
|
|
@@ -204,8 +213,12 @@ const KEYWORDS = {
|
|
|
204
213
|
return (Array.isArray(named) &&
|
|
205
214
|
named.length > 0 &&
|
|
206
215
|
strings(named) &&
|
|
207
|
-
named.every((name) => name === BUILT_IN_TYPE ||
|
|
216
|
+
named.every((name) => name === BUILT_IN_TYPE ||
|
|
217
|
+
name === ATTACHMENT ||
|
|
218
|
+
context.types.has(name) ||
|
|
219
|
+
node.cross_room === true));
|
|
208
220
|
},
|
|
221
|
+
cross_room: (value, _at, node) => typeof value === 'boolean' && node.reference !== undefined,
|
|
209
222
|
};
|
|
210
223
|
function sharedType(values) {
|
|
211
224
|
if (values.length === 0)
|
|
@@ -270,24 +283,45 @@ function united(left, right) {
|
|
|
270
283
|
return undefined;
|
|
271
284
|
return [...left, ...right.filter((value) => !left.some((held) => equalValue(held, value)))];
|
|
272
285
|
}
|
|
286
|
+
function both(left, right) {
|
|
287
|
+
return left !== undefined && right !== undefined ? joined(left, right) : undefined;
|
|
288
|
+
}
|
|
273
289
|
function joined(left, right) {
|
|
274
290
|
const type = left.type === right.type ? left.type : undefined;
|
|
275
291
|
const format = left.format === right.format ? left.format : undefined;
|
|
276
292
|
const values = united(left.values, right.values);
|
|
277
293
|
const reference = united(left.reference, right.reference);
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
294
|
+
const crossRoom = left.crossRoom === true || right.crossRoom === true;
|
|
295
|
+
const items = both(left.items, right.items);
|
|
296
|
+
const prefix = left.prefix === undefined && right.prefix === undefined
|
|
297
|
+
? undefined
|
|
298
|
+
: Array.from({ length: Math.max(left.prefix?.length ?? 0, right.prefix?.length ?? 0) }, (_, index) => both(itemFacts(left, index), itemFacts(right, index)) ?? { prose: false });
|
|
299
|
+
const properties = Object.create(null);
|
|
300
|
+
for (const [name, facts] of Object.entries(left.properties ?? {})) {
|
|
301
|
+
const shared = both(facts, right.properties?.[name]);
|
|
302
|
+
if (shared !== undefined)
|
|
303
|
+
properties[name] = shared;
|
|
304
|
+
}
|
|
305
|
+
const patterns = (left.patterns ?? []).flatMap(({ pattern, facts }) => {
|
|
306
|
+
const shared = both(facts, right.patterns?.find((one) => one.pattern === pattern)?.facts);
|
|
307
|
+
return shared === undefined ? [] : [{ pattern, facts: shared }];
|
|
308
|
+
});
|
|
309
|
+
const additional = both(left.additional, right.additional);
|
|
281
310
|
return {
|
|
282
311
|
...(type === undefined ? {} : { type }),
|
|
283
312
|
...(format === undefined ? {} : { format }),
|
|
284
313
|
...(values === undefined ? {} : { values }),
|
|
285
314
|
...(reference === undefined ? {} : { reference }),
|
|
315
|
+
...(reference !== undefined && crossRoom ? { crossRoom: true } : {}),
|
|
286
316
|
prose: left.prose && right.prose,
|
|
317
|
+
...(prefix === undefined ? {} : { prefix }),
|
|
287
318
|
...(items === undefined ? {} : { items }),
|
|
319
|
+
...(Object.keys(properties).length === 0 ? {} : { properties }),
|
|
320
|
+
...(patterns.length === 0 ? {} : { patterns }),
|
|
321
|
+
...(additional === undefined ? {} : { additional }),
|
|
288
322
|
};
|
|
289
323
|
}
|
|
290
|
-
function propertiesOf(held, defs, ancestry) {
|
|
324
|
+
function propertiesOf(held, variants, defs, ancestry) {
|
|
291
325
|
const declared = new Map();
|
|
292
326
|
for (const node of held) {
|
|
293
327
|
if (!isRecord(node.properties))
|
|
@@ -298,46 +332,88 @@ function propertiesOf(held, defs, ancestry) {
|
|
|
298
332
|
const properties = Object.create(null);
|
|
299
333
|
for (const [name, schemas] of declared)
|
|
300
334
|
properties[name] = factsOf(schemas, defs, ancestry);
|
|
301
|
-
const
|
|
302
|
-
for (const branch of
|
|
303
|
-
for (const [name, facts] of Object.entries(
|
|
335
|
+
const conditional = Object.create(null);
|
|
336
|
+
for (const branch of variants.values()) {
|
|
337
|
+
for (const [name, facts] of Object.entries(branch.properties ?? {})) {
|
|
304
338
|
if (Object.hasOwn(properties, name))
|
|
305
339
|
continue;
|
|
306
|
-
|
|
340
|
+
conditional[name] = Object.hasOwn(conditional, name)
|
|
341
|
+
? joined(conditional[name], facts)
|
|
342
|
+
: facts;
|
|
307
343
|
}
|
|
308
344
|
}
|
|
309
|
-
for (const [name, facts] of Object.entries(
|
|
345
|
+
for (const [name, facts] of Object.entries(conditional))
|
|
310
346
|
properties[name] = { ...facts, conditional: true };
|
|
311
347
|
return Object.keys(properties).length === 0 ? undefined : properties;
|
|
312
348
|
}
|
|
349
|
+
function nullOnly(facts) {
|
|
350
|
+
return facts.type === 'null' || (facts.values?.every((value) => value === null) ?? false);
|
|
351
|
+
}
|
|
352
|
+
function alternativesOf(held, variants) {
|
|
353
|
+
return held.flatMap((node) => [node.anyOf, node.oneOf].flatMap((branches) => {
|
|
354
|
+
if (!Array.isArray(branches))
|
|
355
|
+
return [];
|
|
356
|
+
const kept = branches
|
|
357
|
+
.flatMap((branch) => {
|
|
358
|
+
const facts = isRecord(branch) ? variants.get(branch) : undefined;
|
|
359
|
+
return facts === undefined ? [] : [facts];
|
|
360
|
+
})
|
|
361
|
+
.filter((facts) => !nullOnly(facts));
|
|
362
|
+
return kept.length === 0 ? [] : [kept];
|
|
363
|
+
}));
|
|
364
|
+
}
|
|
365
|
+
function inheritedOf(held) {
|
|
366
|
+
return held.flatMap((node) => {
|
|
367
|
+
const kept = Object.fromEntries(['type', 'items', 'prefixItems'].flatMap((key) => node[key] === undefined ? [] : [[key, node[key]]]));
|
|
368
|
+
return Object.keys(kept).length === 0 ? [] : [kept];
|
|
369
|
+
});
|
|
370
|
+
}
|
|
313
371
|
function factsOf(nodes, defs, ancestry) {
|
|
314
372
|
const { held, ancestry: reached } = conjoined(nodes, defs, ancestry);
|
|
315
|
-
const
|
|
373
|
+
const inherited = inheritedOf(held);
|
|
374
|
+
const variants = new Map(held
|
|
375
|
+
.flatMap(variantsOf)
|
|
376
|
+
.map((branch) => [branch, factsOf([branch, ...inherited], defs, reached)]));
|
|
377
|
+
const unions = alternativesOf(held, variants);
|
|
378
|
+
const alternatives = unions.map((kept) => kept.reduce(joined));
|
|
379
|
+
const listed = [
|
|
380
|
+
...held.flatMap((node) => Array.isArray(node.enum) ? [node.enum] : node.const !== undefined ? [[node.const]] : []),
|
|
381
|
+
...alternatives.flatMap((facts) => (facts.values === undefined ? [] : [facts.values])),
|
|
382
|
+
];
|
|
316
383
|
const values = listed.length === 0
|
|
317
384
|
? undefined
|
|
318
385
|
: listed.reduce((kept, list) => kept.filter((value) => list.some((other) => equalValue(other, value))));
|
|
319
386
|
const type = firstOf(held, (node) => singleType(node.type)) ??
|
|
320
|
-
(values === undefined ? undefined : sharedType(values))
|
|
387
|
+
(values === undefined ? undefined : sharedType(values)) ??
|
|
388
|
+
alternatives.find((facts) => facts.type !== undefined)?.type;
|
|
321
389
|
const reference = firstOf(held, (node) => typeof node.reference === 'string'
|
|
322
390
|
? [node.reference]
|
|
323
391
|
: Array.isArray(node.reference)
|
|
324
392
|
? node.reference
|
|
325
|
-
: undefined);
|
|
326
|
-
const
|
|
393
|
+
: undefined) ?? alternatives.find((facts) => facts.reference !== undefined)?.reference;
|
|
394
|
+
const crossRoom = firstOf(held, (node) => node.reference === undefined ? undefined : node.cross_room === true) ?? alternatives.find((facts) => facts.reference !== undefined)?.crossRoom === true;
|
|
395
|
+
const format = firstOf(held, (node) => (typeof node.format === 'string' ? node.format : undefined)) ??
|
|
396
|
+
alternatives.find((facts) => facts.format !== undefined)?.format;
|
|
327
397
|
const prose = type === 'string' &&
|
|
328
398
|
values === undefined &&
|
|
329
399
|
format === undefined &&
|
|
330
400
|
reference === undefined &&
|
|
331
|
-
held.every((node) => node.pattern === undefined)
|
|
401
|
+
held.every((node) => node.pattern === undefined) &&
|
|
402
|
+
unions.every((kept) => kept.every((facts) => facts.type !== 'string' || facts.prose));
|
|
332
403
|
const listedItems = held.flatMap((node) => (node.items === undefined ? [] : [node.items]));
|
|
333
|
-
const items = type
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
404
|
+
const items = type !== 'array'
|
|
405
|
+
? undefined
|
|
406
|
+
: (alternatives.find((facts) => facts.items !== undefined)?.items ??
|
|
407
|
+
(listedItems.length > 0 ? factsOf(listedItems, defs, reached) : undefined));
|
|
408
|
+
const tuples = held.flatMap((node) => Array.isArray(node.prefixItems) ? [node.prefixItems] : []);
|
|
409
|
+
const prefix = type !== 'array'
|
|
410
|
+
? undefined
|
|
411
|
+
: (alternatives.find((facts) => facts.prefix !== undefined)?.prefix ??
|
|
412
|
+
(tuples.length === 0
|
|
413
|
+
? undefined
|
|
414
|
+
: Array.from({ length: Math.max(...tuples.map((tuple) => tuple.length)) }, (_, index) => factsOf(tuples.flatMap((tuple) => (index < tuple.length ? [tuple[index]] : [])), defs, reached))));
|
|
339
415
|
const mapped = type === 'object' || type === undefined;
|
|
340
|
-
const properties = mapped ? propertiesOf(held, defs, reached) : undefined;
|
|
416
|
+
const properties = mapped ? propertiesOf(held, variants, defs, reached) : undefined;
|
|
341
417
|
const patterns = mapped
|
|
342
418
|
? held.flatMap((node) => Object.entries(isRecord(node.patternProperties) ? node.patternProperties : {}).map(([pattern, schema]) => ({ pattern, facts: factsOf([schema], defs, reached) })))
|
|
343
419
|
: [];
|
|
@@ -350,6 +426,7 @@ function factsOf(nodes, defs, ancestry) {
|
|
|
350
426
|
...(format === undefined ? {} : { format }),
|
|
351
427
|
...(values === undefined ? {} : { values }),
|
|
352
428
|
...(reference === undefined ? {} : { reference }),
|
|
429
|
+
...(reference !== undefined && crossRoom ? { crossRoom: true } : {}),
|
|
353
430
|
prose,
|
|
354
431
|
...(prefix === undefined ? {} : { prefix }),
|
|
355
432
|
...(items === undefined ? {} : { items }),
|
|
@@ -367,7 +444,7 @@ export function itemFacts(facts, index) {
|
|
|
367
444
|
export function memberFacts(facts, key) {
|
|
368
445
|
if (facts.properties !== undefined && Object.hasOwn(facts.properties, key))
|
|
369
446
|
return facts.properties[key];
|
|
370
|
-
const pattern = facts.patterns?.find((one) =>
|
|
447
|
+
const pattern = facts.patterns?.find((one) => linearPattern(one.pattern).test(key));
|
|
371
448
|
return pattern === undefined ? facts.additional : pattern.facts;
|
|
372
449
|
}
|
|
373
450
|
export function crossedFacts(facts) {
|
|
@@ -470,6 +547,56 @@ function readSections(value, at, context) {
|
|
|
470
547
|
}
|
|
471
548
|
return { sections };
|
|
472
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
|
+
}
|
|
473
600
|
function deepFreeze(value) {
|
|
474
601
|
if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
475
602
|
Object.freeze(value);
|
|
@@ -478,21 +605,157 @@ function deepFreeze(value) {
|
|
|
478
605
|
}
|
|
479
606
|
return value;
|
|
480
607
|
}
|
|
608
|
+
function ruleValue(value) {
|
|
609
|
+
return value === null || typeof value === 'string' || typeof value === 'boolean' || finite(value);
|
|
610
|
+
}
|
|
611
|
+
function roleNames(value) {
|
|
612
|
+
return strings(value) && value.every((name) => name !== '');
|
|
613
|
+
}
|
|
614
|
+
function compositesOf(value) {
|
|
615
|
+
return Array.isArray(value) ? ['array'] : isRecord(value) ? ['object'] : [];
|
|
616
|
+
}
|
|
617
|
+
function typed(type) {
|
|
618
|
+
const types = typeof type === 'string' ? [type] : type;
|
|
619
|
+
return Array.isArray(types) ? COMPOSITES.filter((kind) => types.includes(kind)) : undefined;
|
|
620
|
+
}
|
|
621
|
+
function admittedWhole(node) {
|
|
622
|
+
if (node === true)
|
|
623
|
+
return COMPOSITES;
|
|
624
|
+
if (!isRecord(node) || Object.keys(node).some((key) => key !== 'type' && !ANNOTATIONS.has(key)))
|
|
625
|
+
return [];
|
|
626
|
+
return typed(node.type) ?? COMPOSITES;
|
|
627
|
+
}
|
|
628
|
+
function composites(node, defs, seen) {
|
|
629
|
+
if (node === false)
|
|
630
|
+
return [];
|
|
631
|
+
if (!isRecord(node))
|
|
632
|
+
return COMPOSITES;
|
|
633
|
+
const each = (nodes) => Array.isArray(nodes) ? nodes.map((one) => composites(one, defs, seen)) : [];
|
|
634
|
+
const target = typeof node.$ref === 'string' ? refTarget(node.$ref, defs)?.node : undefined;
|
|
635
|
+
const conditioned = () => {
|
|
636
|
+
const met = composites(node.then ?? true, defs, seen);
|
|
637
|
+
return COMPOSITES.filter((kind) => (composites(node.if, defs, seen).includes(kind) && met.includes(kind)) ||
|
|
638
|
+
composites(node.else ?? true, defs, seen).includes(kind));
|
|
639
|
+
};
|
|
640
|
+
const bounds = [
|
|
641
|
+
typed(node.type),
|
|
642
|
+
Array.isArray(node.enum) ? node.enum.flatMap(compositesOf) : undefined,
|
|
643
|
+
Object.hasOwn(node, 'const') ? compositesOf(node.const) : undefined,
|
|
644
|
+
target === undefined || seen.has(target)
|
|
645
|
+
? undefined
|
|
646
|
+
: composites(target, defs, new Set([...seen, target])),
|
|
647
|
+
...each(node.allOf),
|
|
648
|
+
...[node.anyOf, node.oneOf].filter(Array.isArray).map((branches) => each(branches).flat()),
|
|
649
|
+
Object.hasOwn(node, 'if') ? conditioned() : undefined,
|
|
650
|
+
Object.hasOwn(node, 'not')
|
|
651
|
+
? COMPOSITES.filter((kind) => !admittedWhole(node.not).includes(kind))
|
|
652
|
+
: undefined,
|
|
653
|
+
];
|
|
654
|
+
return COMPOSITES.filter((kind) => bounds.every((bound) => bound?.includes(kind) ?? true));
|
|
655
|
+
}
|
|
656
|
+
function transitionOf(value) {
|
|
657
|
+
if (!isRecord(value) || !Object.hasOwn(value, 'from') || !Object.hasOwn(value, 'to'))
|
|
658
|
+
return undefined;
|
|
659
|
+
const { from, to, roles, ...rest } = value;
|
|
660
|
+
if (Object.keys(rest).length > 0 || !ruleValue(from) || !ruleValue(to))
|
|
661
|
+
return undefined;
|
|
662
|
+
if (roles === undefined)
|
|
663
|
+
return { from, to };
|
|
664
|
+
return roleNames(roles) ? { from, to, roles } : undefined;
|
|
665
|
+
}
|
|
666
|
+
function fieldRules(written, field, at, defs) {
|
|
667
|
+
const { change_roles: changeRoles, initial_roles: initialRoles, transitions } = written;
|
|
668
|
+
if (changeRoles !== undefined && !roleNames(changeRoles))
|
|
669
|
+
return refuse('change_roles', `${at}/change_roles`);
|
|
670
|
+
if (initialRoles !== undefined && !roleNames(initialRoles))
|
|
671
|
+
return refuse('initial_roles', `${at}/initial_roles`);
|
|
672
|
+
if (transitions === undefined)
|
|
673
|
+
return {
|
|
674
|
+
...(changeRoles === undefined ? {} : { changeRoles }),
|
|
675
|
+
...(initialRoles === undefined ? {} : { initialRoles }),
|
|
676
|
+
};
|
|
677
|
+
if (!Array.isArray(transitions) || composites(field, defs, new Set()).length > 0)
|
|
678
|
+
return refuse('transitions', `${at}/transitions`);
|
|
679
|
+
const listed = [];
|
|
680
|
+
for (const [index, held] of transitions.entries()) {
|
|
681
|
+
const transition = transitionOf(held);
|
|
682
|
+
if (transition === undefined)
|
|
683
|
+
return refuse('transitions', `${at}/transitions/${index}`);
|
|
684
|
+
listed.push(transition);
|
|
685
|
+
}
|
|
686
|
+
return {
|
|
687
|
+
...(changeRoles === undefined ? {} : { changeRoles }),
|
|
688
|
+
...(initialRoles === undefined ? {} : { initialRoles }),
|
|
689
|
+
transitions: listed,
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function unruled(schema) {
|
|
693
|
+
const written = new Map();
|
|
694
|
+
if (!isRecord(schema.properties))
|
|
695
|
+
return { schema, written };
|
|
696
|
+
const properties = Object.create(null);
|
|
697
|
+
for (const [field, node] of Object.entries(schema.properties)) {
|
|
698
|
+
if (!isRecord(node) || !FIELD_RULES.some((keyword) => Object.hasOwn(node, keyword))) {
|
|
699
|
+
properties[field] = node;
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
written.set(field, node);
|
|
703
|
+
properties[field] = Object.fromEntries(Object.entries(node).filter(([keyword]) => !FIELD_RULES.includes(keyword)));
|
|
704
|
+
}
|
|
705
|
+
return { schema: written.size === 0 ? schema : { ...schema, properties }, written };
|
|
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
|
+
}
|
|
481
727
|
function readType(name, value, context) {
|
|
482
728
|
const at = `/${escapePointer(name)}`;
|
|
483
729
|
if (!isRecord(value))
|
|
484
730
|
return refuse('schema', at);
|
|
485
|
-
const { sections: declared, member_document: mark, ...
|
|
731
|
+
const { sections: declared, member_document: mark, create_roles: createRoles, delete_roles: deleteRoles, ...ruled } = value;
|
|
486
732
|
if (mark !== undefined && typeof mark !== 'boolean')
|
|
487
733
|
return refuse('member_document', `${at}/member_document`);
|
|
734
|
+
if (createRoles !== undefined && !roleNames(createRoles))
|
|
735
|
+
return refuse('create_roles', `${at}/create_roles`);
|
|
736
|
+
if (deleteRoles !== undefined && !roleNames(deleteRoles))
|
|
737
|
+
return refuse('delete_roles', `${at}/delete_roles`);
|
|
488
738
|
const read = declared === undefined
|
|
489
739
|
? { sections: Object.create(null) }
|
|
490
740
|
: readSections(declared, `${at}/sections`, context);
|
|
491
741
|
if ('failure' in read)
|
|
492
742
|
return read.failure;
|
|
743
|
+
const unbranched = withoutBranchSections(ruled, declared, at);
|
|
744
|
+
if ('failure' in unbranched)
|
|
745
|
+
return unbranched.failure;
|
|
746
|
+
const { schema, written } = unruled(unbranched.schema);
|
|
493
747
|
const failure = schemaFailure(schema, at, context);
|
|
494
748
|
if (failure !== undefined)
|
|
495
749
|
return failure;
|
|
750
|
+
const rules = Object.create(null);
|
|
751
|
+
for (const [field, keywords] of written) {
|
|
752
|
+
const properties = schema.properties;
|
|
753
|
+
const where = `${at}/properties/${escapePointer(field)}`;
|
|
754
|
+
const ruling = fieldRules(keywords, properties[field], where, context.defs);
|
|
755
|
+
if ('rule' in ruling)
|
|
756
|
+
return ruling;
|
|
757
|
+
rules[field] = ruling;
|
|
758
|
+
}
|
|
496
759
|
const memberDocument = mark === true;
|
|
497
760
|
const root = valueFacts(schema, context.defs);
|
|
498
761
|
const fields = Object.assign(Object.create(null), root.properties);
|
|
@@ -500,19 +763,26 @@ function readType(name, value, context) {
|
|
|
500
763
|
fields[MEMBER_FIELD] = { type: 'string', prose: false };
|
|
501
764
|
const defs = Object.create(null);
|
|
502
765
|
reachedDefs(value, context.defs, defs);
|
|
766
|
+
const { create_roles: _create, delete_roles: _delete, ...shaped } = value;
|
|
503
767
|
return {
|
|
504
768
|
name,
|
|
505
769
|
memberDocument,
|
|
506
770
|
frontmatter: { ...root, properties: { ...HOUSE_KEYS, ...fields } },
|
|
507
771
|
fields,
|
|
508
772
|
sections: read.sections,
|
|
509
|
-
|
|
773
|
+
rules,
|
|
774
|
+
...(createRoles === undefined ? {} : { createRoles }),
|
|
775
|
+
...(deleteRoles === undefined ? {} : { deleteRoles }),
|
|
776
|
+
shape: {
|
|
777
|
+
schema: written.size === 0 ? shaped : { ...shaped, properties: schema.properties },
|
|
778
|
+
defs,
|
|
779
|
+
},
|
|
510
780
|
};
|
|
511
781
|
}
|
|
512
782
|
function lineAt(text, offset) {
|
|
513
783
|
return text.slice(0, offset).split(/\r\n|\r|\n/).length;
|
|
514
784
|
}
|
|
515
|
-
export function readSchema(text) {
|
|
785
|
+
export function readSchema(text, provided = NO_TYPES) {
|
|
516
786
|
let root;
|
|
517
787
|
try {
|
|
518
788
|
root = jsValue(parseYamlMapping(text, 0, text.length));
|
|
@@ -530,7 +800,7 @@ export function readSchema(text) {
|
|
|
530
800
|
if (name === '' || name.startsWith('$') || name === BUILT_IN_TYPE || name === ATTACHMENT)
|
|
531
801
|
return refuse('schema-type-name', `/${escapePointer(name)}`);
|
|
532
802
|
}
|
|
533
|
-
const context = { defs, types: new Set(names) };
|
|
803
|
+
const context = { defs, types: new Set([...names, ...Object.keys(provided.types)]) };
|
|
534
804
|
for (const [name, def] of Object.entries(defs)) {
|
|
535
805
|
const failure = schemaFailure(def, `/$defs/${escapePointer(name)}`, context);
|
|
536
806
|
if (failure !== undefined)
|
|
@@ -539,7 +809,9 @@ export function readSchema(text) {
|
|
|
539
809
|
const types = Object.create(null);
|
|
540
810
|
let marked = false;
|
|
541
811
|
for (const name of names) {
|
|
542
|
-
const definition =
|
|
812
|
+
const definition = Object.hasOwn(provided.types, name)
|
|
813
|
+
? providedType(name, root[name], provided)
|
|
814
|
+
: readType(name, root[name], context);
|
|
543
815
|
if ('rule' in definition)
|
|
544
816
|
return definition;
|
|
545
817
|
if (definition.memberDocument) {
|
|
@@ -549,5 +821,9 @@ export function readSchema(text) {
|
|
|
549
821
|
}
|
|
550
822
|
types[name] = deepFreeze(definition);
|
|
551
823
|
}
|
|
824
|
+
for (const [name, definition] of Object.entries(provided.types)) {
|
|
825
|
+
if (!Object.hasOwn(types, name))
|
|
826
|
+
types[name] = definition;
|
|
827
|
+
}
|
|
552
828
|
return Object.freeze({ types: Object.freeze(types) });
|
|
553
829
|
}
|
package/dist/divide.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"divide.d.ts","sourceRoot":"","sources":["../src/divide.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"divide.d.ts","sourceRoot":"","sources":["../src/divide.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAwXpF,wBAAgB,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,QAAQ,CAc3F"}
|
package/dist/divide.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { blockRanges, headingLines } from './blocks.js';
|
|
2
|
-
import { projectionInput, rangeText } from './project.js';
|
|
2
|
+
import { firstEditFrom, projectionInput, rangeText, } from './project.js';
|
|
3
3
|
import { refusal } from './refuse.js';
|
|
4
|
-
const
|
|
4
|
+
const SMALLEST_BOUND = 2;
|
|
5
5
|
function node(draft) {
|
|
6
6
|
return {
|
|
7
7
|
start: draft.start,
|
|
@@ -86,8 +86,8 @@ function isTrailingSurrogate(text, index) {
|
|
|
86
86
|
function characterLength(text, index) {
|
|
87
87
|
return isTrailingSurrogate(text, index + 1) ? 2 : 1;
|
|
88
88
|
}
|
|
89
|
-
function boundOf(cutting, from, to,
|
|
90
|
-
const limit = from +
|
|
89
|
+
function boundOf(cutting, from, to, bound) {
|
|
90
|
+
const limit = from + bound;
|
|
91
91
|
if (limit >= to)
|
|
92
92
|
return to;
|
|
93
93
|
for (let index = limit; index > from + 1; index -= 1) {
|
|
@@ -131,16 +131,26 @@ function textOf(state, extent) {
|
|
|
131
131
|
return rangeText(state.content, extent, state.edits);
|
|
132
132
|
}
|
|
133
133
|
function sourceCutting(state, extent) {
|
|
134
|
-
|
|
134
|
+
const source = state.content.slice(extent.start, extent.end);
|
|
135
135
|
const masks = [];
|
|
136
|
-
for (
|
|
137
|
-
|
|
136
|
+
for (let index = firstEditFrom(state.edits, extent.start); index < state.edits.length; index += 1) {
|
|
137
|
+
const edit = state.edits[index];
|
|
138
|
+
if (edit.start > extent.end)
|
|
139
|
+
break;
|
|
140
|
+
if (edit.end > extent.end)
|
|
138
141
|
continue;
|
|
139
|
-
|
|
140
|
-
const to = edit.end - extent.start;
|
|
141
|
-
text = `${text.slice(0, from)}${'x'.repeat(to - from)}${text.slice(to)}`;
|
|
142
|
-
masks.push({ start: from, end: to });
|
|
142
|
+
masks.push({ start: edit.start - extent.start, end: edit.end - extent.start });
|
|
143
143
|
}
|
|
144
|
+
let text = '';
|
|
145
|
+
let cursor = 0;
|
|
146
|
+
for (const mask of masks) {
|
|
147
|
+
if (mask.end <= cursor)
|
|
148
|
+
continue;
|
|
149
|
+
const from = Math.max(mask.start, cursor);
|
|
150
|
+
text += `${source.slice(cursor, from)}${'x'.repeat(mask.end - from)}`;
|
|
151
|
+
cursor = mask.end;
|
|
152
|
+
}
|
|
153
|
+
text += source.slice(cursor);
|
|
144
154
|
return {
|
|
145
155
|
text,
|
|
146
156
|
masks,
|
|
@@ -158,12 +168,12 @@ function valueCutting(value) {
|
|
|
158
168
|
};
|
|
159
169
|
}
|
|
160
170
|
function prefixOf(state, body) {
|
|
161
|
-
if (body.emitted === 0 || body.heading.length >= state.
|
|
171
|
+
if (body.emitted === 0 || body.heading.length >= state.bound)
|
|
162
172
|
return '';
|
|
163
173
|
return body.heading;
|
|
164
174
|
}
|
|
165
175
|
function available(state, body) {
|
|
166
|
-
return state.
|
|
176
|
+
return state.bound - prefixOf(state, body).length;
|
|
167
177
|
}
|
|
168
178
|
function emit(state, body, piece, bare = false) {
|
|
169
179
|
if (piece.text.trim() === '')
|
|
@@ -206,7 +216,7 @@ function divideBound(state, body, cutting, range) {
|
|
|
206
216
|
let start = range.start;
|
|
207
217
|
while (start < range.end) {
|
|
208
218
|
const bare = available(state, body) < characterLength(cutting.text, start);
|
|
209
|
-
const room = bare ? state.
|
|
219
|
+
const room = bare ? state.bound : available(state, body);
|
|
210
220
|
const stop = boundOf(cutting, start, range.end, room);
|
|
211
221
|
const piece = cutting.piece(start, stop);
|
|
212
222
|
if (cutting.masks.length === 0 || piece.text.length <= room) {
|
|
@@ -293,8 +303,8 @@ function divideInput(state, input) {
|
|
|
293
303
|
]);
|
|
294
304
|
}
|
|
295
305
|
export function divide(document, file, context) {
|
|
296
|
-
if (!Number.isInteger(context.
|
|
297
|
-
return { ok: false, refusal: refusal(file, 'division-
|
|
306
|
+
if (!Number.isInteger(context.bound) || context.bound < SMALLEST_BOUND) {
|
|
307
|
+
return { ok: false, refusal: refusal(file, 'division-bound') };
|
|
298
308
|
}
|
|
299
309
|
const result = projectionInput(document, file, context);
|
|
300
310
|
if (!result.ok)
|
|
@@ -302,7 +312,7 @@ export function divide(document, file, context) {
|
|
|
302
312
|
const state = {
|
|
303
313
|
content: document.content,
|
|
304
314
|
edits: result.input.edits,
|
|
305
|
-
|
|
315
|
+
bound: context.bound,
|
|
306
316
|
spans: [],
|
|
307
317
|
};
|
|
308
318
|
divideInput(state, result.input);
|
package/dist/document.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { type Definition } from './definition.js';
|
|
2
|
-
import
|
|
2
|
+
import { type LinkInventory } from './links.js';
|
|
3
|
+
import type { ApplyResult, BodyResult, FrontmatterResult, Change, Document, Link, ParseResult } from './types.js';
|
|
3
4
|
import { type YamlMap } from './yaml.js';
|
|
5
|
+
export declare function inventoryOf(document: Document): LinkInventory;
|
|
6
|
+
export declare function parseFrontmatter(content: string, file?: string): FrontmatterResult;
|
|
4
7
|
export declare function parse(content: string, file?: string): ParseResult;
|
|
5
|
-
export declare function relativize(document: Document, file: string, handle: string, definition?: Definition): ApplyResult;
|
|
8
|
+
export declare function relativize(document: Document, file: string, handle: string, definition?: Definition, kept?: ReadonlySet<string>): ApplyResult;
|
|
6
9
|
export declare function relativizeBody(body: string, file: string, handle: string): BodyResult;
|
|
7
10
|
export declare function relinkBody(body: string, file: string, moves: ReadonlyMap<string, string>): BodyResult;
|
|
8
11
|
export declare function links(document: Document, file: string): readonly Link[];
|
|
9
12
|
export declare function bodyLinks(body: string, file: string): readonly Link[];
|
|
10
|
-
export declare function apply(document: Document,
|
|
13
|
+
export declare function apply(document: Document, changes: readonly Change[]): ApplyResult;
|
|
11
14
|
export declare function serialize(document: Document): string;
|
|
12
15
|
export declare function frontmatter(document: Document): YamlMap | null;
|
|
13
16
|
//# sourceMappingURL=document.d.ts.map
|
package/dist/document.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAcpB,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,WAAW,EAEZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAcL,KAAK,OAAO,EAEb,MAAM,WAAW,CAAC;AAgBnB,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,aAAa,CAM7D;AAgED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,iBAAiB,CAW9E;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,WAAW,CAgB7D;AAmED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,EACvB,IAAI,GAAE,WAAW,CAAC,MAAM,CAAa,GACpC,WAAW,CAuBb;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAUrF;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,UAAU,CAkBZ;AAeD,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,CAEvE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,CAErE;AA4LD,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CA4CjF;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEpD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,IAAI,CAE9D"}
|