@agentshouse/mdmodel 0.1.0-c83456e1cebfb → 0.1.0-cabd61587647f

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 (295) hide show
  1. package/API.md +242 -181
  2. package/README.md +17 -18
  3. package/dist/blocks.d.ts.map +1 -1
  4. package/dist/blocks.js +33 -26
  5. package/dist/condition.d.ts +149 -0
  6. package/dist/condition.d.ts.map +1 -0
  7. package/dist/condition.js +500 -0
  8. package/dist/definition.d.ts +62 -24
  9. package/dist/definition.d.ts.map +1 -1
  10. package/dist/definition.js +703 -138
  11. package/dist/divide.d.ts.map +1 -1
  12. package/dist/divide.js +18 -8
  13. package/dist/document.d.ts +10 -2
  14. package/dist/document.d.ts.map +1 -1
  15. package/dist/document.js +370 -114
  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 +14 -6
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +9 -4
  22. package/dist/links.d.ts +2 -0
  23. package/dist/links.d.ts.map +1 -1
  24. package/dist/links.js +23 -12
  25. package/dist/paths.d.ts +4 -0
  26. package/dist/paths.d.ts.map +1 -1
  27. package/dist/paths.js +110 -10
  28. package/dist/project.d.ts +1 -0
  29. package/dist/project.d.ts.map +1 -1
  30. package/dist/project.js +52 -30
  31. package/dist/references.d.ts +4 -0
  32. package/dist/references.d.ts.map +1 -0
  33. package/dist/references.js +25 -0
  34. package/dist/schema.d.ts +7 -6
  35. package/dist/schema.d.ts.map +1 -1
  36. package/dist/schema.js +157 -31
  37. package/dist/types.d.ts +43 -1
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/validate.d.ts +6 -1
  40. package/dist/validate.d.ts.map +1 -1
  41. package/dist/validate.js +167 -144
  42. package/dist/yaml.d.ts +8 -3
  43. package/dist/yaml.d.ts.map +1 -1
  44. package/dist/yaml.js +133 -43
  45. package/fixtures/README.md +49 -38
  46. package/fixtures/cases/absent-link-dangles/context.json +1 -0
  47. package/fixtures/cases/absent-link-dangles/expected.json +1 -0
  48. package/fixtures/cases/absent-link-dangles/library/item.md +8 -0
  49. package/fixtures/cases/absent-link-dangles/schema.yaml +6 -0
  50. package/fixtures/cases/absent-optional-field/context.json +1 -0
  51. package/fixtures/cases/absent-optional-field/expected.json +1 -0
  52. package/fixtures/cases/absent-optional-field/library/companies/acme.md +4 -0
  53. package/fixtures/cases/absent-optional-field/library/deals/lead.md +6 -0
  54. package/fixtures/cases/absent-optional-field/schema.yaml +56 -0
  55. package/fixtures/cases/absolute-link/context.json +1 -0
  56. package/fixtures/cases/{missing-binary-image → absolute-link}/expected.json +1 -1
  57. package/fixtures/cases/absolute-link/library/item.md +8 -0
  58. package/fixtures/cases/absolute-link/schema.yaml +6 -0
  59. package/fixtures/cases/attachment-reference-any-file/context.json +1 -0
  60. package/fixtures/cases/attachment-reference-any-file/expected.json +1 -0
  61. package/fixtures/cases/attachment-reference-any-file/library/companies/acme.md +4 -0
  62. package/fixtures/cases/attachment-reference-any-file/library/deals/renewal.md +15 -0
  63. package/fixtures/cases/attachment-reference-any-file/library/places/depot.md +4 -0
  64. package/fixtures/cases/attachment-reference-any-file/library/products/seats.md +4 -0
  65. package/fixtures/cases/attachment-reference-any-file/library/products/support.md +4 -0
  66. package/fixtures/cases/attachment-reference-any-file/schema.yaml +32 -0
  67. package/fixtures/cases/attachment-reference-dangles/context.json +1 -0
  68. package/fixtures/cases/attachment-reference-dangles/expected.json +1 -0
  69. package/fixtures/cases/attachment-reference-dangles/library/companies/acme.md +4 -0
  70. package/fixtures/cases/attachment-reference-dangles/library/deals/renewal.md +15 -0
  71. package/fixtures/cases/attachment-reference-dangles/library/places/depot.md +4 -0
  72. package/fixtures/cases/attachment-reference-dangles/library/products/seats.md +4 -0
  73. package/fixtures/cases/attachment-reference-dangles/library/products/support.md +4 -0
  74. package/fixtures/cases/attachment-reference-dangles/schema.yaml +32 -0
  75. package/fixtures/cases/attachment-reference-outside/context.json +1 -0
  76. package/fixtures/cases/attachment-reference-outside/expected.json +6 -0
  77. package/fixtures/cases/attachment-reference-outside/library/companies/acme.md +4 -0
  78. package/fixtures/cases/attachment-reference-outside/library/deals/renewal.md +15 -0
  79. package/fixtures/cases/attachment-reference-outside/library/places/depot.md +4 -0
  80. package/fixtures/cases/attachment-reference-outside/library/products/seats.md +4 -0
  81. package/fixtures/cases/attachment-reference-outside/library/products/support.md +4 -0
  82. package/fixtures/cases/attachment-reference-outside/schema.yaml +32 -0
  83. package/fixtures/cases/binary-any-reference/expected.json +1 -1
  84. package/fixtures/cases/binary-any-reference/schema.yaml +4 -4
  85. package/fixtures/cases/binary-document-collision/schema.yaml +1 -2
  86. package/fixtures/cases/binary-image-dangles/expected.json +1 -0
  87. package/fixtures/cases/binary-image-dangles/schema.yaml +1 -0
  88. package/fixtures/cases/binary-link-dangles/expected.json +1 -0
  89. package/fixtures/cases/binary-link-dangles/schema.yaml +1 -0
  90. package/fixtures/cases/binary-link-outside-collection/schema.yaml +1 -2
  91. package/fixtures/cases/binary-prototype-reference/expected.json +1 -1
  92. package/fixtures/cases/binary-prototype-reference/schema.yaml +4 -4
  93. package/fixtures/cases/binary-typed-reference/expected.json +1 -1
  94. package/fixtures/cases/binary-typed-reference/schema.yaml +5 -5
  95. package/fixtures/cases/boolean-field/context.json +1 -0
  96. package/fixtures/cases/boolean-field/expected.json +6 -0
  97. package/fixtures/cases/boolean-field/library/companies/acme.md +4 -0
  98. package/fixtures/cases/boolean-field/library/deals/renewal.md +31 -0
  99. package/fixtures/cases/boolean-field/schema.yaml +56 -0
  100. package/fixtures/cases/bracketed-link-definition/schema.yaml +6 -6
  101. package/fixtures/cases/closed-nested-object/context.json +1 -0
  102. package/fixtures/cases/closed-nested-object/expected.json +6 -0
  103. package/fixtures/cases/closed-nested-object/library/companies/acme.md +4 -0
  104. package/fixtures/cases/closed-nested-object/library/deals/renewal.md +32 -0
  105. package/fixtures/cases/closed-nested-object/schema.yaml +56 -0
  106. package/fixtures/cases/composed-root-reference/context.json +1 -0
  107. package/fixtures/cases/composed-root-reference/expected.json +6 -0
  108. package/fixtures/cases/composed-root-reference/library/a.md +5 -0
  109. package/fixtures/cases/composed-root-reference/schema.yaml +13 -0
  110. package/fixtures/cases/date-time-format/context.json +1 -0
  111. package/fixtures/cases/date-time-format/expected.json +6 -0
  112. package/fixtures/cases/date-time-format/library/companies/acme.md +4 -0
  113. package/fixtures/cases/date-time-format/library/deals/renewal.md +31 -0
  114. package/fixtures/cases/date-time-format/schema.yaml +56 -0
  115. package/fixtures/cases/declared-binary-links/schema.yaml +1 -2
  116. package/fixtures/cases/default-unfilled/context.json +1 -0
  117. package/fixtures/cases/default-unfilled/expected.json +6 -0
  118. package/fixtures/cases/default-unfilled/library/companies/acme.md +4 -0
  119. package/fixtures/cases/default-unfilled/library/deals/renewal.md +29 -0
  120. package/fixtures/cases/default-unfilled/schema.yaml +56 -0
  121. package/fixtures/cases/defs-pattern/context.json +1 -0
  122. package/fixtures/cases/defs-pattern/expected.json +6 -0
  123. package/fixtures/cases/defs-pattern/library/companies/acme.md +4 -0
  124. package/fixtures/cases/defs-pattern/library/deals/renewal.md +31 -0
  125. package/fixtures/cases/defs-pattern/schema.yaml +56 -0
  126. package/fixtures/cases/dependent-rule/context.json +1 -0
  127. package/fixtures/cases/dependent-rule/expected.json +6 -0
  128. package/fixtures/cases/dependent-rule/library/companies/acme.md +4 -0
  129. package/fixtures/cases/dependent-rule/library/deals/renewal.md +30 -0
  130. package/fixtures/cases/dependent-rule/schema.yaml +56 -0
  131. package/fixtures/cases/duplicate-link-definition/schema.yaml +6 -6
  132. package/fixtures/cases/email-format/context.json +1 -0
  133. package/fixtures/cases/email-format/expected.json +6 -0
  134. package/fixtures/cases/email-format/library/companies/acme.md +4 -0
  135. package/fixtures/cases/email-format/library/deals/renewal.md +31 -0
  136. package/fixtures/cases/email-format/schema.yaml +56 -0
  137. package/fixtures/cases/fenced-link-definition/schema.yaml +6 -6
  138. package/fixtures/cases/field-enum/expected.json +2 -2
  139. package/fixtures/cases/field-enum/schema.yaml +7 -7
  140. package/fixtures/cases/frontmatter-schema/schema.yaml +3 -4
  141. package/fixtures/cases/integer-field/context.json +1 -0
  142. package/fixtures/cases/integer-field/expected.json +6 -0
  143. package/fixtures/cases/integer-field/library/companies/acme.md +4 -0
  144. package/fixtures/cases/integer-field/library/deals/renewal.md +31 -0
  145. package/fixtures/cases/integer-field/schema.yaml +56 -0
  146. package/fixtures/cases/interrupted-link-definition/schema.yaml +1 -2
  147. package/fixtures/cases/json-schema-constructs/context.json +1 -0
  148. package/fixtures/cases/json-schema-constructs/expected.json +1 -0
  149. package/fixtures/cases/json-schema-constructs/library/companies/acme.md +4 -0
  150. package/fixtures/cases/json-schema-constructs/library/deals/renewal.md +31 -0
  151. package/fixtures/cases/json-schema-constructs/schema.yaml +56 -0
  152. package/fixtures/cases/list-of-objects-closed/context.json +1 -0
  153. package/fixtures/cases/list-of-objects-closed/expected.json +6 -0
  154. package/fixtures/cases/list-of-objects-closed/library/companies/acme.md +4 -0
  155. package/fixtures/cases/list-of-objects-closed/library/deals/renewal.md +32 -0
  156. package/fixtures/cases/list-of-objects-closed/schema.yaml +56 -0
  157. package/fixtures/cases/list-of-objects-item/context.json +1 -0
  158. package/fixtures/cases/list-of-objects-item/expected.json +6 -0
  159. package/fixtures/cases/list-of-objects-item/library/companies/acme.md +4 -0
  160. package/fixtures/cases/list-of-objects-item/library/deals/renewal.md +31 -0
  161. package/fixtures/cases/list-of-objects-item/schema.yaml +56 -0
  162. package/fixtures/cases/list-of-objects-reference/context.json +1 -0
  163. package/fixtures/cases/list-of-objects-reference/expected.json +6 -0
  164. package/fixtures/cases/list-of-objects-reference/library/companies/acme.md +4 -0
  165. package/fixtures/cases/list-of-objects-reference/library/deals/renewal.md +14 -0
  166. package/fixtures/cases/list-of-objects-reference/library/places/depot.md +4 -0
  167. package/fixtures/cases/list-of-objects-reference/library/products/seats.md +4 -0
  168. package/fixtures/cases/list-of-objects-reference/library/products/support.md +4 -0
  169. package/fixtures/cases/list-of-objects-reference/schema.yaml +32 -0
  170. package/fixtures/cases/list-size/context.json +1 -0
  171. package/fixtures/cases/list-size/expected.json +6 -0
  172. package/fixtures/cases/list-size/library/companies/acme.md +4 -0
  173. package/fixtures/cases/list-size/library/deals/renewal.md +31 -0
  174. package/fixtures/cases/list-size/schema.yaml +56 -0
  175. package/fixtures/cases/long-fence-link-definition/schema.yaml +1 -2
  176. package/fixtures/cases/malformed-definition/expected.json +2 -2
  177. package/fixtures/cases/malformed-definition/schema.yaml +3 -4
  178. package/fixtures/cases/member-document/schema.yaml +5 -5
  179. package/fixtures/cases/missing-required-field/expected.json +2 -2
  180. package/fixtures/cases/missing-required-field/schema.yaml +7 -7
  181. package/fixtures/cases/missing-section-item-kind/expected.json +2 -2
  182. package/fixtures/cases/missing-section-item-kind/schema.yaml +6 -6
  183. package/fixtures/cases/misspelled-key/context.json +1 -0
  184. package/fixtures/cases/misspelled-key/expected.json +6 -0
  185. package/fixtures/cases/misspelled-key/library/companies/acme.md +4 -0
  186. package/fixtures/cases/misspelled-key/library/deals/renewal.md +32 -0
  187. package/fixtures/cases/misspelled-key/schema.yaml +56 -0
  188. package/fixtures/cases/nested-defs/context.json +1 -0
  189. package/fixtures/cases/nested-defs/expected.json +6 -0
  190. package/fixtures/cases/nested-defs/library/deal.md +6 -0
  191. package/fixtures/cases/nested-defs/schema.yaml +11 -0
  192. package/fixtures/cases/nested-object-reference/context.json +1 -0
  193. package/fixtures/cases/nested-object-reference/expected.json +6 -0
  194. package/fixtures/cases/nested-object-reference/library/companies/acme.md +4 -0
  195. package/fixtures/cases/nested-object-reference/library/deals/renewal.md +14 -0
  196. package/fixtures/cases/nested-object-reference/library/places/depot.md +4 -0
  197. package/fixtures/cases/nested-object-reference/library/products/seats.md +4 -0
  198. package/fixtures/cases/nested-object-reference/library/products/support.md +4 -0
  199. package/fixtures/cases/nested-object-reference/schema.yaml +32 -0
  200. package/fixtures/cases/nested-reference/context.json +1 -0
  201. package/fixtures/cases/nested-reference/expected.json +1 -0
  202. package/fixtures/cases/nested-reference/library/companies/acme.md +4 -0
  203. package/fixtures/cases/nested-reference/library/deals/renewal.md +15 -0
  204. package/fixtures/cases/nested-reference/library/places/depot.md +4 -0
  205. package/fixtures/cases/nested-reference/library/products/seats.md +4 -0
  206. package/fixtures/cases/nested-reference/library/products/support.md +4 -0
  207. package/fixtures/cases/nested-reference/schema.yaml +32 -0
  208. package/fixtures/cases/nested-required-field/context.json +1 -0
  209. package/fixtures/cases/nested-required-field/expected.json +6 -0
  210. package/fixtures/cases/nested-required-field/library/companies/acme.md +4 -0
  211. package/fixtures/cases/nested-required-field/library/deals/renewal.md +30 -0
  212. package/fixtures/cases/nested-required-field/schema.yaml +56 -0
  213. package/fixtures/cases/null-refused/context.json +1 -0
  214. package/fixtures/cases/null-refused/expected.json +6 -0
  215. package/fixtures/cases/null-refused/library/companies/acme.md +4 -0
  216. package/fixtures/cases/null-refused/library/deals/renewal.md +31 -0
  217. package/fixtures/cases/null-refused/schema.yaml +56 -0
  218. package/fixtures/cases/numeric-range/context.json +1 -0
  219. package/fixtures/cases/numeric-range/expected.json +6 -0
  220. package/fixtures/cases/numeric-range/library/companies/acme.md +4 -0
  221. package/fixtures/cases/numeric-range/library/deals/renewal.md +31 -0
  222. package/fixtures/cases/numeric-range/schema.yaml +56 -0
  223. package/fixtures/cases/one-of-variant/context.json +1 -0
  224. package/fixtures/cases/one-of-variant/expected.json +6 -0
  225. package/fixtures/cases/one-of-variant/library/companies/acme.md +4 -0
  226. package/fixtures/cases/one-of-variant/library/deals/renewal.md +31 -0
  227. package/fixtures/cases/one-of-variant/schema.yaml +56 -0
  228. package/fixtures/cases/open-map-value/context.json +1 -0
  229. package/fixtures/cases/open-map-value/expected.json +6 -0
  230. package/fixtures/cases/open-map-value/library/companies/acme.md +4 -0
  231. package/fixtures/cases/open-map-value/library/deals/renewal.md +31 -0
  232. package/fixtures/cases/open-map-value/schema.yaml +56 -0
  233. package/fixtures/cases/other-room-reference/context.json +1 -0
  234. package/fixtures/cases/other-room-reference/expected.json +6 -0
  235. package/fixtures/cases/other-room-reference/library/companies/acme.md +4 -0
  236. package/fixtures/cases/other-room-reference/library/deals/renewal.md +14 -0
  237. package/fixtures/cases/other-room-reference/library/places/depot.md +4 -0
  238. package/fixtures/cases/other-room-reference/library/products/seats.md +4 -0
  239. package/fixtures/cases/other-room-reference/library/products/support.md +4 -0
  240. package/fixtures/cases/other-room-reference/schema.yaml +32 -0
  241. package/fixtures/cases/paragraph-link-definition/schema.yaml +1 -2
  242. package/fixtures/cases/prototype-field/expected.json +1 -1
  243. package/fixtures/cases/prototype-field/schema.yaml +6 -6
  244. package/fixtures/cases/quoted-link-definition/library/notes/draft.md +1 -1
  245. package/fixtures/cases/quoted-link-definition/schema.yaml +1 -2
  246. package/fixtures/cases/referenced-missing-file/schema.yaml +11 -10
  247. package/fixtures/cases/remote-ref/context.json +1 -0
  248. package/fixtures/cases/remote-ref/expected.json +5 -0
  249. package/fixtures/cases/remote-ref/schema.yaml +3 -0
  250. package/fixtures/cases/second-member-document/expected.json +2 -2
  251. package/fixtures/cases/second-member-document/schema.yaml +4 -5
  252. package/fixtures/cases/section-item-enum/schema.yaml +3 -4
  253. package/fixtures/cases/section-item-kind/schema.yaml +3 -4
  254. package/fixtures/cases/section-items/library/page.md +14 -0
  255. package/fixtures/cases/section-items/schema.yaml +10 -8
  256. package/fixtures/cases/section-reference-path/schema.yaml +3 -4
  257. package/fixtures/cases/section-reference-type/schema.yaml +3 -4
  258. package/fixtures/cases/shortcut-reference-link/library/item.md +1 -1
  259. package/fixtures/cases/shortcut-reference-link/schema.yaml +6 -6
  260. package/fixtures/cases/string-length/context.json +1 -0
  261. package/fixtures/cases/string-length/expected.json +6 -0
  262. package/fixtures/cases/string-length/library/companies/acme.md +4 -0
  263. package/fixtures/cases/string-length/library/deals/renewal.md +31 -0
  264. package/fixtures/cases/string-length/schema.yaml +56 -0
  265. package/fixtures/cases/structured-section/schema.yaml +7 -7
  266. package/fixtures/cases/submission-keys/schema.yaml +4 -4
  267. package/fixtures/cases/text-field-kind/expected.json +2 -2
  268. package/fixtures/cases/text-field-kind/schema.yaml +4 -4
  269. package/fixtures/cases/truncated-link-definition/library/notes/draft.md +1 -1
  270. package/fixtures/cases/truncated-link-definition/schema.yaml +1 -2
  271. package/fixtures/cases/types-folder-content/schema.yaml +4 -4
  272. package/fixtures/cases/undeclared-field/expected.json +1 -1
  273. package/fixtures/cases/undeclared-field/schema.yaml +6 -6
  274. package/fixtures/cases/unevaluated-items-closed/context.json +1 -0
  275. package/fixtures/cases/unevaluated-items-closed/expected.json +6 -0
  276. package/fixtures/cases/unevaluated-items-closed/library/trip.md +6 -0
  277. package/fixtures/cases/unevaluated-items-closed/schema.yaml +10 -0
  278. package/fixtures/cases/unknown-type/expected.json +1 -1
  279. package/fixtures/cases/unknown-type/schema.yaml +3 -4
  280. package/fixtures/cases/unlisted-reference-type/expected.json +2 -2
  281. package/fixtures/cases/unlisted-reference-type/schema.yaml +3 -4
  282. package/fixtures/cases/unresolved-link/library/item.md +1 -1
  283. package/fixtures/cases/unresolved-link/schema.yaml +6 -6
  284. package/fixtures/cases/valid-typed-document/schema.yaml +16 -15
  285. package/fixtures/cases/wide-item-fence-link/schema.yaml +1 -2
  286. package/fixtures/division.json +1 -1
  287. package/fixtures/projection.json +33 -1
  288. package/package.json +4 -2
  289. package/fixtures/cases/missing-binary-image/schema.yaml +0 -2
  290. package/fixtures/cases/missing-binary-link/expected.json +0 -5
  291. package/fixtures/cases/missing-binary-link/schema.yaml +0 -2
  292. /package/fixtures/cases/{missing-binary-image → binary-image-dangles}/context.json +0 -0
  293. /package/fixtures/cases/{missing-binary-image → binary-image-dangles}/library/notes/draft.md +0 -0
  294. /package/fixtures/cases/{missing-binary-link → binary-link-dangles}/context.json +0 -0
  295. /package/fixtures/cases/{missing-binary-link → binary-link-dangles}/library/notes/draft.md +0 -0
