@agentshouse/mdmodel 0.1.0-c3d58cb8652e6 → 0.1.0-c4fe1bc82bc55

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 CHANGED
@@ -38,6 +38,9 @@ if (parsed.ok) {
38
38
  }
39
39
  ```
40
40
 
41
+ `MARKDOWN_SYNTAX_PROFILE` is the Markdown every reader here applies, GitHub Flavored Markdown
42
+ 0.29, and `VERSION` is the MD model version.
43
+
41
44
  `verify(schema)` reads one schema text, the MD Types of one Room or App: one
42
45
  JSON Schema document (draft 2020-12) in the YAML subset. Every top-level key but
43
46
  `$defs` names an MD Type holding the JSON Schema of its frontmatter; `$defs`
@@ -72,6 +75,10 @@ variant's own keys `conditional`; a path without one `type`, `null` aside, has
72
75
  none. A malformed schema is refused whole, naming its `rule`, the keyword or the
73
76
  model's own, and the JSON Pointer `location` it concerns, such as
74
77
  `/plan/properties/status/enum`, or `line <n>` outside the YAML subset.
78
+ `pointerFacts(definition, pointer)` reads the facts a frontmatter pointer reaches,
79
+ `itemFacts` and `memberFacts` take one step and `crossedFacts` reads a list's item
80
+ facts; `pointerSegments` and `escapePointer` split and write a pointer, `ARRAY_INDEX`
81
+ matches an index segment, and `ATTACHMENT` is the `reference` that admits any path.
75
82
 
76
83
  `validate(library, context?, model?)` takes the resulting text Library and one
77
84
  `ValidationContext` of `binaryTargets: readonly string[]`, none when omitted.
@@ -103,10 +110,14 @@ and no body link is a referrer.
103
110
  Validation returns acceptance or one refusal naming the file, the field or
104
111
  section, and the violated rule. `parse`, `apply`, and `serialize` operate on a single text
105
112
  Document; they do not validate collection membership or consume binary bytes.
106
- `apply` sets one typed field, including a list field as a whole, replaces
113
+ `apply` sets one typed field, including a list or an object as a whole, replaces
107
114
  one existing section body or the preamble against that value's prior content,
108
115
  or rewrites one Markdown link destination. A section need not be declared by
109
116
  the Document's MD Type to be replaced. A field change does not reformat the rest of the file.
117
+ A field holds a `FrontmatterValue`: null, a string, a boolean, a finite number, a list
118
+ without holes or a plain object of them, holding no cycle. `frontmatterValue(value)` is that test, and
119
+ `apply` refuses any other value as `frontmatter-fence`; `equalValue(left, right)` compares
120
+ two by value, whatever their key order, as `apply` compares a field with its prior.
110
121
 
111
122
  `Document.preamble` is a readonly string containing the exact source after
112
123
  frontmatter and before the first section heading recognized by the existing
@@ -296,3 +307,53 @@ author quoted. A Span divided out of one free-text field value addresses that
296
307
  whole value, because a YAML scalar's own positions are the only ones its source
297
308
  has, and a Span carrying part of one internal link's label addresses that whole
298
309
  link, because a cut never falls inside link syntax.
310
+
311
+ ## Conditions
312
+
313
+ `facts(document, { id, path }, model, resolve)` reads one Document as the `DocumentFacts` a
314
+ condition tests: its `id`, its `path` with a leading `/`, its `type` or `null`, its `sections`, and
315
+ a `Fact` for each frontmatter field it writes that its MD Type declares. `factKind(facts)` names
316
+ the kind a declared value compares as: `reference`, `enum`, `number`, `boolean`, `date`, `time`
317
+ (a `date-time`) or `string`, else `null`. A prose value, or one of no kind, is `prose`, a list or
318
+ an object holds the facts of its members, and a value written `null` is `null`. A value that does
319
+ not fit its kind, such as a string in a number field, a value outside its `enum` or a reference
320
+ `resolve` maps to no `{ id, member? }`, is `unreadable`; a readable reference compares as that `id`.
321
+
322
+ `holds(test, facts, owner)` is `true`, `false` or `undefined`, unknown; a Trigger fires on `true`
323
+ alone. A test's `path` is `/path`, `/type`, `/sections/<heading>`, `/fields/<pointer>`, or
324
+ `/members/<pointer>`, the member of the Document a reference field reaches. A pointer segment that
325
+ is not an index reads every item of a list, an item lacking it unknown, and a test over several
326
+ values holds as `any` does. The value `{ owner: true }` stands for `owner`, a User id.
327
+
328
+ | The path reaches | `exists` | `contains` | any other test |
329
+ | --------------------------------------- | ----------- | -------------- | -------------- |
330
+ | a value | present | `undefined` | compared |
331
+ | `null`, prose or a section | present | `undefined` | `undefined` |
332
+ | a list | present | `any` of items | `undefined` |
333
+ | no item, through an empty list | absent | `false` | `false` |
334
+ | nothing: no such field, section or type | absent | `undefined` | `undefined` |
335
+ | only unreadable values | `undefined` | `undefined` | `undefined` |
336
+
337
+ `exists: true` holds where present and fails where absent, `exists: false` the reverse. `all` is
338
+ `false` if a part is, else `undefined` if a part is; `any` is `true` if a part is, else `undefined`
339
+ if a part is; `not` keeps `undefined`, so absence is tested with `exists`, never with `not`. `eq`
340
+ and `in` are `undefined` against a value of another JSON type and compare a `time` as an instant;
341
+ `prefix` reads only a string, never a reference or a member; `gt`, `gte`, `lt` and `lte` order
342
+ numbers, dates and times alone.
343
+
344
+ `fires(condition, event, owner)` reads one change, `{ before, after, changed, by }`: the facts of
345
+ each side, `null` on the side a creation or a deletion lacks, the `changed` paths whose prose
346
+ changed, and the actor whose `/user`, `/site` and `/door`, one of `WRITE_DOORS`, a `by` test reads.
347
+ `starts_matching` fires when the Document is in `scope` and holds `match` after the change and did
348
+ not before; a creation fires only with `new_documents: true`, and a deletion never fires.
349
+ `field_changes` fires when the side the Document has, after or for a deletion before, is in `scope`
350
+ and holds `match`, and `field` changed: its facts differ, or with neither `from` nor `to` `changed`
351
+ names it. A field absent on both sides never fires; `from: 'new'` admits only a creation and
352
+ `to: 'deleted'` only a deletion, and listed values need that side to hold `field` `in` them.
353
+
354
+ `itemFires(condition, item, owner)` compares `source` and `address` where given and holds `match`
355
+ over `/delivery`, `/source`, `/provider`, `/container`, `/author`, `/has_attachment`,
356
+ `/headers/<name>` and `/json/<pointer>`, unknown for an item with no JSON. `prosePaths(facts)` lists
357
+ the prose and section paths whose text builds `changed`; `pointed(value, pointer)` reads a JSON
358
+ Pointer, `undefined` where nothing is; `dated(value)` checks a `YYYY-MM-DD` date, and
359
+ `instant(value)` reads an RFC 3339 time with its offset as epoch nanoseconds, a `bigint`.
@@ -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;AAmCF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,EAAE,CAiBrF;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAe/E"}
1
+ {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../src/blocks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAqCF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,EAAE,CA+BrF;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAe/E"}
package/dist/blocks.js CHANGED
@@ -23,24 +23,38 @@ function scan(content, from, to, visit) {
23
23
  i = next;
24
24
  }
25
25
  }
26
+ const HASH = 0x23;
26
27
  export function headingLines(content, from, to) {
27
28
  const found = [];
28
- scan(content, from, to, (line) => {
29
- if (line.fenced)
30
- return;
31
- const match = HEADING.exec(line.text);
32
- const hashes = match?.[1];
33
- const name = match?.[2];
34
- if (hashes === undefined || name === undefined)
35
- return;
36
- found.push({
37
- level: hashes.length,
38
- name: name.trim(),
39
- start: line.start,
40
- textEnd: line.start + line.text.length,
41
- next: line.next,
42
- });
43
- });
29
+ let fences = null;
30
+ let i = from;
31
+ while (i < to) {
32
+ const nl = content.indexOf('\n', i);
33
+ const end = nl === -1 || nl >= to ? to : nl;
34
+ const next = end === to ? to : end + 1;
35
+ if (content.charCodeAt(i) === HASH) {
36
+ fences ??= fenceSpans(content.slice(from, to));
37
+ const at = i - from;
38
+ if (!fences.some(([start, stop]) => at >= start && at < stop)) {
39
+ const { text } = lineAt(content, i, to);
40
+ const match = HEADING.exec(text);
41
+ const hashes = match?.[1];
42
+ const name = match?.[2];
43
+ if (hashes !== undefined && name !== undefined) {
44
+ found.push({
45
+ level: hashes.length,
46
+ name: name.trim(),
47
+ start: i,
48
+ textEnd: i + text.length,
49
+ next,
50
+ });
51
+ }
52
+ }
53
+ }
54
+ if (next === i)
55
+ break;
56
+ i = next;
57
+ }
44
58
  return found;
45
59
  }
46
60
  export function blockRanges(content, from, to) {
@@ -77,18 +77,30 @@ export type DateCondition = {
77
77
  };
78
78
  export type Condition = DocumentCondition | ItemCondition | CronCondition | DateCondition;
79
79
  export type FactKind = 'string' | 'number' | 'boolean' | 'date' | 'time' | 'enum' | 'reference';
80
+ type Scalar = string | number | boolean;
80
81
  export type Fact = {
81
82
  readonly kind: FactKind;
82
- readonly value: Scalar | readonly Scalar[];
83
+ readonly value: Scalar;
84
+ readonly member?: string;
85
+ } | {
86
+ readonly kind: 'prose';
87
+ } | {
88
+ readonly kind: 'null';
89
+ } | {
90
+ readonly kind: 'unreadable';
91
+ } | {
92
+ readonly kind: 'list';
93
+ readonly items: readonly Fact[];
94
+ } | {
95
+ readonly kind: 'object';
96
+ readonly fields: Readonly<Record<string, Fact>>;
83
97
  };
84
98
  export type DocumentFacts = {
85
99
  readonly id: string;
86
100
  readonly path: string;
87
101
  readonly type: string | null;
88
102
  readonly fields: Readonly<Record<string, Fact>>;
89
- readonly members: Readonly<Record<string, string | readonly string[]>>;
90
- readonly prose: readonly string[];
91
- readonly unreadable: readonly string[];
103
+ readonly sections: readonly string[];
92
104
  };
93
105
  export declare const WRITE_DOORS: readonly ['browser', 'agent', 'client'];
94
106
  export type WriteDoor = (typeof WRITE_DOORS)[number];
@@ -121,12 +133,12 @@ export type Resolved = {
121
133
  readonly member?: string;
122
134
  };
123
135
  type Truth = boolean | undefined;
124
- type Scalar = string | number | boolean;
125
136
  export declare function factKind(facts: ValueFacts): FactKind | null;
126
137
  export declare function facts(document: Document, at: {
127
138
  readonly id: string;
128
139
  readonly path: string;
129
140
  }, model: VerifiedModel, resolve: (target: string) => Resolved | undefined): DocumentFacts;
141
+ export declare function prosePaths(facts: DocumentFacts): string[];
130
142
  export declare function dated(value: unknown): value is string;
131
143
  export declare function instant(value: unknown): bigint | undefined;
132
144
  export declare function pointed(value: unknown, pointer: string): unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":"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"}
package/dist/condition.js CHANGED
@@ -1,7 +1,12 @@
1
- import { ARRAY_INDEX } from './definition.js';
1
+ import { ARRAY_INDEX, escapePointer, fieldFacts, itemFacts, memberFacts, pointerSegments, } from './definition.js';
2
2
  import { target } from './paths.js';
3
- import { isRecord } from './yaml.js';
3
+ import { isRecord, plain } from './yaml.js';
4
4
  export const WRITE_DOORS = ['browser', 'agent', 'client'];
5
+ const PROSE = { kind: 'prose' };
6
+ const NULL = { kind: 'null' };
7
+ const UNREADABLE = { kind: 'unreadable' };
8
+ const UNREAD = { present: undefined, values: [undefined], items: [undefined] };
9
+ const NO_ITEM = { present: false, values: [], items: [] };
5
10
  const DATE = /^\d{4}-\d{2}-\d{2}$/u;
6
11
  const DATE_TIME = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(?:[Zz]|([+-])(\d{2}):(\d{2}))$/u;
7
12
  export function factKind(facts) {
@@ -21,9 +26,6 @@ export function factKind(facts) {
21
26
  return 'time';
22
27
  return 'string';
23
28
  }
24
- function referenced(model, facts) {
25
- return (facts.reference ?? []).some((to) => Object.hasOwn(model.types, to) && model.types[to].memberDocument);
26
- }
27
29
  function fits(kind, facts, value) {
28
30
  if (!scalar(value))
29
31
  return false;
@@ -41,81 +43,156 @@ function fits(kind, facts, value) {
41
43
  return instant(value) !== undefined;
42
44
  return true;
43
45
  }
44
- function fitted(kind, facts, value, path, resolve) {
45
- if (!fits(kind, facts, value))
46
- return undefined;
46
+ function factOf(value, declared, place) {
47
+ if (value === null)
48
+ return NULL;
49
+ if (Array.isArray(value)) {
50
+ if (declared?.type !== undefined && declared.type !== 'array')
51
+ return UNREADABLE;
52
+ return {
53
+ kind: 'list',
54
+ items: value.map((item, index) => factOf(item, declared === undefined ? undefined : itemFacts(declared, index), place)),
55
+ };
56
+ }
57
+ if (plain(value)) {
58
+ if (declared?.type !== undefined && declared.type !== 'object')
59
+ return UNREADABLE;
60
+ const fields = Object.create(null);
61
+ for (const [key, held] of Object.entries(value))
62
+ fields[key] = factOf(held, declared === undefined ? undefined : memberFacts(declared, key), place);
63
+ return { kind: 'object', fields };
64
+ }
65
+ if (declared?.type === 'array' || declared?.type === 'object')
66
+ return UNREADABLE;
67
+ const kind = declared === undefined || declared.prose ? null : factKind(declared);
68
+ if (kind === null)
69
+ return PROSE;
70
+ if (!fits(kind, declared, value))
71
+ return UNREADABLE;
47
72
  if (kind !== 'reference')
48
- return { value };
49
- const reached = target(path, value);
50
- return reached === null ? undefined : resolve(reached);
73
+ return { kind, value };
74
+ const reached = target(place.path, value);
75
+ const resolved = reached === null ? undefined : place.resolve(reached);
76
+ if (resolved === undefined)
77
+ return UNREADABLE;
78
+ return resolved.member === undefined
79
+ ? { kind, value: resolved.id }
80
+ : { kind, value: resolved.id, member: resolved.member };
51
81
  }
52
82
  export function facts(document, at, model, resolve) {
53
83
  const type = document.type ?? null;
54
84
  const definition = type !== null && Object.hasOwn(model.types, type) ? model.types[type] : null;
55
- const fields = {};
56
- const members = {};
57
- const prose = Object.keys(document.sections).map((heading) => `/sections/${heading}`);
58
- const unreadable = [];
59
- for (const [name, declared] of Object.entries(definition === null ? {} : definition.fields)) {
60
- const value = document.fields[name];
61
- if (value === undefined || value === null)
62
- continue;
63
- const list = declared.type === 'array';
64
- const facts = list ? declared.items : declared;
65
- const kind = facts === undefined || facts.prose ? null : factKind(facts);
66
- if (kind === null) {
67
- prose.push(`/fields/${name}`);
68
- continue;
69
- }
70
- const items = list ? value : [value];
71
- const held = Array.isArray(items)
72
- ? items.map((item) => fitted(kind, facts, item, at.path, resolve))
73
- : [undefined];
74
- if (held.some((item) => item === undefined)) {
75
- unreadable.push(`/fields/${name}`);
76
- if (referenced(model, facts))
77
- unreadable.push(`/members/${name}`);
78
- continue;
79
- }
80
- const values = held.map((item) => ('id' in item ? item.id : item.value));
81
- fields[name] = { kind, value: list ? values : values[0] };
82
- if (!referenced(model, facts))
83
- continue;
84
- const bound = held.flatMap((item) => 'member' in item && item.member !== undefined ? [item.member] : []);
85
- if (list)
86
- members[name] = bound;
87
- else if (bound[0] !== undefined)
88
- members[name] = bound[0];
85
+ const fields = Object.create(null);
86
+ const place = { path: at.path, resolve };
87
+ for (const [name, value] of Object.entries(document.fields)) {
88
+ const declared = definition === null ? undefined : fieldFacts(definition, name);
89
+ if (declared !== undefined)
90
+ fields[name] = factOf(value, declared, place);
89
91
  }
90
92
  return {
91
93
  id: at.id,
92
94
  path: `/${at.path}`,
93
95
  type,
94
96
  fields,
95
- members,
96
- prose: prose.sort(),
97
- unreadable: unreadable.sort(),
97
+ sections: Object.keys(document.sections).sort(),
98
+ };
99
+ }
100
+ function rootOf(facts, prefix) {
101
+ return { pointer: prefix, fact: { kind: 'object', fields: facts.fields } };
102
+ }
103
+ export function prosePaths(facts) {
104
+ const paths = facts.sections.map((heading) => `/sections/${heading}`);
105
+ const visit = ({ pointer, fact }) => {
106
+ if (fact.kind === 'prose')
107
+ paths.push(pointer);
108
+ if (fact.kind === 'list')
109
+ fact.items.forEach((item, index) => visit({ pointer: `${pointer}/${index}`, fact: item }));
110
+ if (fact.kind === 'object')
111
+ for (const [key, held] of Object.entries(fact.fields))
112
+ visit({ pointer: `${pointer}/${escapePointer(key)}`, fact: held });
113
+ };
114
+ visit(rootOf(facts, '/fields'));
115
+ return paths.sort();
116
+ }
117
+ function walked(start, pointer) {
118
+ let reached = [start];
119
+ let several = false;
120
+ let missing = false;
121
+ const each = (from, next) => from.flatMap((one) => {
122
+ const found = next(one);
123
+ if (found === null)
124
+ missing = true;
125
+ return found ?? [];
126
+ });
127
+ for (const token of pointerSegments(pointer)) {
128
+ const step = ({ pointer: at, fact }) => {
129
+ if (fact.kind === 'unreadable')
130
+ return [{ pointer: at, fact }];
131
+ if (fact.kind === 'object')
132
+ return Object.hasOwn(fact.fields, token)
133
+ ? [{ pointer: `${at}/${escapePointer(token)}`, fact: fact.fields[token] }]
134
+ : null;
135
+ if (fact.kind !== 'list')
136
+ return null;
137
+ if (ARRAY_INDEX.test(token)) {
138
+ const item = fact.items[Number(token)];
139
+ return item === undefined ? null : [{ pointer: `${at}/${token}`, fact: item }];
140
+ }
141
+ several = true;
142
+ return each(fact.items.map((item, index) => ({ pointer: `${at}/${index}`, fact: item })), step);
143
+ };
144
+ reached = each(reached, step);
145
+ }
146
+ return { reached, several, missing };
147
+ }
148
+ function expand(fact) {
149
+ return fact.kind === 'list' ? fact.items.flatMap(expand) : [fact];
150
+ }
151
+ function fieldHeld(fact) {
152
+ if (fact.kind === 'unreadable')
153
+ return undefined;
154
+ if (fact.kind === 'null')
155
+ return { kind: 'null' };
156
+ return 'value' in fact ? { kind: fact.kind, value: fact.value } : { kind: 'prose' };
157
+ }
158
+ function memberHeld(fact) {
159
+ if (fact.kind === 'unreadable')
160
+ return undefined;
161
+ return fact.kind === 'reference' && fact.member !== undefined
162
+ ? { kind: 'member', value: fact.member }
163
+ : null;
164
+ }
165
+ function single(held) {
166
+ return { present: true, values: [held], items: null };
167
+ }
168
+ function documentRead({ reached, several, missing }, held) {
169
+ if (reached.length === 0)
170
+ return missing ? undefined : NO_ITEM;
171
+ const facts = reached.map(({ fact }) => fact);
172
+ const kept = (all) => all.map(held).filter((value) => value !== null);
173
+ const unknown = missing ? [undefined] : [];
174
+ const values = kept(facts.filter((fact) => fact.kind !== 'list'));
175
+ const listed = several || facts.some((fact) => fact.kind === 'list');
176
+ const present = facts.some((fact) => fact.kind === 'list') || values.some(Boolean);
177
+ return {
178
+ present: present ? true : values.length > 0 ? undefined : false,
179
+ values: [...values, ...unknown],
180
+ items: listed ? [...kept(facts.flatMap(expand)), ...unknown] : null,
98
181
  };
99
182
  }
100
183
  function readDocument(facts, path) {
101
184
  if (path === '/path')
102
- return { kind: 'path', value: facts.path };
185
+ return single({ kind: 'path', value: facts.path });
103
186
  if (path === '/type')
104
- return facts.type === null ? undefined : { kind: 'string', value: facts.type };
105
- if (facts.unreadable.includes(path))
106
- return { kind: 'unreadable' };
107
- if (facts.prose.includes(path))
108
- return { kind: 'present' };
109
- if (path.startsWith('/fields/')) {
110
- const name = path.slice('/fields/'.length);
111
- return Object.hasOwn(facts.fields, name) ? facts.fields[name] : undefined;
112
- }
113
- if (path.startsWith('/members/')) {
114
- const name = path.slice('/members/'.length);
115
- return Object.hasOwn(facts.members, name)
116
- ? { kind: 'member', value: facts.members[name] }
187
+ return facts.type === null ? undefined : single({ kind: 'string', value: facts.type });
188
+ if (path.startsWith('/sections/'))
189
+ return facts.sections.includes(path.slice('/sections/'.length))
190
+ ? single({ kind: 'prose' })
117
191
  : undefined;
118
- }
192
+ if (path.startsWith('/fields/'))
193
+ return documentRead(walked(rootOf(facts, '/fields'), path.slice('/fields'.length)), fieldHeld);
194
+ if (path.startsWith('/members/'))
195
+ return documentRead(walked(rootOf(facts, '/members'), path.slice('/members'.length)), memberHeld);
119
196
  return undefined;
120
197
  }
121
198
  function readActor(actor, path) {
@@ -126,13 +203,7 @@ function readActor(actor, path) {
126
203
  : path === '/door'
127
204
  ? actor.door
128
205
  : undefined;
129
- return value === undefined ? undefined : { kind: 'actor', value };
130
- }
131
- function plain(value) {
132
- if (!isRecord(value))
133
- return false;
134
- const prototype = Object.getPrototypeOf(value);
135
- return prototype === Object.prototype || prototype === null;
206
+ return value === undefined ? undefined : single({ kind: 'actor', value });
136
207
  }
137
208
  export function dated(value) {
138
209
  return (typeof value === 'string' && DATE.test(value) && instant(`${value}T00:00:00Z`) !== undefined);
@@ -187,8 +258,6 @@ function scalar(value) {
187
258
  (typeof value === 'number' && Number.isFinite(value)));
188
259
  }
189
260
  function jsonHeld(value) {
190
- if (value === undefined)
191
- return undefined;
192
261
  if (typeof value === 'string')
193
262
  return {
194
263
  kind: dated(value) ? 'date' : instant(value) === undefined ? 'string' : 'time',
@@ -196,26 +265,31 @@ function jsonHeld(value) {
196
265
  };
197
266
  if (typeof value === 'boolean')
198
267
  return { kind: 'boolean', value };
268
+ return { kind: 'number', value };
269
+ }
270
+ function jsonRead(value) {
271
+ if (value === undefined)
272
+ return undefined;
199
273
  if (scalar(value))
200
- return { kind: 'number', value };
201
- if (Array.isArray(value))
202
- return { kind: 'list', value: value.filter(scalar) };
203
- return { kind: 'present' };
274
+ return single(jsonHeld(value));
275
+ if (!Array.isArray(value))
276
+ return single({ kind: 'prose' });
277
+ return { present: true, values: [], items: value.filter(scalar).map(jsonHeld), loose: true };
204
278
  }
205
279
  function readItem(item, path) {
206
280
  if (path.startsWith('/json/')) {
207
281
  if (item.json === null)
208
- return { kind: 'unreadable' };
209
- return jsonHeld(pointed(item.json.value, path.slice('/json'.length)));
282
+ return UNREAD;
283
+ return jsonRead(pointed(item.json.value, path.slice('/json'.length)));
210
284
  }
211
285
  if (path.startsWith('/headers/')) {
212
286
  const name = path.slice('/headers/'.length);
213
287
  return Object.hasOwn(item.headers, name)
214
- ? { kind: 'string', value: item.headers[name] }
288
+ ? single({ kind: 'string', value: item.headers[name] })
215
289
  : undefined;
216
290
  }
217
291
  if (path === '/has_attachment')
218
- return { kind: 'boolean', value: item.has_attachment };
292
+ return single({ kind: 'boolean', value: item.has_attachment });
219
293
  const value = path === '/delivery'
220
294
  ? item.delivery
221
295
  : path === '/source'
@@ -227,13 +301,13 @@ function readItem(item, path) {
227
301
  : path === '/author'
228
302
  ? item.author
229
303
  : null;
230
- return value === null ? undefined : { kind: 'string', value };
304
+ return value === null ? undefined : single({ kind: 'string', value });
231
305
  }
232
306
  function wanted(value, owner) {
233
307
  return isRecord(value) && value.owner === true ? owner : value;
234
308
  }
235
309
  function equal(held, value, owner) {
236
- if (held.kind === 'present' || Array.isArray(held.value))
310
+ if (!('value' in held))
237
311
  return undefined;
238
312
  const expected = wanted(value, owner);
239
313
  if (typeof expected !== typeof held.value)
@@ -248,7 +322,7 @@ function sign(left, right) {
248
322
  return left < right ? -1 : left > right ? 1 : 0;
249
323
  }
250
324
  function ordered(held, value, compare) {
251
- if (held.kind === 'present' || Array.isArray(held.value))
325
+ if (!('value' in held))
252
326
  return undefined;
253
327
  if (held.kind === 'number') {
254
328
  if (typeof value !== 'number' || typeof held.value !== 'number')
@@ -278,29 +352,13 @@ function allOf(truths) {
278
352
  return false;
279
353
  return truths.some((truth) => truth === undefined) ? undefined : true;
280
354
  }
281
- function leaf(test, held, owner) {
282
- if (held?.kind === 'unreadable')
283
- return undefined;
284
- if ('exists' in test)
285
- return (held !== undefined) === test.exists;
286
- if (held === undefined)
287
- return undefined;
355
+ function compared(test, held, owner) {
288
356
  if ('eq' in test)
289
357
  return equal(held, test.eq, owner);
290
358
  if ('in' in test)
291
359
  return anyOf(test.in.map((value) => equal(held, value, owner)));
292
- if ('contains' in test) {
293
- if (held.kind === 'present' || !Array.isArray(held.value))
294
- return undefined;
295
- const expected = wanted(test.contains, owner);
296
- if (held.value.some((item) => item === expected))
297
- return true;
298
- if (held.kind === 'list')
299
- return false;
300
- return held.value.every((item) => typeof item === typeof expected) ? false : undefined;
301
- }
302
360
  if ('prefix' in test) {
303
- if (held.kind === 'present' || typeof held.value !== 'string')
361
+ if (!('value' in held) || typeof held.value !== 'string')
304
362
  return undefined;
305
363
  if (held.kind === 'number' || held.kind === 'reference' || held.kind === 'member')
306
364
  return undefined;
@@ -314,6 +372,23 @@ function leaf(test, held, owner) {
314
372
  return ordered(held, test.lt, (sign) => sign < 0);
315
373
  return ordered(held, test.lte, (sign) => sign <= 0);
316
374
  }
375
+ function leaf(test, read, owner) {
376
+ if ('exists' in test) {
377
+ const present = read === undefined ? false : read.present;
378
+ return present === undefined ? undefined : present === test.exists;
379
+ }
380
+ if (read === undefined)
381
+ return undefined;
382
+ if ('contains' in test) {
383
+ if (read.items === null)
384
+ return undefined;
385
+ const truths = read.items.map((item) => item === undefined ? undefined : equal(item, test.contains, owner));
386
+ return read.loose === true && !truths.includes(true) ? false : anyOf(truths);
387
+ }
388
+ if (read.values.length === 0)
389
+ return read === NO_ITEM ? false : undefined;
390
+ return anyOf(read.values.map((value) => (value === undefined ? undefined : compared(test, value, owner))));
391
+ }
317
392
  function evaluated(test, read, owner) {
318
393
  if ('all' in test)
319
394
  return allOf(test.all.map((part) => evaluated(part, read, owner)));
@@ -342,24 +417,46 @@ function matched(condition, test, document, owner) {
342
417
  return false;
343
418
  return test === undefined || holds(test, document, owner) === true;
344
419
  }
345
- function sameFact(left, right) {
346
- return JSON.stringify(left) === JSON.stringify(right);
420
+ function reachedAt(document, field) {
421
+ if (document === null)
422
+ return [];
423
+ if (field.startsWith('/sections/'))
424
+ return document.sections.includes(field.slice('/sections/'.length))
425
+ ? [{ pointer: field, fact: PROSE }]
426
+ : [];
427
+ if (!field.startsWith('/fields/'))
428
+ return [];
429
+ return walked(rootOf(document, '/fields'), field.slice('/fields'.length)).reached;
430
+ }
431
+ function valueOf(fact) {
432
+ if (fact.kind === 'list')
433
+ return { kind: fact.kind, items: fact.items.map(valueOf) };
434
+ if (fact.kind === 'object')
435
+ return {
436
+ kind: fact.kind,
437
+ fields: Object.keys(fact.fields)
438
+ .sort()
439
+ .map((key) => [key, valueOf(fact.fields[key])]),
440
+ };
441
+ return 'value' in fact ? { kind: fact.kind, value: fact.value } : fact;
442
+ }
443
+ function signature(reached) {
444
+ return JSON.stringify(reached.map(({ fact }) => valueOf(fact)));
347
445
  }
348
446
  function among(values, document, field, owner) {
349
447
  return holds({ path: field, in: values }, document, owner) === true;
350
448
  }
351
449
  function fieldChanged(condition, event, owner) {
352
450
  const { field, from, to } = condition;
353
- if (from === undefined && to === undefined && event.changed.includes(field))
451
+ const before = reachedAt(event.before, field);
452
+ const after = reachedAt(event.after, field);
453
+ const pointers = [field, ...[...before, ...after].map(({ pointer }) => pointer)];
454
+ const prose = event.changed.some((changed) => pointers.some((pointer) => changed === pointer || changed.startsWith(`${pointer}/`)));
455
+ if (from === undefined && to === undefined && prose)
354
456
  return true;
355
- if (!field.startsWith('/fields/'))
356
- return false;
357
- const name = field.slice('/fields/'.length);
358
- const before = event.before?.fields[name];
359
- const after = event.after?.fields[name];
360
- if (before === undefined && after === undefined)
457
+ if (before.length === 0 && after.length === 0)
361
458
  return false;
362
- if (event.before !== null && event.after !== null && sameFact(before, after))
459
+ if (event.before !== null && event.after !== null && signature(before) === signature(after))
363
460
  return false;
364
461
  if (from === 'new'
365
462
  ? event.before !== null
@@ -54,5 +54,13 @@ export declare function refTarget(reference: string, defs: Readonly<Record<strin
54
54
  export declare function valueFacts(node: unknown, defs: Readonly<Record<string, unknown>>): ValueFacts;
55
55
  export declare function itemFacts(facts: ValueFacts, index: number): ValueFacts | undefined;
56
56
  export declare function memberFacts(facts: ValueFacts, key: string): ValueFacts | undefined;
57
+ export type PointerFacts = {
58
+ readonly facts: ValueFacts;
59
+ readonly through: boolean;
60
+ readonly conditional: boolean;
61
+ };
62
+ export declare function crossedFacts(facts: ValueFacts): ValueFacts[];
63
+ export declare function fieldFacts(definition: Definition, key: string): ValueFacts | undefined;
64
+ export declare function pointerFacts(definition: Definition, pointer: string): PointerFacts | undefined;
57
65
  export declare function readSchema(text: string): VerifiedModel | Failure;
58
66
  //# sourceMappingURL=definition.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAEjG,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAEpF,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAEtF,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IACzD,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAc5E,eAAO,MAAM,UAAU,EAAE,SAAS,QAAQ,EAQzC,CAAC;AAEF,eAAO,MAAM,aAAa,QAAQ,CAAC;AAEnC,eAAO,MAAM,UAAU,eAAe,CAAC;AAQvC,eAAO,MAAM,WAAW,QAAyB,CAAC;AAYlD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAMD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAEzD;AAED,wBAAgB,SAAS,CACvB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAiC/D;AA4UD,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,UAAU,CAE7F;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAElF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAKlF;AAmGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,CAiChE"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"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"}
@@ -370,6 +370,54 @@ export function memberFacts(facts, key) {
370
370
  const pattern = facts.patterns?.find((one) => new RegExp(one.pattern, 'u').test(key));
371
371
  return pattern === undefined ? facts.additional : pattern.facts;
372
372
  }
373
+ export function crossedFacts(facts) {
374
+ if (facts.type !== 'array')
375
+ return [facts];
376
+ return [...(facts.prefix ?? []), ...(facts.items === undefined ? [] : [facts.items])].flatMap(crossedFacts);
377
+ }
378
+ export function fieldFacts(definition, key) {
379
+ if (Object.hasOwn(definition.fields, key))
380
+ return definition.fields[key];
381
+ if (Object.hasOwn(HOUSE_KEYS, key))
382
+ return undefined;
383
+ return memberFacts(definition.frontmatter, key);
384
+ }
385
+ function stepped({ facts, through, conditional }, token) {
386
+ if (facts.type === 'array' && ARRAY_INDEX.test(token)) {
387
+ const item = itemFacts(facts, Number(token));
388
+ return item === undefined ? [] : [{ facts: item, through, conditional }];
389
+ }
390
+ return crossedFacts(facts).flatMap((crossed) => {
391
+ const member = memberFacts(crossed, token);
392
+ return member === undefined
393
+ ? []
394
+ : [
395
+ {
396
+ facts: member,
397
+ through: through || facts.type === 'array',
398
+ conditional: conditional || member.conditional === true,
399
+ },
400
+ ];
401
+ });
402
+ }
403
+ export function pointerFacts(definition, pointer) {
404
+ const [field, ...rest] = pointerSegments(pointer);
405
+ const declared = field === undefined ? undefined : fieldFacts(definition, field);
406
+ if (declared === undefined)
407
+ return undefined;
408
+ let reached = [
409
+ { facts: declared, through: false, conditional: declared.conditional === true },
410
+ ];
411
+ for (const token of rest)
412
+ reached = reached.flatMap((held) => stepped(held, token));
413
+ if (reached.length === 0)
414
+ return undefined;
415
+ return reached.reduce((kept, held) => ({
416
+ facts: joined(kept.facts, held.facts),
417
+ through: kept.through || held.through,
418
+ conditional: kept.conditional || held.conditional,
419
+ }));
420
+ }
373
421
  function reachedDefs(value, defs, reached) {
374
422
  if (Array.isArray(value)) {
375
423
  for (const item of value)
@@ -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;AAMhF,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,WAAW,EAEZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAYL,KAAK,OAAO,EAEb,MAAM,WAAW,CAAC;AAwCnB,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,WAAW,CAkD7D;AA2KD,wBAAgB,UAAU,CACxB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,GACtB,WAAW,CAYb;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAOrF;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,UAAU,CAeZ;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;AAED,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAerE;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEpD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,IAAI,CAE9D"}
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMhF,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,WAAW,EAEZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAaL,KAAK,OAAO,EAEb,MAAM,WAAW,CAAC;AAwCnB,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,WAAW,CAkD7D;AA8KD,wBAAgB,UAAU,CACxB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,GACtB,WAAW,CAYb;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAOrF;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,UAAU,CAeZ;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;AAED,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAOrE;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEpD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,GAAG,IAAI,CAE9D"}
package/dist/document.js CHANGED
@@ -4,7 +4,7 @@ import { relative, retarget, SHELL_ROOMS, shellTarget, target } from './paths.js
4
4
  import { references } from './references.js';
5
5
  import { headingSpans, sectionsRecord } from './sections.js';
6
6
  import { refusal } from './refuse.js';
7
- import { bodyStartAfterYaml, bodyStartOf, equalValue, extractFrontmatter, jsValue, lineEnding, mapEntry, parseYamlMapping, serializeJs, serializeKey, YamlError, } from './yaml.js';
7
+ import { bodyStartAfterYaml, bodyStartOf, equalValue, extractFrontmatter, frontmatterValue, jsValue, lineEnding, mapEntry, parseYamlMapping, serializeJs, serializeKey, YamlError, } from './yaml.js';
8
8
  const internals = new WeakMap();
9
9
  function refuse(file, rule, location) {
10
10
  return location === undefined ? refusal(file, rule) : refusal(file, rule, { location });
@@ -78,6 +78,9 @@ function applyField(document, name, value, prior) {
78
78
  if (!equalValue(document.fields[name], prior)) {
79
79
  return { outcome: 'stale', document };
80
80
  }
81
+ if (!frontmatterValue(value)) {
82
+ return { outcome: 'refuse', refusal: refuse('', 'frontmatter-fence', name) };
83
+ }
81
84
  let nextContent;
82
85
  const existing = mapEntry(internal.root, name);
83
86
  if (existing !== undefined) {
@@ -297,17 +300,9 @@ export function apply(document, change) {
297
300
  return applyReference(document, change.pointer, change.value, change.prior);
298
301
  if (change.kind === 'preamble')
299
302
  return applyPreamble(document, change.value, change.prior);
300
- try {
301
- if (change.kind === 'field')
302
- return applyField(document, change.name, change.value, change.prior);
303
- return applySection(document, change.name, change.value, change.prior);
304
- }
305
- catch (error) {
306
- if (error instanceof YamlError) {
307
- return { outcome: 'refuse', refusal: refuse('', 'frontmatter-fence', change.name) };
308
- }
309
- throw error;
310
- }
303
+ if (change.kind === 'field')
304
+ return applyField(document, change.name, change.value, change.prior);
305
+ return applySection(document, change.name, change.value, change.prior);
311
306
  }
312
307
  export function serialize(document) {
313
308
  return document.content;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { dated, factKind, facts, fires, holds, instant, itemFires, pointed, WRITE_DOORS, } from './condition.js';
1
+ export { dated, factKind, facts, fires, holds, instant, itemFires, pointed, prosePaths, WRITE_DOORS, } from './condition.js';
2
2
  export type { Actor, Condition, ConditionScope, ConditionTest, ConditionValue, CronCondition, DateCondition, DocumentCondition, DocumentEvent, DocumentFacts, Fact, FactKind, ItemCondition, ItemFacts, Resolved, WriteDoor, } from './condition.js';
3
3
  export { divide } from './divide.js';
4
4
  export { apply, bodyLinks, links, parse, relativize, relativizeBody, relinkBody, serialize, } from './document.js';
@@ -7,9 +7,11 @@ export { relative, retarget, target } from './paths.js';
7
7
  export { MARKDOWN_SYNTAX_PROFILE } from './profile.js';
8
8
  export { project } from './project.js';
9
9
  export { references } from './references.js';
10
- export { ARRAY_INDEX, ATTACHMENT, escapePointer, itemFacts, memberFacts, pointerSegments, } from './definition.js';
11
- export type { Definition, JsonType, PatternFacts, SectionSpec, Shape, ValueFacts, } from './definition.js';
10
+ export { ARRAY_INDEX, ATTACHMENT, crossedFacts, escapePointer, itemFacts, memberFacts, pointerFacts, pointerSegments, } from './definition.js';
11
+ export type { Definition, JsonType, PatternFacts, PointerFacts, SectionSpec, Shape, ValueFacts, } from './definition.js';
12
12
  export type { ApplyResult, BodyResult, Change, Division, DivisionContext, Document, Library, ModelVerification, Link, ParseResult, Projection, ProjectionContext, Reference, Refusal, Span, Validation, ValidationContext, VerifiedModel, } from './types.js';
13
13
  export { validate, verify } from './validate.js';
14
14
  export { VERSION } from './version.js';
15
+ export { equalValue, frontmatterValue } from './yaml.js';
16
+ export type { FrontmatterValue } from './yaml.js';
15
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,QAAQ,EACR,KAAK,EACL,KAAK,EACL,KAAK,EACL,OAAO,EACP,SAAS,EACT,OAAO,EACP,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,KAAK,EACL,SAAS,EACT,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,SAAS,EACT,QAAQ,EACR,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EACL,KAAK,EACL,SAAS,EACT,KAAK,EACL,KAAK,EACL,UAAU,EACV,cAAc,EACd,UAAU,EACV,SAAS,GACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EACL,WAAW,EACX,UAAU,EACV,aAAa,EACb,SAAS,EACT,WAAW,EACX,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,KAAK,EACL,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,WAAW,EACX,UAAU,EACV,MAAM,EACN,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,OAAO,EACP,iBAAiB,EACjB,IAAI,EACJ,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,IAAI,EACJ,UAAU,EACV,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,QAAQ,EACR,KAAK,EACL,KAAK,EACL,KAAK,EACL,OAAO,EACP,SAAS,EACT,OAAO,EACP,UAAU,EACV,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,KAAK,EACL,SAAS,EACT,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,SAAS,EACT,QAAQ,EACR,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EACL,KAAK,EACL,SAAS,EACT,KAAK,EACL,KAAK,EACL,UAAU,EACV,cAAc,EACd,UAAU,EACV,SAAS,GACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,WAAW,EACX,YAAY,EACZ,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,KAAK,EACL,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,WAAW,EACX,UAAU,EACV,MAAM,EACN,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,OAAO,EACP,iBAAiB,EACjB,IAAI,EACJ,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,IAAI,EACJ,UAAU,EACV,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACzD,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { dated, factKind, facts, fires, holds, instant, itemFires, pointed, WRITE_DOORS, } from './condition.js';
1
+ export { dated, factKind, facts, fires, holds, instant, itemFires, pointed, prosePaths, WRITE_DOORS, } from './condition.js';
2
2
  export { divide } from './divide.js';
3
3
  export { apply, bodyLinks, links, parse, relativize, relativizeBody, relinkBody, serialize, } from './document.js';
4
4
  export { MEMBER_FIELD, RECEIVED_FIELD, SITE_FIELD } from './fields.js';
@@ -6,6 +6,7 @@ export { relative, retarget, target } from './paths.js';
6
6
  export { MARKDOWN_SYNTAX_PROFILE } from './profile.js';
7
7
  export { project } from './project.js';
8
8
  export { references } from './references.js';
9
- export { ARRAY_INDEX, ATTACHMENT, escapePointer, itemFacts, memberFacts, pointerSegments, } from './definition.js';
9
+ export { ARRAY_INDEX, ATTACHMENT, crossedFacts, escapePointer, itemFacts, memberFacts, pointerFacts, pointerSegments, } from './definition.js';
10
10
  export { validate, verify } from './validate.js';
11
11
  export { VERSION } from './version.js';
12
+ export { equalValue, frontmatterValue } from './yaml.js';
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAGV,OAAO,EACP,iBAAiB,EAEjB,UAAU,EACV,iBAAiB,EACjB,aAAa,EACd,MAAM,YAAY,CAAC;AAwDpB,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAQxD;AAED,wBAAgB,QAAQ,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,iBAAyC,EAClD,KAAK,GAAE,aAA6B,GACnC,UAAU,CAyGZ"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAGV,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,aAAa,EACd,MAAM,YAAY,CAAC;AAwDpB,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAQxD;AAED,wBAAgB,QAAQ,CACtB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,iBAAyC,EAClD,KAAK,GAAE,aAA6B,GACnC,UAAU,CAqGZ"}
package/dist/validate.js CHANGED
@@ -18,7 +18,7 @@ function instanceType(document) {
18
18
  return null;
19
19
  return raw;
20
20
  }
21
- function reaches(file, href, to, documents, binaryTargets) {
21
+ function reaches(file, href, to, types, binaryTargets) {
22
22
  const resolved = classifyHref(file, href);
23
23
  if (resolved.kind !== 'path')
24
24
  return false;
@@ -26,8 +26,8 @@ function reaches(file, href, to, documents, binaryTargets) {
26
26
  return true;
27
27
  if (binaryTargets.has(resolved.path))
28
28
  return false;
29
- const held = documents.get(resolved.path);
30
- return held === undefined || (held.ok && to.includes(held.document.type ?? BUILT_IN_TYPE));
29
+ const held = types.get(resolved.path);
30
+ return held === undefined || to.includes(held);
31
31
  }
32
32
  function itemHrefs(content, items) {
33
33
  const bodyStart = bodyStartOf(content);
@@ -56,28 +56,28 @@ export function verify(schema) {
56
56
  export function validate(library, context = { binaryTargets: [] }, model = { types: {} }) {
57
57
  const binaryTargets = new Set(context.binaryTargets);
58
58
  const files = Object.keys(library).sort();
59
+ const types = new Map();
59
60
  const documents = new Map();
60
61
  for (const file of files) {
61
62
  if (binaryTargets.has(file))
62
63
  return refuse(file, 'binary-target-document');
63
64
  const parsed = parse(library[file], file);
64
- documents.set(file, parsed);
65
65
  if (!parsed.ok)
66
66
  return { verdict: 'refuse', ...parsed.refusal };
67
+ types.set(file, parsed.document.type ?? BUILT_IN_TYPE);
68
+ if (instanceType(parsed.document) !== BUILT_IN_TYPE)
69
+ documents.set(file, parsed.document);
67
70
  }
68
71
  const definitions = new Map(Object.entries(model.types));
69
72
  const sectionReferences = new Map();
70
- for (const file of files) {
71
- const parsed = documents.get(file);
72
- if (parsed === undefined || !parsed.ok)
73
- continue;
74
- const kind = instanceType(parsed.document);
73
+ for (const [file, document] of documents) {
74
+ const kind = instanceType(document);
75
75
  if (kind === BUILT_IN_TYPE)
76
76
  continue;
77
77
  const definition = kind === null ? undefined : definitions.get(kind);
78
78
  if (definition === undefined)
79
79
  return refuse(file, 'unknown-type', { location: '/type' });
80
- const fieldFailure = frontmatterRefusal(definition, parsed.document.fields);
80
+ const fieldFailure = frontmatterRefusal(definition, document.fields);
81
81
  if (fieldFailure !== undefined) {
82
82
  return refuse(file, fieldFailure.rule, { location: fieldFailure.location });
83
83
  }
@@ -105,18 +105,15 @@ export function validate(library, context = { binaryTargets: [] }, model = { typ
105
105
  }
106
106
  sectionReferences.set(file, references);
107
107
  }
108
- for (const file of files) {
109
- const parsed = documents.get(file);
110
- if (parsed === undefined || !parsed.ok)
111
- continue;
112
- const kind = instanceType(parsed.document);
108
+ for (const [file, document] of documents) {
109
+ const kind = instanceType(document);
113
110
  if (kind === null || kind === BUILT_IN_TYPE)
114
111
  continue;
115
112
  const definition = definitions.get(kind);
116
113
  if (definition === undefined)
117
114
  continue;
118
- for (const { pointer, to, value } of references(parsed.document, definition)) {
119
- if (!reaches(file, value, to, documents, binaryTargets))
115
+ for (const { pointer, to, value } of references(document, definition)) {
116
+ if (!reaches(file, value, to, types, binaryTargets))
120
117
  return refuse(file, 'unresolved-reference', { location: pointer });
121
118
  }
122
119
  const body = bodyAfterFrontmatter(library[file]);
@@ -127,24 +124,21 @@ export function validate(library, context = { binaryTargets: [] }, model = { typ
127
124
  }
128
125
  for (const { section, to, hrefs } of sectionReferences.get(file)) {
129
126
  for (const href of hrefs) {
130
- if (!reaches(file, href, to, documents, binaryTargets))
127
+ if (!reaches(file, href, to, types, binaryTargets))
131
128
  return refuse(file, 'unresolved-reference', { location: section });
132
129
  }
133
130
  }
134
131
  }
135
132
  const missing = new Map();
136
- for (const file of files) {
137
- const parsed = documents.get(file);
138
- if (parsed === undefined || !parsed.ok)
139
- continue;
140
- const kind = instanceType(parsed.document);
133
+ for (const [file, document] of documents) {
134
+ const kind = instanceType(document);
141
135
  if (kind === null || kind === BUILT_IN_TYPE)
142
136
  continue;
143
137
  const definition = definitions.get(kind);
144
138
  if (definition === undefined)
145
139
  continue;
146
140
  const named = [
147
- ...references(parsed.document, definition),
141
+ ...references(document, definition),
148
142
  ...sectionReferences
149
143
  .get(file)
150
144
  .flatMap(({ to, hrefs }) => hrefs.map((value) => ({ value, to }))),
@@ -155,7 +149,7 @@ export function validate(library, context = { binaryTargets: [] }, model = { typ
155
149
  const resolved = classifyHref(file, value);
156
150
  if (resolved.kind !== 'path')
157
151
  continue;
158
- if (documents.has(resolved.path) || binaryTargets.has(resolved.path))
152
+ if (types.has(resolved.path) || binaryTargets.has(resolved.path))
159
153
  continue;
160
154
  const referrers = missing.get(resolved.path) ?? [];
161
155
  referrers.push(file);
package/dist/yaml.d.ts CHANGED
@@ -32,7 +32,12 @@ export declare function parseYamlMapping(text: string, start: number, end: numbe
32
32
  export declare function jsValue(node: YamlNode): unknown;
33
33
  export declare function mapEntry(map: YamlMap, key: string): YamlEntry | undefined;
34
34
  export declare function isPlainSafe(text: string): boolean;
35
- export declare function serializeJs(value: unknown): string;
35
+ export type FrontmatterValue = string | number | boolean | null | readonly FrontmatterValue[] | {
36
+ readonly [name: string]: FrontmatterValue;
37
+ };
38
+ export declare function plain(value: unknown): value is Record<string, unknown>;
39
+ export declare function frontmatterValue(value: unknown): value is FrontmatterValue;
40
+ export declare function serializeJs(value: FrontmatterValue): string;
36
41
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
37
42
  export declare function serializeKey(name: string): string;
38
43
  export declare function bodyStartAfterYaml(content: string, yamlEnd: number): number;
@@ -1 +1 @@
1
- {"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"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"}
package/dist/yaml.js CHANGED
@@ -418,24 +418,42 @@ export function isPlainSafe(text) {
418
418
  return false;
419
419
  return true;
420
420
  }
421
+ export function plain(value) {
422
+ if (!isRecord(value))
423
+ return false;
424
+ const prototype = Object.getPrototypeOf(value);
425
+ return prototype === Object.prototype || prototype === null;
426
+ }
427
+ function listed(value) {
428
+ const keys = Object.keys(value);
429
+ return keys.length === value.length && keys.every((key, index) => key === String(index));
430
+ }
431
+ function heldWithin(value, within) {
432
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
433
+ return true;
434
+ if (typeof value === 'number')
435
+ return Number.isFinite(value);
436
+ if (typeof value !== 'object' || within.includes(value))
437
+ return false;
438
+ const path = [...within, value];
439
+ const held = (item) => heldWithin(item, path);
440
+ if (Array.isArray(value))
441
+ return listed(value) && value.every(held);
442
+ return plain(value) && Object.values(value).every(held);
443
+ }
444
+ export function frontmatterValue(value) {
445
+ return heldWithin(value, []);
446
+ }
421
447
  export function serializeJs(value) {
422
- if (value === null)
423
- return 'null';
424
- if (value === true)
425
- return 'true';
426
- if (value === false)
427
- return 'false';
428
- if (typeof value === 'number' && Number.isFinite(value))
429
- return JSON.stringify(value);
430
448
  if (typeof value === 'string')
431
449
  return isPlainSafe(value) ? value : JSON.stringify(value);
450
+ if (value === null || typeof value !== 'object')
451
+ return JSON.stringify(value);
432
452
  if (Array.isArray(value))
433
453
  return `[${value.map(serializeJs).join(', ')}]`;
434
- if (isRecord(value))
435
- return `{${Object.entries(value)
436
- .map(([key, held]) => `${serializeKey(key)}: ${serializeJs(held)}`)
437
- .join(', ')}}`;
438
- throw new YamlError(0);
454
+ return `{${Object.entries(value)
455
+ .map(([key, held]) => `${serializeKey(key)}: ${serializeJs(held)}`)
456
+ .join(', ')}}`;
439
457
  }
440
458
  export function isRecord(value) {
441
459
  return value !== null && typeof value === 'object' && !Array.isArray(value);
@@ -485,7 +503,8 @@ export function equalValue(left, right) {
485
503
  if (left === right)
486
504
  return true;
487
505
  if (Array.isArray(left) && Array.isArray(right)) {
488
- return (left.length === right.length && left.every((item, index) => equalValue(item, right[index])));
506
+ return (left.length === right.length &&
507
+ Array.from(left).every((item, index) => equalValue(item, right[index])));
489
508
  }
490
509
  if (isRecord(left) && isRecord(right)) {
491
510
  const keys = Object.keys(left);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentshouse/mdmodel",
3
- "version": "0.1.0-c3d58cb8652e6",
3
+ "version": "0.1.0-c4fe1bc82bc55",
4
4
  "description": "MD Type language, parser, validator, structured change application, Markdown syntax profile, and conformance fixtures",
5
5
  "license": "MIT",
6
6
  "type": "module",