@agentshouse/mdmodel 0.1.0-c4fe1bc82bc55 → 0.1.0-c520180b7a33f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/API.md +264 -250
  2. package/README.md +21 -22
  3. package/dist/blocks.d.ts.map +1 -1
  4. package/dist/blocks.js +35 -20
  5. package/dist/definition.d.ts +17 -1
  6. package/dist/definition.d.ts.map +1 -1
  7. package/dist/definition.js +321 -45
  8. package/dist/divide.d.ts.map +1 -1
  9. package/dist/divide.js +27 -17
  10. package/dist/document.d.ts +6 -3
  11. package/dist/document.d.ts.map +1 -1
  12. package/dist/document.js +326 -171
  13. package/dist/event.d.ts +78 -0
  14. package/dist/event.d.ts.map +1 -0
  15. package/dist/event.js +230 -0
  16. package/dist/fields.d.ts +2 -0
  17. package/dist/fields.d.ts.map +1 -1
  18. package/dist/fields.js +7 -0
  19. package/dist/index.d.ts +24 -10
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +14 -7
  22. package/dist/kinds.d.ts +19 -0
  23. package/dist/kinds.d.ts.map +1 -0
  24. package/dist/kinds.js +161 -0
  25. package/dist/links.d.ts +3 -0
  26. package/dist/links.d.ts.map +1 -1
  27. package/dist/links.js +108 -51
  28. package/dist/paths.d.ts +10 -1
  29. package/dist/paths.d.ts.map +1 -1
  30. package/dist/paths.js +118 -12
  31. package/dist/pattern.d.ts +10 -0
  32. package/dist/pattern.d.ts.map +1 -0
  33. package/dist/pattern.js +355 -0
  34. package/dist/project.d.ts +1 -0
  35. package/dist/project.d.ts.map +1 -1
  36. package/dist/project.js +38 -15
  37. package/dist/query/language.d.ts +223 -0
  38. package/dist/query/language.d.ts.map +1 -0
  39. package/dist/query/language.js +565 -0
  40. package/dist/query/match.d.ts +14 -0
  41. package/dist/query/match.d.ts.map +1 -0
  42. package/dist/query/match.js +121 -0
  43. package/dist/query/rows.d.ts +32 -0
  44. package/dist/query/rows.d.ts.map +1 -0
  45. package/dist/query/rows.js +161 -0
  46. package/dist/query/sql.d.ts +39 -0
  47. package/dist/query/sql.d.ts.map +1 -0
  48. package/dist/query/sql.js +279 -0
  49. package/dist/references.d.ts +2 -2
  50. package/dist/references.d.ts.map +1 -1
  51. package/dist/references.js +6 -1
  52. package/dist/reserved.d.ts +5 -0
  53. package/dist/reserved.d.ts.map +1 -0
  54. package/dist/reserved.js +20 -0
  55. package/dist/schema.d.ts +1 -0
  56. package/dist/schema.d.ts.map +1 -1
  57. package/dist/schema.js +57 -6
  58. package/dist/types.d.ts +57 -2
  59. package/dist/types.d.ts.map +1 -1
  60. package/dist/validate.d.ts +31 -2
  61. package/dist/validate.d.ts.map +1 -1
  62. package/dist/validate.js +400 -115
  63. package/dist/yaml.d.ts +1 -2
  64. package/dist/yaml.d.ts.map +1 -1
  65. package/dist/yaml.js +75 -32
  66. package/fixtures/README.md +27 -7
  67. package/fixtures/cases/conditional-section/context.json +1 -0
  68. package/fixtures/cases/conditional-section/expected.json +6 -0
  69. package/fixtures/cases/conditional-section/library/questions/hosting.md +9 -0
  70. package/fixtures/cases/conditional-section/library/questions/payments.md +12 -0
  71. package/fixtures/cases/conditional-section/schema.yaml +14 -0
  72. package/fixtures/cases/cross-room-link/context.json +1 -0
  73. package/fixtures/cases/cross-room-link/expected.json +1 -0
  74. package/fixtures/cases/cross-room-link/library/clients/acme.md +6 -0
  75. package/fixtures/cases/cross-room-link/schema.yaml +3 -0
  76. package/fixtures/cases/cross-room-reference/context.json +1 -0
  77. package/fixtures/cases/cross-room-reference/expected.json +1 -0
  78. package/fixtures/cases/cross-room-reference/library/clients/acme.md +9 -0
  79. package/fixtures/cases/cross-room-reference/schema.yaml +9 -0
  80. package/fixtures/cases/link-into-a-reserved-name/context.json +1 -0
  81. package/fixtures/cases/link-into-a-reserved-name/expected.json +5 -0
  82. package/fixtures/cases/link-into-a-reserved-name/library/notes/a.md +6 -0
  83. package/fixtures/cases/link-into-a-reserved-name/schema.yaml +3 -0
  84. package/fixtures/cases/link-into-a-reserved-name-from-an-untyped-document/context.json +1 -0
  85. package/fixtures/cases/link-into-a-reserved-name-from-an-untyped-document/expected.json +5 -0
  86. package/fixtures/cases/link-into-a-reserved-name-from-an-untyped-document/library/notes/b.md +5 -0
  87. package/fixtures/cases/member-on-an-untyped-document/context.json +1 -0
  88. package/fixtures/cases/member-on-an-untyped-document/expected.json +6 -0
  89. package/fixtures/cases/member-on-an-untyped-document/library/note.md +4 -0
  90. package/fixtures/cases/member-on-another-type/context.json +1 -0
  91. package/fixtures/cases/member-on-another-type/expected.json +6 -0
  92. package/fixtures/cases/member-on-another-type/library/note.md +4 -0
  93. package/fixtures/cases/member-on-another-type/schema.yaml +7 -0
  94. package/fixtures/cases/reference-into-a-reserved-name/context.json +1 -0
  95. package/fixtures/cases/reference-into-a-reserved-name/expected.json +6 -0
  96. package/fixtures/cases/reference-into-a-reserved-name/library/notes/a.md +4 -0
  97. package/fixtures/cases/reference-into-a-reserved-name/library/settings/brief.md +1 -0
  98. package/fixtures/cases/reference-into-a-reserved-name/schema.yaml +3 -0
  99. package/fixtures/cases/room-md-declares-a-type/context.json +1 -0
  100. package/fixtures/cases/room-md-declares-a-type/expected.json +6 -0
  101. package/fixtures/cases/room-md-declares-a-type/library/ROOM.md +5 -0
  102. package/fixtures/cases/typed-path-names-another-type/context.json +11 -0
  103. package/fixtures/cases/typed-path-names-another-type/expected.json +6 -0
  104. package/fixtures/cases/typed-path-names-another-type/library/settings/prefs/one.md +3 -0
  105. package/fixtures/cases/typed-path-names-another-type/schema.yaml +6 -0
  106. package/fixtures/cases/typed-path-names-its-type/context.json +11 -0
  107. package/fixtures/cases/typed-path-names-its-type/expected.json +3 -0
  108. package/fixtures/cases/typed-path-names-its-type/library/settings/prefs/deeper/two.md +1 -0
  109. package/fixtures/cases/typed-path-names-its-type/library/settings/prefs/one.md +4 -0
  110. package/fixtures/cases/typed-path-names-its-type/schema.yaml +6 -0
  111. package/fixtures/cases/typed-path-names-no-type/context.json +11 -0
  112. package/fixtures/cases/typed-path-names-no-type/expected.json +6 -0
  113. package/fixtures/cases/typed-path-names-no-type/library/settings/prefs/one.md +1 -0
  114. package/fixtures/cases/typed-path-names-no-type/schema.yaml +6 -0
  115. package/fixtures/cases/unnamed-typed-path-checks-its-fields/context.json +11 -0
  116. package/fixtures/cases/unnamed-typed-path-checks-its-fields/expected.json +6 -0
  117. package/fixtures/cases/unnamed-typed-path-checks-its-fields/library/rooms/team/tasks/plan.md +4 -0
  118. package/fixtures/cases/unnamed-typed-path-checks-its-fields/schema.yaml +5 -0
  119. package/fixtures/cases/unnamed-typed-path-names-a-type/context.json +11 -0
  120. package/fixtures/cases/unnamed-typed-path-names-a-type/expected.json +6 -0
  121. package/fixtures/cases/unnamed-typed-path-names-a-type/library/rooms/team/tasks/plan.md +6 -0
  122. package/fixtures/cases/unnamed-typed-path-names-a-type/schema.yaml +5 -0
  123. package/fixtures/cases/unnamed-typed-path-reads-its-type/context.json +11 -0
  124. package/fixtures/cases/unnamed-typed-path-reads-its-type/expected.json +3 -0
  125. package/fixtures/cases/unnamed-typed-path-reads-its-type/library/rooms/team/plan.md +1 -0
  126. package/fixtures/cases/unnamed-typed-path-reads-its-type/library/rooms/team/tasks/plan.md +5 -0
  127. package/fixtures/cases/unnamed-typed-path-reads-its-type/schema.yaml +5 -0
  128. package/fixtures/cases/unnamed-typed-path-without-a-body/context.json +11 -0
  129. package/fixtures/cases/unnamed-typed-path-without-a-body/expected.json +5 -0
  130. package/fixtures/cases/unnamed-typed-path-without-a-body/library/rooms/team/tasks/plan.md +5 -0
  131. package/fixtures/cases/unnamed-typed-path-without-a-body/schema.yaml +5 -0
  132. package/fixtures/division.json +26 -26
  133. package/fixtures/queries.json +913 -0
  134. package/package.json +10 -3
  135. package/dist/condition.d.ts +0 -149
  136. package/dist/condition.d.ts.map +0 -1
  137. package/dist/condition.js +0 -491