package/dist/validate.js CHANGED
@@ -1,54 +1,59 @@
1
- import { readSchema } from './definition.js';
1
+ import { ATTACHMENT, BUILT_IN_TYPE, readSchema } from './definition.js';
2
2
  import { parse } from './document.js';
3
- import { MEMBER_FIELD, RECEIVED_FIELD, SITE_FIELD } from './fields.js';
4
3
  import { hrefOccurrences, linkInventory } from './links.js';
5
4
  import { classifyHref } from './paths.js';
5
+ import { references } from './references.js';
6
6
  import { refusal } from './refuse.js';
7
- import { fitsKind, validateFields } from './schema.js';
7
+ import { fitsItem, frontmatterRefusal } from './schema.js';
8
8
  import { headingSpans, listItems } from './sections.js';
9
9
  import { bodyAfterFrontmatter, bodyStartOf } from './yaml.js';
10
- const MEMBER_SPEC = { kind: 'string', required: false };
11
10
  function refuse(file, rule, extra) {
12
11
  return { verdict: 'refuse', ...refusal(file, rule, extra) };
13
12
  }
14
13
  function instanceType(document) {
15
14
  const raw = document.fields.type;
16
15
  if (raw === undefined || raw === null)
17
- return 'any';
16
+ return BUILT_IN_TYPE;
18
17
  if (typeof raw !== 'string' || raw === '')
19
18
  return null;
20
19
  return raw;
21
20
  }
22
- function referenceTargets(spec, value) {
23
- if (spec.kind === 'reference' && typeof value === 'string')
24
- return [value];
25
- if (spec.kind === 'list' && spec.of.kind === 'reference' && Array.isArray(value)) {
26
- return value.filter((item) => typeof item === 'string');
27
- }
28
- return [];
29
- }
30
- function expectedReferenceType(spec) {
31
- if (spec.kind === 'reference')
32
- return spec.to;
33
- if (spec.kind === 'list' && spec.of.kind === 'reference')
34
- return spec.of.to;
35
- return null;
21
+ function reaches(reference, typeOf, binary) {
22
+ if (reference.target === null)
23
+ return false;
24
+ if (reference.to.includes(ATTACHMENT))
25
+ return true;
26
+ if (binary(reference.target))
27
+ return false;
28
+ const held = typeOf(reference.target);
29
+ return held === undefined || reference.to.includes(held);
36
30
  }
37
- function reaches(file, href, to, documents, binaryTargets) {
38
- const resolved = classifyHref(file, href);
39
- if (resolved.kind !== 'path' || binaryTargets.has(resolved.path))
31
+ function missing(reference, typeOf, binary) {
32
+ if (reference.to.includes(ATTACHMENT) || reference.target === null)
40
33
  return false;
41
- const held = documents.get(resolved.path);
42
- return held === undefined || (held.ok && (held.document.type ?? 'any') === to);
34
+ return typeOf(reference.target) === undefined && !binary(reference.target);
35
+ }
36
+ export function resolves(reference, typeOf, binary) {
37
+ return reaches(reference, typeOf, binary) && !missing(reference, typeOf, binary);
43
38
  }
44
- function itemHrefs(content, items) {
45
- const bodyStart = bodyStartOf(content);
46
- const { uses } = linkInventory(content.slice(bodyStart));
39
+ function usesIn(content) {
40
+ let held;
41
+ return () => {
42
+ if (held !== undefined)
43
+ return held;
44
+ const bodyStart = bodyStartOf(content);
45
+ held = linkInventory(content.slice(bodyStart)).uses.map((use) => ({
46
+ ...use,
47
+ start: bodyStart + use.start,
48
+ end: bodyStart + use.end,
49
+ }));
50
+ return held;
51
+ };
52
+ }
53
+ function itemHrefs(content, items, uses) {
47
54
  const hrefs = [];
48
55
  for (const item of items) {
49
- const link = uses.find((use) => bodyStart + use.start === item.start &&
50
- bodyStart + use.end === item.end &&
51
- content[item.start] === '[');
56
+ const link = uses().find((use) => use.start === item.start && use.end === item.end && content[item.start] === '[');
52
57
  if (link === undefined)
53
58
  return null;
54
59
  hrefs.push(link.destination.href);
@@ -65,137 +70,155 @@ export function verify(schema) {
65
70
  ...(read.location === undefined ? {} : { location: read.location }),
66
71
  };
67
72
  }
68
- function declaredFields(definition) {
69
- if (!definition.memberDocument || Object.hasOwn(definition.fields, MEMBER_FIELD))
70
- return definition.fields;
71
- return { ...definition.fields, [MEMBER_FIELD]: MEMBER_SPEC };
73
+ function structure(file, content, document, definition) {
74
+ if (definition === undefined)
75
+ return { refusal: refuse(file, 'unknown-type', { location: '/type' }) };
76
+ const fieldFailure = frontmatterRefusal(definition, document.fields);
77
+ if (fieldFailure !== undefined) {
78
+ return { refusal: refuse(file, fieldFailure.rule, { location: fieldFailure.location }) };
79
+ }
80
+ const spans = headingSpans(content, bodyStartOf(content));
81
+ const uses = usesIn(content);
82
+ const sections = [];
83
+ for (const [name, spec] of Object.entries(definition.sections)) {
84
+ const occurrences = spans.filter((one) => one.name === name);
85
+ if (occurrences.length === 0 && spec.required)
86
+ return { refusal: refuse(file, 'required-section', { location: name }) };
87
+ if (spec.kind !== 'list')
88
+ continue;
89
+ for (const span of occurrences) {
90
+ const items = listItems(content, span.bodyStart, span.bodyEnd);
91
+ if (items === null ||
92
+ items.some((item) => !fitsItem(definition, name, content.slice(item.start, item.end))))
93
+ return { refusal: refuse(file, 'structured-section', { location: name }) };
94
+ if (spec.items.reference === undefined)
95
+ continue;
96
+ const hrefs = itemHrefs(content, items, uses);
97
+ if (hrefs === null)
98
+ return { refusal: refuse(file, 'structured-section', { location: name }) };
99
+ sections.push({ section: name, to: spec.items.reference, hrefs });
100
+ }
101
+ }
102
+ return { sections };
72
103
  }
73
- export function validate(library, context = { binaryTargets: [] }, model = { types: {} }) {
104
+ function linked(file, content) {
105
+ return hrefOccurrences(bodyAfterFrontmatter(content)).every((occurrence) => classifyHref(file, occurrence.href).kind !== 'invalid');
106
+ }
107
+ function reached(file, href, to) {
108
+ const resolved = classifyHref(file, href);
109
+ return { target: resolved.kind === 'path' ? resolved.path : null, to };
110
+ }
111
+ function definitionOf(document, model) {
112
+ const kind = instanceType(document);
113
+ return kind === null || !Object.hasOwn(model.types, kind) ? undefined : model.types[kind];
114
+ }
115
+ export function checkDocument(file, content, model) {
116
+ const parsed = parse(content, file);
117
+ if (!parsed.ok)
118
+ return { ok: false };
119
+ const document = parsed.document;
120
+ const type = document.type ?? BUILT_IN_TYPE;
121
+ if (instanceType(document) === BUILT_IN_TYPE)
122
+ return { ok: true, type, typed: false, references: [] };
123
+ const definition = definitionOf(document, model);
124
+ const read = structure(file, content, document, definition);
125
+ if ('refusal' in read || definition === undefined || !linked(file, content))
126
+ return { ok: false };
127
+ return {
128
+ ok: true,
129
+ type,
130
+ typed: true,
131
+ references: [
132
+ ...references(document, definition).map(({ value, to }) => reached(file, value, to)),
133
+ ...read.sections.flatMap(({ to, hrefs }) => hrefs.map((href) => reached(file, href, to))),
134
+ ],
135
+ };
136
+ }
137
+ export function sectionReferences(file, content, definition) {
138
+ const referring = (name) => {
139
+ const spec = Object.hasOwn(definition.sections, name) ? definition.sections[name] : undefined;
140
+ return spec?.kind === 'list' ? spec.items.reference : undefined;
141
+ };
142
+ if (!Object.keys(definition.sections).some((name) => referring(name) !== undefined))
143
+ return [];
144
+ const uses = usesIn(content);
145
+ const found = [];
146
+ for (const span of headingSpans(content, bodyStartOf(content))) {
147
+ const to = referring(span.name);
148
+ if (to === undefined)
149
+ continue;
150
+ const items = listItems(content, span.bodyStart, span.bodyEnd);
151
+ const hrefs = items === null ? null : itemHrefs(content, items, uses);
152
+ for (const href of hrefs ?? [])
153
+ found.push(reached(file, href, to));
154
+ }
155
+ return found;
156
+ }
157
+ export function* validating(library, context = { binaryTargets: [] }, model = { types: {} }) {
74
158
  const binaryTargets = new Set(context.binaryTargets);
159
+ const binary = (path) => binaryTargets.has(path);
75
160
  const files = Object.keys(library).sort();
161
+ const types = new Map();
162
+ const typeOf = (path) => types.get(path);
76
163
  const documents = new Map();
77
164
  for (const file of files) {
78
165
  if (binaryTargets.has(file))
79
166
  return refuse(file, 'binary-target-document');
80
167
  const parsed = parse(library[file], file);
81
- documents.set(file, parsed);
82
168
  if (!parsed.ok)
83
169
  return { verdict: 'refuse', ...parsed.refusal };
170
+ types.set(file, parsed.document.type ?? BUILT_IN_TYPE);
171
+ if (instanceType(parsed.document) !== BUILT_IN_TYPE)
172
+ documents.set(file, parsed.document);
173
+ yield file;
84
174
  }
85
- const definitions = new Map(Object.entries(model.types));
86
175
  const sectionReferences = new Map();
87
- for (const file of files) {
88
- const parsed = documents.get(file);
89
- if (parsed === undefined || !parsed.ok)
90
- continue;
91
- const kind = instanceType(parsed.document);
92
- if (kind === 'any')
93
- continue;
94
- const definition = kind === null ? undefined : definitions.get(kind);
95
- if (definition === undefined)
96
- return refuse(file, 'unknown-type', { location: 'type' });
97
- const fields = declaredFields(definition);
98
- const fieldFailure = validateFields(fields, parsed.document.fields);
99
- if (fieldFailure !== undefined) {
100
- return refuse(file, fieldFailure.rule, { location: fieldFailure.field });
101
- }
102
- const declared = new Set(Object.keys(fields));
103
- const undeclared = Object.keys(parsed.document.fields).find((name) => !['type', SITE_FIELD, RECEIVED_FIELD].includes(name) && !declared.has(name));
104
- if (undeclared !== undefined)
105
- return refuse(file, 'undeclared-field', { location: undeclared });
106
- const content = library[file];
107
- const spans = headingSpans(content, bodyStartOf(content));
108
- const references = [];
109
- for (const [name, spec] of Object.entries(definition.sections)) {
110
- const occurrences = spans.filter((one) => one.name === name);
111
- if (occurrences.length === 0 && spec.required)
112
- return refuse(file, 'required-section', { location: name });
113
- if (spec.kind !== 'list')
114
- continue;
115
- for (const span of occurrences) {
116
- const items = listItems(content, span.bodyStart, span.bodyEnd);
117
- if (items === null ||
118
- items.some((item) => !fitsKind(spec.of, content.slice(item.start, item.end))))
119
- return refuse(file, 'structured-section', { location: name });
120
- if (spec.of.kind !== 'reference')
121
- continue;
122
- const hrefs = itemHrefs(content, items);
123
- if (hrefs === null)
124
- return refuse(file, 'structured-section', { location: name });
125
- references.push({ section: name, to: spec.of.to, hrefs });
126
- }
127
- }
128
- sectionReferences.set(file, references);
176
+ for (const [file, document] of documents) {
177
+ const read = structure(file, library[file], document, definitionOf(document, model));
178
+ if ('refusal' in read)
179
+ return read.refusal;
180
+ sectionReferences.set(file, read.sections);
181
+ yield file;
129
182
  }
130
- for (const file of files) {
131
- const parsed = documents.get(file);
132
- if (parsed === undefined || !parsed.ok)
133
- continue;
134
- const kind = instanceType(parsed.document);
135
- if (kind === null || kind === 'any')
136
- continue;
137
- const definition = definitions.get(kind);
138
- if (definition === undefined)
139
- continue;
140
- for (const [name, spec] of Object.entries(definition.fields)) {
141
- const targets = referenceTargets(spec, parsed.document.fields[name]);
142
- const expected = expectedReferenceType(spec);
143
- if (expected === null)
144
- continue;
145
- for (const target of targets) {
146
- if (!reaches(file, target, expected, documents, binaryTargets))
147
- return refuse(file, 'unresolved-reference', { location: name });
148
- }
149
- }
150
- const body = bodyAfterFrontmatter(library[file]);
151
- for (const occurrence of hrefOccurrences(body)) {
152
- const resolved = classifyHref(file, occurrence.href);
153
- if (resolved.kind === 'skip')
154
- continue;
155
- if (resolved.kind === 'invalid' ||
156
- (!documents.has(resolved.path) && !binaryTargets.has(resolved.path))) {
157
- return refuse(file, 'unresolved-link');
158
- }
183
+ let least;
184
+ for (const [file, document] of documents) {
185
+ const definition = definitionOf(document, model);
186
+ const fields = references(document, definition).map(({ pointer, value, to }) => ({
187
+ reference: reached(file, value, to),
188
+ location: pointer,
189
+ }));
190
+ for (const { reference, location } of fields) {
191
+ if (!reaches(reference, typeOf, binary))
192
+ return refuse(file, 'unresolved-reference', { location });
159
193
  }
160
- for (const { section, to, hrefs } of sectionReferences.get(file)) {
161
- for (const href of hrefs) {
162
- if (!reaches(file, href, to, documents, binaryTargets))
163
- return refuse(file, 'unresolved-reference', { location: section });
164
- }
194
+ if (!linked(file, library[file]))
195
+ return refuse(file, 'unresolved-link');
196
+ const sections = sectionReferences
197
+ .get(file)
198
+ .flatMap(({ section, to, hrefs }) => hrefs.map((href) => ({ reference: reached(file, href, to), location: section })));
199
+ for (const { reference, location } of sections) {
200
+ if (!reaches(reference, typeOf, binary))
201
+ return refuse(file, 'unresolved-reference', { location });
165
202
  }
166
- }
167
- const missing = new Map();
168
- for (const file of files) {
169
- const parsed = documents.get(file);
170
- if (parsed === undefined || !parsed.ok)
171
- continue;
172
- const kind = instanceType(parsed.document);
173
- if (kind === null || kind === 'any')
174
- continue;
175
- const definition = definitions.get(kind);
176
- if (definition === undefined)
177
- continue;
178
- for (const [name, spec] of Object.entries(definition.fields)) {
179
- const expected = expectedReferenceType(spec);
180
- if (expected === null)
203
+ for (const { reference } of [...fields, ...sections]) {
204
+ if (!missing(reference, typeOf, binary))
181
205
  continue;
182
- for (const target of referenceTargets(spec, parsed.document.fields[name])) {
183
- const resolved = classifyHref(file, target);
184
- if (resolved.kind !== 'path')
185
- continue;
186
- if (documents.has(resolved.path))
187
- continue;
188
- const referrers = missing.get(resolved.path) ?? [];
189
- referrers.push(file);
190
- missing.set(resolved.path, referrers);
191
- }
206
+ const path = reference.target;
207
+ if (least === undefined || path < least.path)
208
+ least = { path, referrers: [] };
209
+ if (path === least.path && least.referrers.at(-1) !== file)
210
+ least.referrers.push(file);
192
211
  }
212
+ yield file;
193
213
  }
194
- const missingPaths = [...missing.keys()].sort();
195
- if (missingPaths.length > 0) {
196
- const path = missingPaths[0];
197
- const referrers = [...new Set(missing.get(path) ?? [])].sort();
198
- return refuse(path, 'referenced-missing-file', { referrers });
199
- }
214
+ if (least !== undefined)
215
+ return refuse(least.path, 'referenced-missing-file', { referrers: least.referrers });
200
216
  return { verdict: 'accept' };
201
217
  }
218
+ export function validate(library, context = { binaryTargets: [] }, model = { types: {} }) {
219
+ const steps = validating(library, context, model);
220
+ let step = steps.next();
221
+ while (step.done !== true)
222
+ step = steps.next();
223
+ return step.value;
224
+ }
package/dist/yaml.d.ts CHANGED
@@ -16,8 +16,7 @@ export type YamlSeq = {
16
16
  };
17
17
  export type YamlEntry = {
18
18
  readonly key: string;
19
- readonly keyStart: number;
20
- readonly keyEnd: number;
19
+ readonly after: number;
21
20
  readonly value: YamlNode;
22
21
  };
23
22
  export type YamlMap = {
@@ -32,7 +31,13 @@ export declare function parseYamlMapping(text: string, start: number, end: numbe
32
31
  export declare function jsValue(node: YamlNode): unknown;
33
32
  export declare function mapEntry(map: YamlMap, key: string): YamlEntry | undefined;
34
33
  export declare function isPlainSafe(text: string): boolean;
35
- export declare function serializeJs(value: unknown): string;
34
+ export type FrontmatterValue = string | number | boolean | null | readonly FrontmatterValue[] | {
35
+ readonly [name: string]: FrontmatterValue;
36
+ };
37
+ export declare function plain(value: unknown): value is Record<string, unknown>;
38
+ export declare function frontmatterValue(value: unknown): value is FrontmatterValue;
39
+ export declare function serializeJs(value: FrontmatterValue): string;
40
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
36
41
  export declare function serializeKey(name: string): string;
37
42
  export declare function bodyStartAfterYaml(content: string, yamlEnd: number): number;
38
43
  export declare function bodyStartOf(content: string): number;
@@ -1 +1 @@
1
- {"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM;IAAnC,YAAqB,MAAM,EAAE,MAAM,EAGlC;CACF;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;AAoEtD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAM7E;AA2ND,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAclF;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAM/C;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAEzE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMjD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQlD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAG3E;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,GACd;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAqB9F;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAQjE;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEzD"}
1
+ {"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../src/yaml.ts"],"names":[],"mappings":"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"}
package/dist/yaml.js CHANGED
@@ -84,6 +84,30 @@ export function interpretPlain(text) {
84
84
  return Number(text);
85
85
  return text;
86
86
  }
87
+ const ESCAPES = {
88
+ b: '\b',
89
+ f: '\f',
90
+ n: '\n',
91
+ r: '\r',
92
+ t: '\t',
93
+ '"': '"',
94
+ '/': '/',
95
+ '\\': '\\',
96
+ };
97
+ function parseEscape(c) {
98
+ c.i += 1;
99
+ const escaped = peek(c);
100
+ const held = ESCAPES[escaped];
101
+ if (held !== undefined) {
102
+ c.i += 1;
103
+ return held;
104
+ }
105
+ const hex = c.text.slice(c.i + 1, c.i + 5);
106
+ if (escaped !== 'u' || c.i + 5 > c.end || !/^[0-9A-Fa-f]{4}$/.test(hex))
107
+ throw new YamlError(c.i);
108
+ c.i += 5;
109
+ return String.fromCharCode(Number.parseInt(hex, 16));
110
+ }
87
111
  function parseQuoted(c) {
88
112
  const quote = peek(c);
89
113
  const start = c.i;
@@ -91,31 +115,19 @@ function parseQuoted(c) {
91
115
  let out = '';
92
116
  while (c.i < c.end) {
93
117
  const ch = peek(c);
118
+ if (quote === "'" && ch === "'" && c.i + 1 < c.end && c.text[c.i + 1] === "'") {
119
+ out += "'";
120
+ c.i += 2;
121
+ continue;
122
+ }
94
123
  if (ch === quote) {
95
124
  c.i += 1;
96
125
  return scalar(out, start, c.i);
97
126
  }
98
127
  if (ch === '\n' || ch === '\r')
99
128
  throw new YamlError(c.i);
100
- if (quote === "'" && ch === "'" && c.text[c.i + 1] === "'") {
101
- out += "'";
102
- c.i += 2;
103
- continue;
104
- }
105
129
  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;
130
+ out += parseEscape(c);
119
131
  continue;
120
132
  }
121
133
  out += ch;
@@ -208,11 +220,12 @@ function parseFlowMap(c) {
208
220
  if (peek(c) !== ':')
209
221
  throw new YamlError(c.i);
210
222
  c.i += 1;
223
+ const after = c.i;
211
224
  const value = parseFlowValue(c);
212
225
  if (seen.has(key.name))
213
226
  throw new YamlError(key.start);
214
227
  seen.add(key.name);
215
- entries.push({ key: key.name, keyStart: key.start, keyEnd: key.end, value });
228
+ entries.push({ key: key.name, after, value });
216
229
  skipFlowSpace(c);
217
230
  if (peek(c) === ',') {
218
231
  c.i += 1;
@@ -254,6 +267,7 @@ function parseFlowSeq(c) {
254
267
  throw new YamlError(c.i);
255
268
  }
256
269
  function parseValue(c, parentKeyIndent) {
270
+ const at = c.i;
257
271
  skipSpaces(c);
258
272
  if (peek(c) === '#')
259
273
  skipToEol(c);
@@ -262,10 +276,12 @@ function parseValue(c, parentKeyIndent) {
262
276
  skipEol(c);
263
277
  skipBlankAndComments(c);
264
278
  if (c.i >= c.end)
265
- return scalar(null, c.i, c.i);
279
+ return scalar(null, at, at);
266
280
  const nextIndent = indentAt(c);
281
+ if (nextIndent === parentKeyIndent && seqAhead(c))
282
+ return parseBlockSeq(c, nextIndent);
267
283
  if (nextIndent <= parentKeyIndent)
268
- return scalar(null, c.i, c.i);
284
+ return scalar(null, at, at);
269
285
  if (peek(c) === '-')
270
286
  return parseBlockSeq(c, nextIndent);
271
287
  if (peek(c) === '[')
@@ -282,6 +298,43 @@ function parseValue(c, parentKeyIndent) {
282
298
  throw new YamlError(c.i);
283
299
  return parseScalar(c, false);
284
300
  }
301
+ function seqAhead(c) {
302
+ const next = c.text[c.i + 1];
303
+ return peek(c) === '-' && (next === ' ' || next === '\n' || next === '\r' || c.i + 1 >= c.end);
304
+ }
305
+ function mappingAhead(c) {
306
+ const start = c.i;
307
+ try {
308
+ if (peek(c) === '{' || peek(c) === '[')
309
+ return false;
310
+ parseKey(c);
311
+ skipSpaces(c);
312
+ if (peek(c) !== ':')
313
+ return false;
314
+ const next = c.text[c.i + 1];
315
+ return next === ' ' || next === '\n' || next === '\r' || c.i + 1 >= c.end;
316
+ }
317
+ catch (error) {
318
+ if (error instanceof YamlError)
319
+ return false;
320
+ throw error;
321
+ }
322
+ finally {
323
+ c.i = start;
324
+ }
325
+ }
326
+ function lineStartOf(c) {
327
+ let j = c.i;
328
+ while (j > 0 && c.text[j - 1] !== '\n' && c.text[j - 1] !== '\r')
329
+ j -= 1;
330
+ return j;
331
+ }
332
+ function parseSeqItem(c, indent) {
333
+ skipSpaces(c);
334
+ if (peek(c) !== '#' && peek(c) !== '\n' && peek(c) !== '\r' && c.i < c.end && mappingAhead(c))
335
+ return parseBlockMap(c, c.i - lineStartOf(c), true);
336
+ return parseValue(c, indent);
337
+ }
285
338
  function parseBlockSeq(c, indent) {
286
339
  const start = c.i;
287
340
  const items = [];
@@ -295,35 +348,41 @@ function parseBlockSeq(c, indent) {
295
348
  if (peek(c) !== '-')
296
349
  break;
297
350
  c.i += 1;
298
- items.push(parseValue(c, indent));
299
- end = c.i;
351
+ const item = parseSeqItem(c, indent);
352
+ items.push(item);
353
+ end = item.end;
300
354
  }
301
355
  return { kind: 'seq', items, start, end };
302
356
  }
303
- function parseBlockMap(c, indent) {
357
+ function parseBlockMap(c, indent, inline = false) {
304
358
  const start = c.i;
305
359
  const entries = [];
306
360
  const seen = new Set();
307
361
  let end = start;
362
+ let first = inline;
308
363
  while (c.i < c.end) {
309
- skipBlankAndComments(c);
310
- if (c.i >= c.end)
311
- break;
312
- if (indentAt(c) < indent)
313
- break;
314
- if (indentAt(c) > indent)
315
- throw new YamlError(c.i);
364
+ if (!first) {
365
+ skipBlankAndComments(c);
366
+ if (c.i >= c.end)
367
+ break;
368
+ if (indentAt(c) < indent)
369
+ break;
370
+ if (indentAt(c) > indent)
371
+ throw new YamlError(c.i);
372
+ }
373
+ first = false;
316
374
  const key = parseKey(c);
317
375
  skipSpaces(c);
318
376
  if (peek(c) !== ':')
319
377
  throw new YamlError(c.i);
320
378
  c.i += 1;
379
+ const after = c.i;
321
380
  const value = parseValue(c, indent);
322
381
  if (seen.has(key.name))
323
382
  throw new YamlError(key.start);
324
383
  seen.add(key.name);
325
- entries.push({ key: key.name, keyStart: key.start, keyEnd: key.end, value });
326
- end = c.i;
384
+ entries.push({ key: key.name, after, value });
385
+ end = value.end;
327
386
  }
328
387
  return { kind: 'map', entries, start, end };
329
388
  }
@@ -369,20 +428,45 @@ export function isPlainSafe(text) {
369
428
  return false;
370
429
  return true;
371
430
  }
431
+ export function plain(value) {
432
+ if (!isRecord(value))
433
+ return false;
434
+ const prototype = Object.getPrototypeOf(value);
435
+ return prototype === Object.prototype || prototype === null;
436
+ }
437
+ function listed(value) {
438
+ const keys = Object.keys(value);
439
+ return keys.length === value.length && keys.every((key, index) => key === String(index));
440
+ }
441
+ function heldWithin(value, within) {
442
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
443
+ return true;
444
+ if (typeof value === 'number')
445
+ return Number.isFinite(value);
446
+ if (typeof value !== 'object' || within.includes(value))
447
+ return false;
448
+ const path = [...within, value];
449
+ const held = (item) => heldWithin(item, path);
450
+ if (Array.isArray(value))
451
+ return listed(value) && value.every(held);
452
+ return plain(value) && Object.values(value).every(held);
453
+ }
454
+ export function frontmatterValue(value) {
455
+ return heldWithin(value, []);
456
+ }
372
457
  export function serializeJs(value) {
373
- if (value === null)
374
- return 'null';
375
- if (value === true)
376
- return 'true';
377
- if (value === false)
378
- return 'false';
379
- if (typeof value === 'number' && Number.isFinite(value))
380
- return JSON.stringify(value);
381
458
  if (typeof value === 'string')
382
459
  return isPlainSafe(value) ? value : JSON.stringify(value);
460
+ if (value === null || typeof value !== 'object')
461
+ return JSON.stringify(value);
383
462
  if (Array.isArray(value))
384
463
  return `[${value.map(serializeJs).join(', ')}]`;
385
- throw new YamlError(0);
464
+ return `{${Object.entries(value)
465
+ .map(([key, held]) => `${serializeKey(key)}: ${serializeJs(held)}`)
466
+ .join(', ')}}`;
467
+ }
468
+ export function isRecord(value) {
469
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
386
470
  }
387
471
  export function serializeKey(name) {
388
472
  return isPlainSafe(name) || /^[A-Za-z][A-Za-z0-9_-]*$/.test(name) ? name : JSON.stringify(name);
@@ -429,7 +513,13 @@ export function equalValue(left, right) {
429
513
  if (left === right)
430
514
  return true;
431
515
  if (Array.isArray(left) && Array.isArray(right)) {
432
- return (left.length === right.length && left.every((item, index) => equalValue(item, right[index])));
516
+ return (left.length === right.length &&
517
+ Array.from(left).every((item, index) => equalValue(item, right[index])));
518
+ }
519
+ if (isRecord(left) && isRecord(right)) {
520
+ const keys = Object.keys(left);
521
+ return (keys.length === Object.keys(right).length &&
522
+ keys.every((key) => Object.hasOwn(right, key) && equalValue(left[key], right[key])));
433
523
  }
434
524
  return false;
435
525
  }