package/dist/yaml.js CHANGED
@@ -6,6 +6,18 @@ export class YamlError extends Error {
6
6
  this.name = 'YamlError';
7
7
  }
8
8
  }
9
+ const YAML_DEPTH_MAX = 64;
10
+ function nested(c, parse) {
11
+ if (c.depth >= YAML_DEPTH_MAX)
12
+ throw new YamlError(c.i);
13
+ c.depth += 1;
14
+ try {
15
+ return parse();
16
+ }
17
+ finally {
18
+ c.depth -= 1;
19
+ }
20
+ }
9
21
  function peek(c) {
10
22
  return c.i < c.end ? c.text[c.i] : '';
11
23
  }
@@ -70,7 +82,10 @@ function indentAt(c) {
70
82
  }
71
83
  return n;
72
84
  }
85
+ const UNHELD_TEXT = /[\0\ud800-\udfff]/u;
73
86
  function scalar(value, start, end) {
87
+ if (typeof value === 'string' && UNHELD_TEXT.test(value))
88
+ throw new YamlError(start);
74
89
  return { kind: 'scalar', value, start, end };
75
90
  }
76
91
  export function interpretPlain(text) {
@@ -84,6 +99,30 @@ export function interpretPlain(text) {
84
99
  return Number(text);
85
100
  return text;
86
101
  }
102
+ const ESCAPES = {
103
+ b: '\b',
104
+ f: '\f',
105
+ n: '\n',
106
+ r: '\r',
107
+ t: '\t',
108
+ '"': '"',
109
+ '/': '/',
110
+ '\\': '\\',
111
+ };
112
+ function parseEscape(c) {
113
+ c.i += 1;
114
+ const escaped = peek(c);
115
+ const held = ESCAPES[escaped];
116
+ if (held !== undefined) {
117
+ c.i += 1;
118
+ return held;
119
+ }
120
+ const hex = c.text.slice(c.i + 1, c.i + 5);
121
+ if (escaped !== 'u' || c.i + 5 > c.end || !/^[0-9A-Fa-f]{4}$/.test(hex))
122
+ throw new YamlError(c.i);
123
+ c.i += 5;
124
+ return String.fromCharCode(Number.parseInt(hex, 16));
125
+ }
87
126
  function parseQuoted(c) {
88
127
  const quote = peek(c);
89
128
  const start = c.i;
@@ -91,31 +130,19 @@ function parseQuoted(c) {
91
130
  let out = '';
92
131
  while (c.i < c.end) {
93
132
  const ch = peek(c);
133
+ if (quote === "'" && ch === "'" && c.i + 1 < c.end && c.text[c.i + 1] === "'") {
134
+ out += "'";
135
+ c.i += 2;
136
+ continue;
137
+ }
94
138
  if (ch === quote) {
95
139
  c.i += 1;
96
140
  return scalar(out, start, c.i);
97
141
  }
98
142
  if (ch === '\n' || ch === '\r')
99
143
  throw new YamlError(c.i);
100
- if (quote === "'" && ch === "'" && c.text[c.i + 1] === "'") {
101
- out += "'";
102
- c.i += 2;
103
- continue;
104
- }
105
144
  if (quote === '"' && ch === '\\') {
106
- c.i += 1;
107
- const escaped = peek(c);
108
- if (escaped === 'n')
109
- out += '\n';
110
- else if (escaped === 't')
111
- out += '\t';
112
- else if (escaped === '"')
113
- out += '"';
114
- else if (escaped === '\\')
115
- out += '\\';
116
- else
117
- throw new YamlError(c.i);
118
- c.i += 1;
145
+ out += parseEscape(c);
119
146
  continue;
120
147
  }
121
148
  out += ch;
@@ -190,6 +217,9 @@ function parseFlowValue(c) {
190
217
  return parseScalar(c, true);
191
218
  }
192
219
  function parseFlowMap(c) {
220
+ return nested(c, () => flowMap(c));
221
+ }
222
+ function flowMap(c) {
193
223
  const start = c.i;
194
224
  if (peek(c) !== '{')
195
225
  throw new YamlError(c.i);
@@ -208,11 +238,12 @@ function parseFlowMap(c) {
208
238
  if (peek(c) !== ':')
209
239
  throw new YamlError(c.i);
210
240
  c.i += 1;
241
+ const after = c.i;
211
242
  const value = parseFlowValue(c);
212
243
  if (seen.has(key.name))
213
244
  throw new YamlError(key.start);
214
245
  seen.add(key.name);
215
- entries.push({ key: key.name, keyStart: key.start, keyEnd: key.end, value });
246
+ entries.push({ key: key.name, after, value });
216
247
  skipFlowSpace(c);
217
248
  if (peek(c) === ',') {
218
249
  c.i += 1;
@@ -227,6 +258,9 @@ function parseFlowMap(c) {
227
258
  throw new YamlError(c.i);
228
259
  }
229
260
  function parseFlowSeq(c) {
261
+ return nested(c, () => flowSeq(c));
262
+ }
263
+ function flowSeq(c) {
230
264
  const start = c.i;
231
265
  if (peek(c) !== '[')
232
266
  throw new YamlError(c.i);
@@ -254,6 +288,7 @@ function parseFlowSeq(c) {
254
288
  throw new YamlError(c.i);
255
289
  }
256
290
  function parseValue(c, parentKeyIndent) {
291
+ const at = c.i;
257
292
  skipSpaces(c);
258
293
  if (peek(c) === '#')
259
294
  skipToEol(c);
@@ -262,12 +297,12 @@ function parseValue(c, parentKeyIndent) {
262
297
  skipEol(c);
263
298
  skipBlankAndComments(c);
264
299
  if (c.i >= c.end)
265
- return scalar(null, c.i, c.i);
300
+ return scalar(null, at, at);
266
301
  const nextIndent = indentAt(c);
267
302
  if (nextIndent === parentKeyIndent && seqAhead(c))
268
303
  return parseBlockSeq(c, nextIndent);
269
304
  if (nextIndent <= parentKeyIndent)
270
- return scalar(null, c.i, c.i);
305
+ return scalar(null, at, at);
271
306
  if (peek(c) === '-')
272
307
  return parseBlockSeq(c, nextIndent);
273
308
  if (peek(c) === '[')
@@ -315,9 +350,6 @@ function lineStartOf(c) {
315
350
  j -= 1;
316
351
  return j;
317
352
  }
318
- function valueEnd(value, marked) {
319
- return value.kind === 'scalar' && value.start === value.end ? marked : value.end;
320
- }
321
353
  function parseSeqItem(c, indent) {
322
354
  skipSpaces(c);
323
355
  if (peek(c) !== '#' && peek(c) !== '\n' && peek(c) !== '\r' && c.i < c.end && mappingAhead(c))
@@ -325,6 +357,9 @@ function parseSeqItem(c, indent) {
325
357
  return parseValue(c, indent);
326
358
  }
327
359
  function parseBlockSeq(c, indent) {
360
+ return nested(c, () => blockSeq(c, indent));
361
+ }
362
+ function blockSeq(c, indent) {
328
363
  const start = c.i;
329
364
  const items = [];
330
365
  let end = start;
@@ -337,14 +372,16 @@ function parseBlockSeq(c, indent) {
337
372
  if (peek(c) !== '-')
338
373
  break;
339
374
  c.i += 1;
340
- const marked = c.i;
341
375
  const item = parseSeqItem(c, indent);
342
376
  items.push(item);
343
- end = valueEnd(item, marked);
377
+ end = item.end;
344
378
  }
345
379
  return { kind: 'seq', items, start, end };
346
380
  }
347
381
  function parseBlockMap(c, indent, inline = false) {
382
+ return nested(c, () => blockMap(c, indent, inline));
383
+ }
384
+ function blockMap(c, indent, inline) {
348
385
  const start = c.i;
349
386
  const entries = [];
350
387
  const seen = new Set();
@@ -366,18 +403,18 @@ function parseBlockMap(c, indent, inline = false) {
366
403
  if (peek(c) !== ':')
367
404
  throw new YamlError(c.i);
368
405
  c.i += 1;
369
- const marked = c.i;
406
+ const after = c.i;
370
407
  const value = parseValue(c, indent);
371
408
  if (seen.has(key.name))
372
409
  throw new YamlError(key.start);
373
410
  seen.add(key.name);
374
- entries.push({ key: key.name, keyStart: key.start, keyEnd: key.end, value });
375
- end = valueEnd(value, marked);
411
+ entries.push({ key: key.name, after, value });
412
+ end = value.end;
376
413
  }
377
414
  return { kind: 'map', entries, start, end };
378
415
  }
379
416
  export function parseYamlMapping(text, start, end) {
380
- const c = { text, i: start, end };
417
+ const c = { text, i: start, end, depth: 0 };
381
418
  skipBlankAndComments(c);
382
419
  if (c.i >= end)
383
420
  return { kind: 'map', entries: [], start, end };
@@ -429,17 +466,23 @@ function listed(value) {
429
466
  return keys.length === value.length && keys.every((key, index) => key === String(index));
430
467
  }
431
468
  function heldWithin(value, within) {
432
- if (value === null || typeof value === 'string' || typeof value === 'boolean')
469
+ if (typeof value === 'string')
470
+ return !UNHELD_TEXT.test(value);
471
+ if (value === null || typeof value === 'boolean')
433
472
  return true;
434
473
  if (typeof value === 'number')
435
474
  return Number.isFinite(value);
436
475
  if (typeof value !== 'object' || within.includes(value))
437
476
  return false;
477
+ if (within.length + 1 >= YAML_DEPTH_MAX)
478
+ return false;
438
479
  const path = [...within, value];
439
480
  const held = (item) => heldWithin(item, path);
440
481
  if (Array.isArray(value))
441
482
  return listed(value) && value.every(held);
442
- return plain(value) && Object.values(value).every(held);
483
+ return (plain(value) &&
484
+ Object.keys(value).every((key) => !UNHELD_TEXT.test(key)) &&
485
+ Object.values(value).every(held));
443
486
  }
444
487
  export function frontmatterValue(value) {
445
488
  return heldWithin(value, []);
@@ -51,8 +51,8 @@ change to a value that is not prose leaves the projection alone.
51
51
 
52
52
  `division.json` exercises the public `divide` seam separately from the
53
53
  validation Libraries. It carries `schema` and `cases` like `projection.json`,
54
- and each case adds the `budget` the division runs under. Parse the source, call
55
- `divide(document, file, context)` with `{ documentTargets, definition, budget }`,
54
+ and each case adds the `bound` the division runs under. Parse the source, call
55
+ `divide(document, file, context)` with `{ documentTargets, definition, bound }`,
56
56
  and compare against `expected`: either `{ "ok": true, "spans": [...] }`, where
57
57
  each span carries the exact `text` to embed and the exact `source` the returned
58
58
  `start` and `end` address in that case's source, or `{ "ok": false, "refusal": ... }`. Then
@@ -65,6 +65,19 @@ value one span carries part of. `start` and `end` are UTF-8 byte offsets into th
65
65
  source; every source in this corpus is ASCII, so a consumer compares the
66
66
  addressed `source` with an ordinary string slice.
67
67
 
68
+ ## Queries
69
+
70
+ `queries.json` is the one table of cases both query evaluators answer. It carries `schema`,
71
+ one schema text; `documents`, each named and carrying its `path`, the `type` a collection
72
+ stores for it (`any` for an untyped Markdown Document, `null` for one that is not Markdown),
73
+ its `fileId`, the `text` the device holds or `null`, and its `fields`; and `cases`, each with a
74
+ `name`, a `query` of filter parts, the `document` it names and whether it `matches`. Verify
75
+ the schema and plan `{ ...query, select: {} }` with `planOf` against its types. Then
76
+ `matches(plan, candidate)` over the named Document, given its type's definition, and the
77
+ condition `sql.tests` writes over a collection holding every Document of the table with the
78
+ values `indexed` derives from it must both answer `matches`. A new operator adds its cases
79
+ here first.
80
+
68
81
  ## Verdict format
69
82
 
70
83
  Acceptance:
@@ -107,6 +120,7 @@ schema text. The model's own rules:
107
120
  | `frontmatter-fence` | A present frontmatter fence does not parse as the accepted YAML subset |
108
121
  | `schema-yaml` | A schema text is not a mapping in the accepted YAML subset |
109
122
  | `schema-type-name` | A type name is empty, starts with `$`, or is `any` or `attachment` |
123
+ | `provided-type` | A schema names a type its caller provides with a key but its two role keywords |
110
124
  | `schema` | A type or subschema is neither a mapping nor a boolean |
111
125
  | `schema-keyword` | A schema carries a key that is no JSON Schema 2020-12 keyword the model admits |
112
126
  | `$defs` | `$defs` is not a mapping |
@@ -114,17 +128,23 @@ schema text. The model's own rules:
114
128
  | `reference` | `reference` is not on a string or names something but a type, `any`, `attachment` |
115
129
  | `sections` | A section is not `{ kind: text }` or `{ kind: list, items }` over one scalar |
116
130
  | `member_document` | The mark is not a boolean, or a second type carries it |
117
- | `unknown-type` | A file declares a type absent from the governing schema |
131
+ | `unknown-type` | A file declares a type absent from the governing schema, or other than its typed path requires it to name |
118
132
  | `undeclared-field` | A closed object carries a key it does not declare |
119
133
  | `required-section` | A required section heading is missing |
134
+ | `conditional-section` | A section its type's `if` branch requires is absent or holds no text |
120
135
  | `unresolved-reference` | A reference at any depth or a section item reaches no member it admits |
121
- | `unresolved-link` | A body link is an absolute path or leaves the collection |
136
+ | `unresolved-link` | A body link is an absolute path, leaves the collection or, from a typed Document at a document path, reaches a reserved name |
137
+ | `room-md-type` | `ROOM.md` declares a type |
138
+ | `required-body` | A file at a typed path that requires a body has a body holding no text |
122
139
  | `structured-section` | A declared list section is not a list of values of its item schema |
123
140
  | `referenced-missing-file` | Remaining files still reference an absent path |
124
141
  | `unwritable-link` | No Markdown destination form can carry a new link destination |
125
- | `division-budget` | A division budget is not a whole number of at least 2 |
142
+ | `division-bound` | A division bound is not a whole number of at least 2 |
143
+
144
+ A `then` or `else` of an `if` on a type, in its `allOf` or in such a branch may hold
145
+ `sections`, naming sections the type declares as the type declares them, else `sections`.
126
146
 
127
- `unwritable-link` is refused by `apply` and `division-budget` by `divide`, not
147
+ `unwritable-link` is refused by `apply` and `division-bound` by `divide`, not
128
148
  by `validate`, so no case under `cases/` carries either.
129
149
 
130
150
  A reference that admits `attachment` reaches any path in the same Library, so
@@ -136,6 +156,6 @@ Library is accepted too, so `unresolved-link` never names it and
136
156
  ## YAML subset
137
157
 
138
158
  Frontmatter and a schema text are each a mapping in a closed YAML subset: block and flow mappings,
139
- block and flow sequences, a block sequence item that opens a mapping, plain and quoted scalars, `true`, `false`, `null`,
159
+ block and flow sequences, a block sequence item that opens a mapping, plain and quoted scalars (a single-quoted scalar doubles its apostrophe, a double-quoted one takes JSON's escapes), `true`, `false`, `null`,
140
160
  and decimal numbers. It does not take YAML 1.1 boolean or timestamp aliases,
141
161
  octal numbers, anchors, tags, or block scalars. A mapping carries each key once.
@@ -0,0 +1 @@
1
+ { "binaryTargets": [] }
@@ -0,0 +1,6 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "questions/payments.md",
4
+ "location": "Answer",
5
+ "rule": "conditional-section"
6
+ }
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: question
3
+ title: Where does it run
4
+ status: open
5
+ ---
6
+
7
+ ## Question
8
+
9
+ Which host runs the shop?
@@ -0,0 +1,12 @@
1
+ ---
2
+ type: question
3
+ title: Who takes payments
4
+ status: answered
5
+ ---
6
+
7
+ ## Question
8
+
9
+ Which provider takes card payments?
10
+
11
+ ## Answer
12
+
@@ -0,0 +1,14 @@
1
+ question:
2
+ properties:
3
+ title: { type: string }
4
+ status: { enum: [open, answered, withdrawn] }
5
+ required: [title, status]
6
+ sections:
7
+ Question: { kind: text, required: true }
8
+ Answer: { kind: text }
9
+ if:
10
+ properties:
11
+ status: { enum: [answered, withdrawn] }
12
+ then:
13
+ sections:
14
+ Answer: { kind: text, required: true }
@@ -0,0 +1 @@
1
+ { "binaryTargets": [] }
@@ -0,0 +1 @@
1
+ { "verdict": "accept" }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: client
3
+ name: Acme
4
+ ---
5
+
6
+ Paid by [the March invoice](/rooms/finance/invoices/march.md#total).
@@ -0,0 +1,3 @@
1
+ client:
2
+ properties:
3
+ name: { type: string }
@@ -0,0 +1 @@
1
+ { "binaryTargets": [] }
@@ -0,0 +1 @@
1
+ { "verdict": "accept" }
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: client
3
+ name: Acme
4
+ finance: /rooms/finance/invoices/acme.md
5
+ ---
6
+
7
+ ## Invoices
8
+
9
+ - [March](/rooms/finance/invoices/march.md)
@@ -0,0 +1,9 @@
1
+ client:
2
+ properties:
3
+ name: { type: string }
4
+ finance: { type: string, reference: invoice, cross_room: true }
5
+ sections:
6
+ Invoices: { kind: list, items: { type: string, reference: invoice, cross_room: true } }
7
+ invoice:
8
+ properties:
9
+ name: { type: string }
@@ -0,0 +1 @@
1
+ { "binaryTargets": [] }
@@ -0,0 +1,5 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "notes/a.md",
4
+ "rule": "unresolved-link"
5
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: note
3
+ title: Plan
4
+ ---
5
+
6
+ See [the schema](../settings/schema.yaml).
@@ -0,0 +1,3 @@
1
+ note:
2
+ properties:
3
+ title: { type: string }
@@ -0,0 +1,5 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "notes/b.md",
4
+ "rule": "unresolved-link"
5
+ }
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: any
3
+ ---
4
+
5
+ See [the Room](../Rooms/other/plan.md).
@@ -0,0 +1 @@
1
+ { "binaryTargets": [] }
@@ -0,0 +1,6 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "note.md",
4
+ "location": "/member",
5
+ "rule": "undeclared-field"
6
+ }
@@ -0,0 +1,4 @@
1
+ ---
2
+ member: ana@example.com
3
+ ---
4
+ # Ana
@@ -0,0 +1 @@
1
+ { "binaryTargets": [] }
@@ -0,0 +1,6 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "note.md",
4
+ "location": "/member",
5
+ "rule": "undeclared-field"
6
+ }
@@ -0,0 +1,4 @@
1
+ ---
2
+ type: note
3
+ member: ana@example.com
4
+ ---
@@ -0,0 +1,7 @@
1
+ contact:
2
+ member_document: true
3
+ properties:
4
+ name: { type: string }
5
+ note:
6
+ properties:
7
+ member: { type: string }
@@ -0,0 +1 @@
1
+ { "binaryTargets": [] }
@@ -0,0 +1,6 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "notes/a.md",
4
+ "rule": "unresolved-reference",
5
+ "location": "/brief"
6
+ }
@@ -0,0 +1,4 @@
1
+ ---
2
+ type: task
3
+ brief: ../settings/brief.md
4
+ ---
@@ -0,0 +1,3 @@
1
+ task:
2
+ properties:
3
+ brief: { type: string, reference: any }
@@ -0,0 +1 @@
1
+ { "binaryTargets": [] }
@@ -0,0 +1,6 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "ROOM.md",
4
+ "location": "/type",
5
+ "rule": "room-md-type"
6
+ }
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: any
3
+ ---
4
+
5
+ # Research
@@ -0,0 +1,11 @@
1
+ {
2
+ "binaryTargets": [],
3
+ "typedPaths": [
4
+ {
5
+ "path": "settings/prefs/*.md",
6
+ "type": "prefs",
7
+ "named": true,
8
+ "body": false
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "settings/prefs/one.md",
4
+ "rule": "unknown-type",
5
+ "location": "/type"
6
+ }
@@ -0,0 +1,6 @@
1
+ prefs:
2
+ properties:
3
+ theme: { type: string }
4
+ note:
5
+ properties:
6
+ title: { type: string }
@@ -0,0 +1,11 @@
1
+ {
2
+ "binaryTargets": [],
3
+ "typedPaths": [
4
+ {
5
+ "path": "settings/prefs/*.md",
6
+ "type": "prefs",
7
+ "named": true,
8
+ "body": false
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "verdict": "accept"
3
+ }
@@ -0,0 +1,4 @@
1
+ ---
2
+ type: prefs
3
+ theme: dark
4
+ ---
@@ -0,0 +1,6 @@
1
+ prefs:
2
+ properties:
3
+ theme: { type: string }
4
+ note:
5
+ properties:
6
+ title: { type: string }
@@ -0,0 +1,11 @@
1
+ {
2
+ "binaryTargets": [],
3
+ "typedPaths": [
4
+ {
5
+ "path": "settings/prefs/*.md",
6
+ "type": "prefs",
7
+ "named": true,
8
+ "body": false
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "verdict": "refuse",
3
+ "file": "settings/prefs/one.md",
4
+ "rule": "unknown-type",
5
+ "location": "/type"
6
+ }
@@ -0,0 +1,6 @@
1
+ prefs:
2
+ properties:
3
+ theme: { type: string }
4
+ note:
5
+ properties:
6
+ title: { type: string }
@@ -0,0 +1,11 @@
1
+ {
2
+ "binaryTargets": [],
3
+ "typedPaths": [
4
+ {
5
+ "path": "rooms/*/tasks/*.md",
6
+ "type": "task",
7
+ "named": false,
8
+ "body": true
9
+ }
10
+ ]
11
+ }