@agentshouse/mdmodel 0.1.0-alpha.9 → 0.1.0-c04c0d681d2d4

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 (404) hide show
  1. package/API.md +368 -0
  2. package/README.md +36 -194
  3. package/dist/blocks.d.ts +11 -0
  4. package/dist/blocks.d.ts.map +1 -0
  5. package/dist/blocks.js +69 -0
  6. package/dist/condition.d.ts +162 -0
  7. package/dist/condition.d.ts.map +1 -0
  8. package/dist/condition.js +616 -0
  9. package/dist/definition.d.ts +70 -27
  10. package/dist/definition.d.ts.map +1 -1
  11. package/dist/definition.js +728 -146
  12. package/dist/divide.d.ts +3 -0
  13. package/dist/divide.d.ts.map +1 -0
  14. package/dist/divide.js +320 -0
  15. package/dist/document.d.ts +12 -2
  16. package/dist/document.d.ts.map +1 -1
  17. package/dist/document.js +400 -177
  18. package/dist/fields.d.ts +6 -0
  19. package/dist/fields.d.ts.map +1 -0
  20. package/dist/fields.js +10 -0
  21. package/dist/index.d.ts +16 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +10 -4
  24. package/dist/links.d.ts +4 -0
  25. package/dist/links.d.ts.map +1 -1
  26. package/dist/links.js +633 -225
  27. package/dist/paths.d.ts +15 -4
  28. package/dist/paths.d.ts.map +1 -1
  29. package/dist/paths.js +149 -36
  30. package/dist/profile.js +1 -3
  31. package/dist/project.d.ts +20 -1
  32. package/dist/project.d.ts.map +1 -1
  33. package/dist/project.js +101 -95
  34. package/dist/references.d.ts +4 -0
  35. package/dist/references.d.ts.map +1 -0
  36. package/dist/references.js +30 -0
  37. package/dist/refuse.d.ts.map +1 -1
  38. package/dist/refuse.js +2 -10
  39. package/dist/schema.d.ts +7 -5
  40. package/dist/schema.d.ts.map +1 -1
  41. package/dist/schema.js +156 -41
  42. package/dist/sections.d.ts +2 -1
  43. package/dist/sections.d.ts.map +1 -1
  44. package/dist/sections.js +44 -66
  45. package/dist/types.d.ts +95 -3
  46. package/dist/types.d.ts.map +1 -1
  47. package/dist/types.js +1 -3
  48. package/dist/validate.d.ts +10 -2
  49. package/dist/validate.d.ts.map +1 -1
  50. package/dist/validate.js +283 -159
  51. package/dist/version.d.ts +1 -1
  52. package/dist/version.d.ts.map +1 -1
  53. package/dist/version.js +1 -3
  54. package/dist/yaml.d.ts +9 -3
  55. package/dist/yaml.d.ts.map +1 -1
  56. package/dist/yaml.js +300 -201
  57. package/fixtures/README.md +91 -56
  58. package/fixtures/cases/absent-link-dangles/library/item.md +8 -0
  59. package/fixtures/cases/absent-link-dangles/schema.yaml +6 -0
  60. package/fixtures/cases/absent-optional-field/context.json +1 -0
  61. package/fixtures/cases/absent-optional-field/expected.json +1 -0
  62. package/fixtures/cases/absent-optional-field/library/companies/acme.md +4 -0
  63. package/fixtures/cases/absent-optional-field/library/deals/lead.md +6 -0
  64. package/fixtures/cases/absent-optional-field/schema.yaml +56 -0
  65. package/fixtures/cases/absolute-link/context.json +1 -0
  66. package/fixtures/cases/absolute-link/expected.json +5 -0
  67. package/fixtures/cases/absolute-link/library/item.md +8 -0
  68. package/fixtures/cases/absolute-link/schema.yaml +6 -0
  69. package/fixtures/cases/attachment-reference-any-file/context.json +1 -0
  70. package/fixtures/cases/attachment-reference-any-file/expected.json +1 -0
  71. package/fixtures/cases/attachment-reference-any-file/library/companies/acme.md +4 -0
  72. package/fixtures/cases/attachment-reference-any-file/library/deals/renewal.md +15 -0
  73. package/fixtures/cases/attachment-reference-any-file/library/places/depot.md +4 -0
  74. package/fixtures/cases/attachment-reference-any-file/library/products/seats.md +4 -0
  75. package/fixtures/cases/attachment-reference-any-file/library/products/support.md +4 -0
  76. package/fixtures/cases/attachment-reference-any-file/schema.yaml +32 -0
  77. package/fixtures/cases/attachment-reference-dangles/context.json +1 -0
  78. package/fixtures/cases/attachment-reference-dangles/expected.json +1 -0
  79. package/fixtures/cases/attachment-reference-dangles/library/companies/acme.md +4 -0
  80. package/fixtures/cases/attachment-reference-dangles/library/deals/renewal.md +15 -0
  81. package/fixtures/cases/attachment-reference-dangles/library/places/depot.md +4 -0
  82. package/fixtures/cases/attachment-reference-dangles/library/products/seats.md +4 -0
  83. package/fixtures/cases/attachment-reference-dangles/library/products/support.md +4 -0
  84. package/fixtures/cases/attachment-reference-dangles/schema.yaml +32 -0
  85. package/fixtures/cases/attachment-reference-outside/context.json +1 -0
  86. package/fixtures/cases/attachment-reference-outside/expected.json +6 -0
  87. package/fixtures/cases/attachment-reference-outside/library/companies/acme.md +4 -0
  88. package/fixtures/cases/attachment-reference-outside/library/deals/renewal.md +15 -0
  89. package/fixtures/cases/attachment-reference-outside/library/places/depot.md +4 -0
  90. package/fixtures/cases/attachment-reference-outside/library/products/seats.md +4 -0
  91. package/fixtures/cases/attachment-reference-outside/library/products/support.md +4 -0
  92. package/fixtures/cases/attachment-reference-outside/schema.yaml +32 -0
  93. package/fixtures/cases/binary-any-reference/expected.json +1 -2
  94. package/fixtures/cases/binary-any-reference/schema.yaml +4 -0
  95. package/fixtures/cases/binary-document-collision/expected.json +1 -2
  96. package/fixtures/cases/binary-document-collision/schema.yaml +1 -0
  97. package/fixtures/cases/binary-image-dangles/expected.json +1 -0
  98. package/fixtures/cases/binary-image-dangles/schema.yaml +1 -0
  99. package/fixtures/cases/binary-link-dangles/expected.json +1 -0
  100. package/fixtures/cases/binary-link-dangles/schema.yaml +1 -0
  101. package/fixtures/cases/binary-link-outside-collection/expected.json +1 -2
  102. package/fixtures/cases/binary-link-outside-collection/schema.yaml +1 -0
  103. package/fixtures/cases/binary-prototype-reference/expected.json +1 -2
  104. package/fixtures/cases/binary-prototype-reference/schema.yaml +4 -0
  105. package/fixtures/cases/binary-typed-reference/expected.json +1 -2
  106. package/fixtures/cases/binary-typed-reference/schema.yaml +5 -0
  107. package/fixtures/cases/boolean-field/context.json +1 -0
  108. package/fixtures/cases/boolean-field/expected.json +6 -0
  109. package/fixtures/cases/boolean-field/library/companies/acme.md +4 -0
  110. package/fixtures/cases/boolean-field/library/deals/renewal.md +31 -0
  111. package/fixtures/cases/boolean-field/schema.yaml +56 -0
  112. package/fixtures/cases/bracketed-link-definition/schema.yaml +6 -0
  113. package/fixtures/cases/closed-nested-object/context.json +1 -0
  114. package/fixtures/cases/closed-nested-object/expected.json +6 -0
  115. package/fixtures/cases/closed-nested-object/library/companies/acme.md +4 -0
  116. package/fixtures/cases/closed-nested-object/library/deals/renewal.md +32 -0
  117. package/fixtures/cases/closed-nested-object/schema.yaml +56 -0
  118. package/fixtures/cases/composed-root-reference/context.json +1 -0
  119. package/fixtures/cases/composed-root-reference/expected.json +6 -0
  120. package/fixtures/cases/composed-root-reference/library/a.md +5 -0
  121. package/fixtures/cases/composed-root-reference/schema.yaml +13 -0
  122. package/fixtures/cases/cross-room-link/context.json +1 -0
  123. package/fixtures/cases/cross-room-link/expected.json +1 -0
  124. package/fixtures/cases/cross-room-link/library/clients/acme.md +6 -0
  125. package/fixtures/cases/cross-room-link/schema.yaml +3 -0
  126. package/fixtures/cases/cross-room-reference/context.json +1 -0
  127. package/fixtures/cases/cross-room-reference/expected.json +1 -0
  128. package/fixtures/cases/cross-room-reference/library/clients/acme.md +9 -0
  129. package/fixtures/cases/cross-room-reference/schema.yaml +9 -0
  130. package/fixtures/cases/date-time-format/context.json +1 -0
  131. package/fixtures/cases/date-time-format/expected.json +6 -0
  132. package/fixtures/cases/date-time-format/library/companies/acme.md +4 -0
  133. package/fixtures/cases/date-time-format/library/deals/renewal.md +31 -0
  134. package/fixtures/cases/date-time-format/schema.yaml +56 -0
  135. package/fixtures/cases/declared-binary-links/schema.yaml +1 -0
  136. package/fixtures/cases/default-unfilled/context.json +1 -0
  137. package/fixtures/cases/default-unfilled/expected.json +6 -0
  138. package/fixtures/cases/default-unfilled/library/companies/acme.md +4 -0
  139. package/fixtures/cases/default-unfilled/library/deals/renewal.md +29 -0
  140. package/fixtures/cases/default-unfilled/schema.yaml +56 -0
  141. package/fixtures/cases/defs-pattern/context.json +1 -0
  142. package/fixtures/cases/defs-pattern/expected.json +6 -0
  143. package/fixtures/cases/defs-pattern/library/companies/acme.md +4 -0
  144. package/fixtures/cases/defs-pattern/library/deals/renewal.md +31 -0
  145. package/fixtures/cases/defs-pattern/schema.yaml +56 -0
  146. package/fixtures/cases/dependent-rule/context.json +1 -0
  147. package/fixtures/cases/dependent-rule/expected.json +6 -0
  148. package/fixtures/cases/dependent-rule/library/companies/acme.md +4 -0
  149. package/fixtures/cases/dependent-rule/library/deals/renewal.md +30 -0
  150. package/fixtures/cases/dependent-rule/schema.yaml +56 -0
  151. package/fixtures/cases/duplicate-link-definition/schema.yaml +6 -0
  152. package/fixtures/cases/email-format/context.json +1 -0
  153. package/fixtures/cases/email-format/expected.json +6 -0
  154. package/fixtures/cases/email-format/library/companies/acme.md +4 -0
  155. package/fixtures/cases/email-format/library/deals/renewal.md +31 -0
  156. package/fixtures/cases/email-format/schema.yaml +56 -0
  157. package/fixtures/cases/fenced-link-definition/schema.yaml +6 -0
  158. package/fixtures/cases/field-enum/expected.json +2 -3
  159. package/fixtures/cases/field-enum/schema.yaml +7 -0
  160. package/fixtures/cases/frontmatter-schema/context.json +1 -0
  161. package/fixtures/cases/frontmatter-schema/expected.json +5 -0
  162. package/fixtures/cases/frontmatter-schema/schema.yaml +5 -0
  163. package/fixtures/cases/integer-field/context.json +1 -0
  164. package/fixtures/cases/integer-field/expected.json +6 -0
  165. package/fixtures/cases/integer-field/library/companies/acme.md +4 -0
  166. package/fixtures/cases/integer-field/library/deals/renewal.md +31 -0
  167. package/fixtures/cases/integer-field/schema.yaml +56 -0
  168. package/fixtures/cases/interrupted-link-definition/schema.yaml +1 -0
  169. package/fixtures/cases/json-schema-constructs/context.json +1 -0
  170. package/fixtures/cases/json-schema-constructs/expected.json +1 -0
  171. package/fixtures/cases/json-schema-constructs/library/companies/acme.md +4 -0
  172. package/fixtures/cases/json-schema-constructs/library/deals/renewal.md +31 -0
  173. package/fixtures/cases/json-schema-constructs/schema.yaml +56 -0
  174. package/fixtures/cases/list-of-objects-closed/context.json +1 -0
  175. package/fixtures/cases/list-of-objects-closed/expected.json +6 -0
  176. package/fixtures/cases/list-of-objects-closed/library/companies/acme.md +4 -0
  177. package/fixtures/cases/list-of-objects-closed/library/deals/renewal.md +32 -0
  178. package/fixtures/cases/list-of-objects-closed/schema.yaml +56 -0
  179. package/fixtures/cases/list-of-objects-item/context.json +1 -0
  180. package/fixtures/cases/list-of-objects-item/expected.json +6 -0
  181. package/fixtures/cases/list-of-objects-item/library/companies/acme.md +4 -0
  182. package/fixtures/cases/list-of-objects-item/library/deals/renewal.md +31 -0
  183. package/fixtures/cases/list-of-objects-item/schema.yaml +56 -0
  184. package/fixtures/cases/list-of-objects-reference/context.json +1 -0
  185. package/fixtures/cases/list-of-objects-reference/expected.json +6 -0
  186. package/fixtures/cases/list-of-objects-reference/library/companies/acme.md +4 -0
  187. package/fixtures/cases/list-of-objects-reference/library/deals/renewal.md +14 -0
  188. package/fixtures/cases/list-of-objects-reference/library/places/depot.md +4 -0
  189. package/fixtures/cases/list-of-objects-reference/library/products/seats.md +4 -0
  190. package/fixtures/cases/list-of-objects-reference/library/products/support.md +4 -0
  191. package/fixtures/cases/list-of-objects-reference/schema.yaml +32 -0
  192. package/fixtures/cases/list-size/context.json +1 -0
  193. package/fixtures/cases/list-size/expected.json +6 -0
  194. package/fixtures/cases/list-size/library/companies/acme.md +4 -0
  195. package/fixtures/cases/list-size/library/deals/renewal.md +31 -0
  196. package/fixtures/cases/list-size/schema.yaml +56 -0
  197. package/fixtures/cases/long-fence-link-definition/schema.yaml +1 -0
  198. package/fixtures/cases/malformed-definition/expected.json +2 -4
  199. package/fixtures/cases/malformed-definition/schema.yaml +3 -0
  200. package/fixtures/cases/member-document/context.json +1 -0
  201. package/fixtures/cases/member-document/expected.json +1 -0
  202. package/fixtures/cases/member-document/library/people/ana.md +5 -0
  203. package/fixtures/cases/member-document/schema.yaml +5 -0
  204. package/fixtures/cases/missing-required-field/expected.json +2 -3
  205. package/fixtures/cases/missing-required-field/schema.yaml +7 -0
  206. package/fixtures/cases/missing-section-item-kind/expected.json +2 -4
  207. package/fixtures/cases/missing-section-item-kind/schema.yaml +6 -0
  208. package/fixtures/cases/misspelled-key/context.json +1 -0
  209. package/fixtures/cases/misspelled-key/expected.json +6 -0
  210. package/fixtures/cases/misspelled-key/library/companies/acme.md +4 -0
  211. package/fixtures/cases/misspelled-key/library/deals/renewal.md +32 -0
  212. package/fixtures/cases/misspelled-key/schema.yaml +56 -0
  213. package/fixtures/cases/nested-defs/context.json +1 -0
  214. package/fixtures/cases/nested-defs/expected.json +6 -0
  215. package/fixtures/cases/nested-defs/library/deal.md +6 -0
  216. package/fixtures/cases/nested-defs/schema.yaml +11 -0
  217. package/fixtures/cases/nested-object-reference/context.json +1 -0
  218. package/fixtures/cases/nested-object-reference/expected.json +6 -0
  219. package/fixtures/cases/nested-object-reference/library/companies/acme.md +4 -0
  220. package/fixtures/cases/nested-object-reference/library/deals/renewal.md +14 -0
  221. package/fixtures/cases/nested-object-reference/library/places/depot.md +4 -0
  222. package/fixtures/cases/nested-object-reference/library/products/seats.md +4 -0
  223. package/fixtures/cases/nested-object-reference/library/products/support.md +4 -0
  224. package/fixtures/cases/nested-object-reference/schema.yaml +32 -0
  225. package/fixtures/cases/nested-reference/context.json +1 -0
  226. package/fixtures/cases/nested-reference/expected.json +1 -0
  227. package/fixtures/cases/nested-reference/library/companies/acme.md +4 -0
  228. package/fixtures/cases/nested-reference/library/deals/renewal.md +15 -0
  229. package/fixtures/cases/nested-reference/library/places/depot.md +4 -0
  230. package/fixtures/cases/nested-reference/library/products/seats.md +4 -0
  231. package/fixtures/cases/nested-reference/library/products/support.md +4 -0
  232. package/fixtures/cases/nested-reference/schema.yaml +32 -0
  233. package/fixtures/cases/nested-required-field/context.json +1 -0
  234. package/fixtures/cases/nested-required-field/expected.json +6 -0
  235. package/fixtures/cases/nested-required-field/library/companies/acme.md +4 -0
  236. package/fixtures/cases/nested-required-field/library/deals/renewal.md +30 -0
  237. package/fixtures/cases/nested-required-field/schema.yaml +56 -0
  238. package/fixtures/cases/null-refused/context.json +1 -0
  239. package/fixtures/cases/null-refused/expected.json +6 -0
  240. package/fixtures/cases/null-refused/library/companies/acme.md +4 -0
  241. package/fixtures/cases/null-refused/library/deals/renewal.md +31 -0
  242. package/fixtures/cases/null-refused/schema.yaml +56 -0
  243. package/fixtures/cases/numeric-range/context.json +1 -0
  244. package/fixtures/cases/numeric-range/expected.json +6 -0
  245. package/fixtures/cases/numeric-range/library/companies/acme.md +4 -0
  246. package/fixtures/cases/numeric-range/library/deals/renewal.md +31 -0
  247. package/fixtures/cases/numeric-range/schema.yaml +56 -0
  248. package/fixtures/cases/one-of-variant/context.json +1 -0
  249. package/fixtures/cases/one-of-variant/expected.json +6 -0
  250. package/fixtures/cases/one-of-variant/library/companies/acme.md +4 -0
  251. package/fixtures/cases/one-of-variant/library/deals/renewal.md +31 -0
  252. package/fixtures/cases/one-of-variant/schema.yaml +56 -0
  253. package/fixtures/cases/open-map-value/context.json +1 -0
  254. package/fixtures/cases/open-map-value/expected.json +6 -0
  255. package/fixtures/cases/open-map-value/library/companies/acme.md +4 -0
  256. package/fixtures/cases/open-map-value/library/deals/renewal.md +31 -0
  257. package/fixtures/cases/open-map-value/schema.yaml +56 -0
  258. package/fixtures/cases/other-room-reference/context.json +1 -0
  259. package/fixtures/cases/other-room-reference/expected.json +6 -0
  260. package/fixtures/cases/other-room-reference/library/companies/acme.md +4 -0
  261. package/fixtures/cases/other-room-reference/library/deals/renewal.md +14 -0
  262. package/fixtures/cases/other-room-reference/library/places/depot.md +4 -0
  263. package/fixtures/cases/other-room-reference/library/products/seats.md +4 -0
  264. package/fixtures/cases/other-room-reference/library/products/support.md +4 -0
  265. package/fixtures/cases/other-room-reference/schema.yaml +32 -0
  266. package/fixtures/cases/paragraph-link-definition/schema.yaml +1 -0
  267. package/fixtures/cases/prototype-field/expected.json +2 -3
  268. package/fixtures/cases/prototype-field/schema.yaml +6 -0
  269. package/fixtures/cases/quoted-link-definition/expected.json +1 -2
  270. package/fixtures/cases/quoted-link-definition/library/notes/draft.md +1 -1
  271. package/fixtures/cases/quoted-link-definition/schema.yaml +1 -0
  272. package/fixtures/cases/referenced-missing-file/expected.json +0 -1
  273. package/fixtures/cases/referenced-missing-file/schema.yaml +11 -0
  274. package/fixtures/cases/remote-ref/context.json +1 -0
  275. package/fixtures/cases/remote-ref/expected.json +5 -0
  276. package/fixtures/cases/remote-ref/schema.yaml +3 -0
  277. package/fixtures/cases/second-member-document/context.json +1 -0
  278. package/fixtures/cases/second-member-document/expected.json +5 -0
  279. package/fixtures/cases/second-member-document/schema.yaml +4 -0
  280. package/fixtures/cases/section-item-enum/context.json +1 -0
  281. package/fixtures/cases/section-item-enum/expected.json +6 -0
  282. package/fixtures/cases/section-item-enum/library/task.md +8 -0
  283. package/fixtures/cases/section-item-enum/schema.yaml +3 -0
  284. package/fixtures/cases/section-item-kind/context.json +1 -0
  285. package/fixtures/cases/section-item-kind/expected.json +6 -0
  286. package/fixtures/cases/section-item-kind/library/task.md +8 -0
  287. package/fixtures/cases/section-item-kind/schema.yaml +3 -0
  288. package/fixtures/cases/section-items/context.json +1 -0
  289. package/fixtures/cases/section-items/expected.json +1 -0
  290. package/fixtures/cases/section-items/library/other.md +3 -0
  291. package/fixtures/cases/section-items/library/page.md +42 -0
  292. package/fixtures/cases/section-items/schema.yaml +10 -0
  293. package/fixtures/cases/section-reference-path/context.json +1 -0
  294. package/fixtures/cases/section-reference-path/expected.json +6 -0
  295. package/fixtures/cases/section-reference-path/library/other.md +3 -0
  296. package/fixtures/cases/section-reference-path/library/page.md +7 -0
  297. package/fixtures/cases/section-reference-path/schema.yaml +3 -0
  298. package/fixtures/cases/section-reference-type/context.json +1 -0
  299. package/fixtures/cases/section-reference-type/expected.json +6 -0
  300. package/fixtures/cases/section-reference-type/library/note.md +1 -0
  301. package/fixtures/cases/section-reference-type/library/page.md +7 -0
  302. package/fixtures/cases/section-reference-type/schema.yaml +3 -0
  303. package/fixtures/cases/shortcut-reference-link/context.json +1 -0
  304. package/fixtures/cases/shortcut-reference-link/expected.json +5 -0
  305. package/fixtures/cases/shortcut-reference-link/library/item.md +10 -0
  306. package/fixtures/cases/shortcut-reference-link/schema.yaml +6 -0
  307. package/fixtures/cases/string-length/context.json +1 -0
  308. package/fixtures/cases/string-length/expected.json +6 -0
  309. package/fixtures/cases/string-length/library/companies/acme.md +4 -0
  310. package/fixtures/cases/string-length/library/deals/renewal.md +31 -0
  311. package/fixtures/cases/string-length/schema.yaml +56 -0
  312. package/fixtures/cases/structured-section/expected.json +1 -2
  313. package/fixtures/cases/structured-section/schema.yaml +7 -0
  314. package/fixtures/cases/submission-keys/context.json +1 -0
  315. package/fixtures/cases/submission-keys/expected.json +1 -0
  316. package/fixtures/cases/submission-keys/library/notes/visitor.md +8 -0
  317. package/fixtures/cases/submission-keys/schema.yaml +4 -0
  318. package/fixtures/cases/text-field-kind/context.json +1 -0
  319. package/fixtures/cases/text-field-kind/expected.json +6 -0
  320. package/fixtures/cases/text-field-kind/library/page.md +4 -0
  321. package/fixtures/cases/text-field-kind/schema.yaml +4 -0
  322. package/fixtures/cases/truncated-link-definition/expected.json +1 -2
  323. package/fixtures/cases/truncated-link-definition/library/notes/draft.md +1 -1
  324. package/fixtures/cases/truncated-link-definition/schema.yaml +1 -0
  325. package/fixtures/cases/types-folder-content/context.json +1 -0
  326. package/fixtures/cases/types-folder-content/expected.json +1 -0
  327. package/fixtures/cases/types-folder-content/library/types/task.md +4 -0
  328. package/fixtures/cases/types-folder-content/schema.yaml +4 -0
  329. package/fixtures/cases/unclosed-frontmatter/expected.json +1 -2
  330. package/fixtures/cases/undeclared-field/expected.json +2 -3
  331. package/fixtures/cases/undeclared-field/schema.yaml +6 -0
  332. package/fixtures/cases/unevaluated-items-closed/context.json +1 -0
  333. package/fixtures/cases/unevaluated-items-closed/expected.json +6 -0
  334. package/fixtures/cases/unevaluated-items-closed/library/trip.md +6 -0
  335. package/fixtures/cases/unevaluated-items-closed/schema.yaml +10 -0
  336. package/fixtures/cases/unknown-type/context.json +1 -0
  337. package/fixtures/cases/unknown-type/expected.json +6 -0
  338. package/fixtures/cases/unknown-type/library/item.md +3 -0
  339. package/fixtures/cases/unknown-type/schema.yaml +3 -0
  340. package/fixtures/cases/unlisted-reference-type/context.json +1 -0
  341. package/fixtures/cases/unlisted-reference-type/expected.json +5 -0
  342. package/fixtures/cases/unlisted-reference-type/schema.yaml +3 -0
  343. package/fixtures/cases/unresolved-link/expected.json +1 -2
  344. package/fixtures/cases/unresolved-link/library/item.md +1 -1
  345. package/fixtures/cases/unresolved-link/schema.yaml +6 -0
  346. package/fixtures/cases/valid-typed-document/schema.yaml +16 -0
  347. package/fixtures/cases/wide-item-fence-link/schema.yaml +1 -0
  348. package/fixtures/division.json +409 -0
  349. package/fixtures/projection.json +90 -21
  350. package/package.json +6 -13
  351. package/dist/definition.js.map +0 -1
  352. package/dist/document.js.map +0 -1
  353. package/dist/index.js.map +0 -1
  354. package/dist/links.js.map +0 -1
  355. package/dist/paths.js.map +0 -1
  356. package/dist/profile.js.map +0 -1
  357. package/dist/project.js.map +0 -1
  358. package/dist/refuse.js.map +0 -1
  359. package/dist/schema.js.map +0 -1
  360. package/dist/sections.js.map +0 -1
  361. package/dist/types.js.map +0 -1
  362. package/dist/validate.js.map +0 -1
  363. package/dist/version.js.map +0 -1
  364. package/dist/yaml.js.map +0 -1
  365. package/fixtures/cases/binary-any-reference/library/types/note.md +0 -5
  366. package/fixtures/cases/binary-document-collision/library/types/note.md +0 -3
  367. package/fixtures/cases/binary-link-outside-collection/library/types/note.md +0 -3
  368. package/fixtures/cases/binary-prototype-reference/library/types/note.md +0 -5
  369. package/fixtures/cases/binary-typed-reference/library/types/note.md +0 -5
  370. package/fixtures/cases/binary-typed-reference/library/types/person.md +0 -3
  371. package/fixtures/cases/bracketed-link-definition/library/types/task.md +0 -7
  372. package/fixtures/cases/declared-binary-links/library/types/note.md +0 -3
  373. package/fixtures/cases/duplicate-link-definition/library/types/task.md +0 -7
  374. package/fixtures/cases/fenced-link-definition/library/types/task.md +0 -7
  375. package/fixtures/cases/field-enum/library/types/task.md +0 -8
  376. package/fixtures/cases/interrupted-link-definition/library/types/note.md +0 -3
  377. package/fixtures/cases/long-fence-link-definition/library/types/note.md +0 -3
  378. package/fixtures/cases/malformed-definition/library/types/task.md +0 -5
  379. package/fixtures/cases/missing-binary-image/expected.json +0 -6
  380. package/fixtures/cases/missing-binary-image/library/types/note.md +0 -3
  381. package/fixtures/cases/missing-binary-link/expected.json +0 -6
  382. package/fixtures/cases/missing-binary-link/library/types/note.md +0 -3
  383. package/fixtures/cases/missing-required-field/library/types/task.md +0 -8
  384. package/fixtures/cases/missing-section-item-kind/library/types/task.md +0 -7
  385. package/fixtures/cases/paragraph-link-definition/library/types/note.md +0 -3
  386. package/fixtures/cases/prd-definition/library/types/task.md +0 -16
  387. package/fixtures/cases/prototype-field/library/types/task.md +0 -7
  388. package/fixtures/cases/quoted-link-definition/library/types/note.md +0 -3
  389. package/fixtures/cases/referenced-missing-file/library/types/person.md +0 -5
  390. package/fixtures/cases/referenced-missing-file/library/types/task.md +0 -8
  391. package/fixtures/cases/structured-section/library/types/task.md +0 -8
  392. package/fixtures/cases/truncated-link-definition/library/types/note.md +0 -3
  393. package/fixtures/cases/undeclared-field/library/types/task.md +0 -7
  394. package/fixtures/cases/unresolved-link/library/types/task.md +0 -7
  395. package/fixtures/cases/valid-typed-document/library/types/person.md +0 -5
  396. package/fixtures/cases/valid-typed-document/library/types/task.md +0 -13
  397. package/fixtures/cases/wide-item-fence-link/library/types/note.md +0 -3
  398. package/markdown-syntax-profile.md +0 -9
  399. /package/fixtures/cases/{prd-definition → absent-link-dangles}/context.json +0 -0
  400. /package/fixtures/cases/{prd-definition → absent-link-dangles}/expected.json +0 -0
  401. /package/fixtures/cases/{missing-binary-image → binary-image-dangles}/context.json +0 -0
  402. /package/fixtures/cases/{missing-binary-image → binary-image-dangles}/library/notes/draft.md +0 -0
  403. /package/fixtures/cases/{missing-binary-link → binary-link-dangles}/context.json +0 -0
  404. /package/fixtures/cases/{missing-binary-link → binary-link-dangles}/library/notes/draft.md +0 -0
@@ -1,171 +1,753 @@
1
- import { typeNameFromPath } from './paths.js';
2
- import { refusal } from './refuse.js';
3
- function refuse(file, rule, location) {
4
- return location === undefined ? refusal(file, rule) : refusal(file, rule, {
5
- location
6
- });
1
+ import { MEMBER_FIELD, RECEIVED_FIELD, SITE_FIELD, TYPE_FIELD } from './fields.js';
2
+ import { equalValue, isRecord, jsValue, parseYamlMapping, YamlError } from './yaml.js';
3
+ export const JSON_TYPES = [
4
+ 'string',
5
+ 'number',
6
+ 'integer',
7
+ 'boolean',
8
+ 'object',
9
+ 'array',
10
+ 'null',
11
+ ];
12
+ export const BUILT_IN_TYPE = 'any';
13
+ export const ATTACHMENT = 'attachment';
14
+ const SCALAR_TYPES = new Set(['string', 'number', 'integer', 'boolean']);
15
+ const COMPOSITES = ['array', 'object'];
16
+ const ANNOTATIONS = new Set([
17
+ '$comment',
18
+ 'title',
19
+ 'description',
20
+ 'default',
21
+ 'examples',
22
+ 'deprecated',
23
+ 'readOnly',
24
+ 'writeOnly',
25
+ ]);
26
+ const FIELD_RULES = ['change_roles', 'initial_roles', 'transitions'];
27
+ const DEFS_REFERENCE = '#/$defs/';
28
+ const UNRESOLVED = /[\u0000-\u001f\u007f%[\]\\^{|}]|\s$/u;
29
+ export const ARRAY_INDEX = /^(?:0|[1-9][0-9]*)$/u;
30
+ const HOUSE_KEYS = {
31
+ [TYPE_FIELD]: { prose: false },
32
+ [SITE_FIELD]: { prose: false },
33
+ [RECEIVED_FIELD]: { prose: false },
34
+ };
35
+ function refuse(rule, location) {
36
+ return location === undefined ? { rule } : { rule, location };
37
+ }
38
+ export function escapePointer(key) {
39
+ return key.replaceAll('~', '~0').replaceAll('/', '~1');
40
+ }
41
+ function unescapePointer(segment) {
42
+ return segment.replaceAll('~1', '/').replaceAll('~0', '~');
43
+ }
44
+ export function pointerSegments(pointer) {
45
+ return pointer.split('/').slice(1).map(unescapePointer);
46
+ }
47
+ export function refTarget(reference, defs) {
48
+ if (!reference.startsWith(DEFS_REFERENCE) || UNRESOLVED.test(reference))
49
+ return undefined;
50
+ const segments = reference.slice(DEFS_REFERENCE.length).split('/');
51
+ const [name = '', ...rest] = segments.map(unescapePointer);
52
+ if (segments.some((segment) => escapePointer(unescapePointer(segment)) !== segment))
53
+ return undefined;
54
+ if (!Object.hasOwn(defs, name))
55
+ return undefined;
56
+ let node = defs[name];
57
+ for (let index = 0; index < rest.length; index += 1) {
58
+ const keyword = rest[index];
59
+ if (!isRecord(node) || !Object.hasOwn(node, keyword) || !Object.hasOwn(KEYWORDS, keyword))
60
+ return undefined;
61
+ const check = KEYWORDS[keyword];
62
+ const held = node[keyword];
63
+ if (check === SCHEMA) {
64
+ node = held;
65
+ continue;
66
+ }
67
+ const key = rest[index + 1];
68
+ index += 1;
69
+ if (check === SCHEMA_LIST && Array.isArray(held) && key !== undefined && ARRAY_INDEX.test(key))
70
+ node = held[Number(key)];
71
+ else if (check === SCHEMA_MAP &&
72
+ isRecord(held) &&
73
+ key !== undefined &&
74
+ Object.hasOwn(held, key))
75
+ node = held[key];
76
+ else
77
+ return undefined;
78
+ if (node === undefined)
79
+ return undefined;
80
+ }
81
+ return { name, node };
82
+ }
83
+ function compiles(pattern) {
84
+ if (typeof pattern !== 'string')
85
+ return false;
86
+ try {
87
+ new RegExp(pattern, 'u');
88
+ return true;
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ function finite(value) {
95
+ return typeof value === 'number' && Number.isFinite(value);
96
+ }
97
+ function count(value) {
98
+ return Number.isSafeInteger(value) && value >= 0;
7
99
  }
8
- function isRecord(value) {
9
- return value !== null && typeof value === 'object' && !Array.isArray(value);
100
+ function strings(value) {
101
+ return (Array.isArray(value) &&
102
+ value.every((item) => typeof item === 'string') &&
103
+ new Set(value).size === value.length);
10
104
  }
11
- function requiredFlag(value) {
12
- if (value === undefined) return false;
13
- if (typeof value === 'boolean') return value;
105
+ function schemaFailure(value, at, context) {
106
+ if (typeof value === 'boolean')
107
+ return undefined;
108
+ if (!isRecord(value))
109
+ return refuse('schema', at);
110
+ for (const [key, held] of Object.entries(value)) {
111
+ const where = `${at}/${escapePointer(key)}`;
112
+ if (!Object.hasOwn(KEYWORDS, key))
113
+ return refuse('schema-keyword', where);
114
+ const check = KEYWORDS[key];
115
+ if (check === SCHEMA) {
116
+ const failure = schemaFailure(held, where, context);
117
+ if (failure !== undefined)
118
+ return failure;
119
+ continue;
120
+ }
121
+ if (check === SCHEMA_LIST) {
122
+ if (!Array.isArray(held) || held.length === 0)
123
+ return refuse(key, where);
124
+ for (const [index, item] of held.entries()) {
125
+ const failure = schemaFailure(item, `${where}/${index}`, context);
126
+ if (failure !== undefined)
127
+ return failure;
128
+ }
129
+ continue;
130
+ }
131
+ if (check === SCHEMA_MAP) {
132
+ if (!isRecord(held))
133
+ return refuse(key, where);
134
+ for (const [name, item] of Object.entries(held)) {
135
+ if (key === 'patternProperties' && !compiles(name))
136
+ return refuse(key, `${where}/${escapePointer(name)}`);
137
+ const failure = schemaFailure(item, `${where}/${escapePointer(name)}`, context);
138
+ if (failure !== undefined)
139
+ return failure;
140
+ }
141
+ continue;
142
+ }
143
+ if (!check(held, where, value, context))
144
+ return refuse(key, where);
145
+ }
14
146
  return undefined;
15
147
  }
16
- function stringList(value) {
17
- if (!Array.isArray(value) || value.length === 0) return undefined;
18
- if (!value.every((item)=>typeof item === 'string' && item !== '')) return undefined;
19
- return value;
148
+ const SCHEMA = () => true;
149
+ const SCHEMA_LIST = () => true;
150
+ const SCHEMA_MAP = () => true;
151
+ const ANY = () => true;
152
+ const TEXT = (value) => typeof value === 'string';
153
+ const FLAG = (value) => typeof value === 'boolean';
154
+ const NUMBER = finite;
155
+ const COUNT = count;
156
+ const KEYWORDS = {
157
+ $comment: TEXT,
158
+ $ref: (value, _at, _node, context) => typeof value === 'string' && refTarget(value, context.defs) !== undefined,
159
+ $defs: SCHEMA_MAP,
160
+ allOf: SCHEMA_LIST,
161
+ anyOf: SCHEMA_LIST,
162
+ oneOf: SCHEMA_LIST,
163
+ prefixItems: SCHEMA_LIST,
164
+ not: SCHEMA,
165
+ if: SCHEMA,
166
+ then: SCHEMA,
167
+ else: SCHEMA,
168
+ items: SCHEMA,
169
+ contains: SCHEMA,
170
+ additionalProperties: SCHEMA,
171
+ unevaluatedProperties: SCHEMA,
172
+ unevaluatedItems: SCHEMA,
173
+ propertyNames: SCHEMA,
174
+ contentSchema: SCHEMA,
175
+ properties: SCHEMA_MAP,
176
+ patternProperties: SCHEMA_MAP,
177
+ dependentSchemas: SCHEMA_MAP,
178
+ type: (value) => (typeof value === 'string' && JSON_TYPES.includes(value)) ||
179
+ (Array.isArray(value) &&
180
+ value.length > 0 &&
181
+ strings(value) &&
182
+ value.every((item) => JSON_TYPES.includes(item))),
183
+ enum: (value) => Array.isArray(value) && value.length > 0,
184
+ const: ANY,
185
+ multipleOf: (value) => finite(value) && value > 0,
186
+ maximum: NUMBER,
187
+ exclusiveMaximum: NUMBER,
188
+ minimum: NUMBER,
189
+ exclusiveMinimum: NUMBER,
190
+ maxLength: COUNT,
191
+ minLength: COUNT,
192
+ maxItems: COUNT,
193
+ minItems: COUNT,
194
+ maxContains: COUNT,
195
+ minContains: COUNT,
196
+ maxProperties: COUNT,
197
+ minProperties: COUNT,
198
+ pattern: compiles,
199
+ uniqueItems: FLAG,
200
+ required: strings,
201
+ dependentRequired: (value) => isRecord(value) && Object.values(value).every(strings),
202
+ format: TEXT,
203
+ contentEncoding: TEXT,
204
+ contentMediaType: TEXT,
205
+ title: TEXT,
206
+ description: TEXT,
207
+ default: ANY,
208
+ examples: (value) => Array.isArray(value),
209
+ deprecated: FLAG,
210
+ readOnly: FLAG,
211
+ writeOnly: FLAG,
212
+ reference: (value, _at, node, context) => {
213
+ if (node.type !== 'string')
214
+ return false;
215
+ const named = typeof value === 'string' ? [value] : value;
216
+ return (Array.isArray(named) &&
217
+ named.length > 0 &&
218
+ strings(named) &&
219
+ named.every((name) => name === BUILT_IN_TYPE ||
220
+ name === ATTACHMENT ||
221
+ context.types.has(name) ||
222
+ node.cross_room === true));
223
+ },
224
+ cross_room: (value, _at, node) => typeof value === 'boolean' && node.reference !== undefined,
225
+ };
226
+ function sharedType(values) {
227
+ if (values.length === 0)
228
+ return undefined;
229
+ if (values.every((value) => typeof value === 'string'))
230
+ return 'string';
231
+ if (values.every((value) => typeof value === 'number'))
232
+ return 'number';
233
+ if (values.every((value) => typeof value === 'boolean'))
234
+ return 'boolean';
235
+ return undefined;
20
236
  }
21
- const SCALAR_KINDS = new Set([
22
- 'text',
23
- 'string',
24
- 'number',
25
- 'date',
26
- 'enum',
27
- 'reference'
28
- ]);
29
- function parseScalar(file, location, spec, required) {
30
- const kind = spec.kind;
31
- if (kind === 'text') return {
32
- kind: 'text',
33
- required
34
- };
35
- if (kind === 'string') return {
36
- kind: 'string',
37
- required
38
- };
39
- if (kind === 'number') return {
40
- kind: 'number',
41
- required
237
+ function singleType(type) {
238
+ if (typeof type === 'string')
239
+ return type;
240
+ if (!Array.isArray(type))
241
+ return undefined;
242
+ const kept = type.filter((one) => one !== 'null');
243
+ return kept.length === 1 ? kept[0] : undefined;
244
+ }
245
+ function firstOf(held, read) {
246
+ for (const node of held) {
247
+ const value = read(node);
248
+ if (value !== undefined)
249
+ return value;
250
+ }
251
+ return undefined;
252
+ }
253
+ function conjoined(nodes, defs, ancestry) {
254
+ const held = [];
255
+ const reached = new Set(ancestry);
256
+ const visit = (node) => {
257
+ if (!isRecord(node) || held.includes(node))
258
+ return;
259
+ held.push(node);
260
+ if (typeof node.$ref === 'string') {
261
+ const target = refTarget(node.$ref, defs)?.node;
262
+ if (target !== undefined && !reached.has(target)) {
263
+ reached.add(target);
264
+ visit(target);
265
+ }
266
+ }
267
+ if (Array.isArray(node.allOf))
268
+ for (const one of node.allOf)
269
+ visit(one);
42
270
  };
43
- if (kind === 'date') return {
44
- kind: 'date',
45
- required
271
+ for (const node of nodes)
272
+ visit(node);
273
+ return { held, ancestry: reached };
274
+ }
275
+ function variantsOf(node) {
276
+ return [
277
+ ...(Array.isArray(node.anyOf) ? node.anyOf : []),
278
+ ...(Array.isArray(node.oneOf) ? node.oneOf : []),
279
+ node.then,
280
+ node.else,
281
+ ...(isRecord(node.dependentSchemas) ? Object.values(node.dependentSchemas) : []),
282
+ ].filter(isRecord);
283
+ }
284
+ function united(left, right) {
285
+ if (left === undefined || right === undefined)
286
+ return undefined;
287
+ return [...left, ...right.filter((value) => !left.some((held) => equalValue(held, value)))];
288
+ }
289
+ function both(left, right) {
290
+ return left !== undefined && right !== undefined ? joined(left, right) : undefined;
291
+ }
292
+ function joined(left, right) {
293
+ const type = left.type === right.type ? left.type : undefined;
294
+ const format = left.format === right.format ? left.format : undefined;
295
+ const values = united(left.values, right.values);
296
+ const reference = united(left.reference, right.reference);
297
+ const crossRoom = left.crossRoom === true || right.crossRoom === true;
298
+ const items = both(left.items, right.items);
299
+ const prefix = left.prefix === undefined && right.prefix === undefined
300
+ ? undefined
301
+ : Array.from({ length: Math.max(left.prefix?.length ?? 0, right.prefix?.length ?? 0) }, (_, index) => both(itemFacts(left, index), itemFacts(right, index)) ?? { prose: false });
302
+ const properties = Object.create(null);
303
+ for (const [name, facts] of Object.entries(left.properties ?? {})) {
304
+ const shared = both(facts, right.properties?.[name]);
305
+ if (shared !== undefined)
306
+ properties[name] = shared;
307
+ }
308
+ const patterns = (left.patterns ?? []).flatMap(({ pattern, facts }) => {
309
+ const shared = both(facts, right.patterns?.find((one) => one.pattern === pattern)?.facts);
310
+ return shared === undefined ? [] : [{ pattern, facts: shared }];
311
+ });
312
+ const additional = both(left.additional, right.additional);
313
+ return {
314
+ ...(type === undefined ? {} : { type }),
315
+ ...(format === undefined ? {} : { format }),
316
+ ...(values === undefined ? {} : { values }),
317
+ ...(reference === undefined ? {} : { reference }),
318
+ ...(reference !== undefined && crossRoom ? { crossRoom: true } : {}),
319
+ prose: left.prose && right.prose,
320
+ ...(prefix === undefined ? {} : { prefix }),
321
+ ...(items === undefined ? {} : { items }),
322
+ ...(Object.keys(properties).length === 0 ? {} : { properties }),
323
+ ...(patterns.length === 0 ? {} : { patterns }),
324
+ ...(additional === undefined ? {} : { additional }),
46
325
  };
47
- if (kind === 'enum') {
48
- const values = stringList(spec.values);
49
- if (values === undefined) return refuse(file, 'definition-enum-values', location);
50
- return {
51
- kind: 'enum',
52
- required,
53
- values
54
- };
326
+ }
327
+ function propertiesOf(held, variants, defs, ancestry) {
328
+ const declared = new Map();
329
+ for (const node of held) {
330
+ if (!isRecord(node.properties))
331
+ continue;
332
+ for (const [name, schema] of Object.entries(node.properties))
333
+ declared.set(name, [...(declared.get(name) ?? []), schema]);
55
334
  }
56
- if (kind === 'reference') {
57
- if (typeof spec.to !== 'string' || spec.to === '') return refuse(file, 'definition-reference-to', location);
58
- return {
59
- kind: 'reference',
60
- required,
61
- to: spec.to
62
- };
335
+ const properties = Object.create(null);
336
+ for (const [name, schemas] of declared)
337
+ properties[name] = factsOf(schemas, defs, ancestry);
338
+ const conditional = Object.create(null);
339
+ for (const branch of variants.values()) {
340
+ for (const [name, facts] of Object.entries(branch.properties ?? {})) {
341
+ if (Object.hasOwn(properties, name))
342
+ continue;
343
+ conditional[name] = Object.hasOwn(conditional, name)
344
+ ? joined(conditional[name], facts)
345
+ : facts;
346
+ }
63
347
  }
64
- return refuse(file, 'definition-field-kind', location);
65
- }
66
- function extraKeys(spec, allowed) {
67
- return Object.keys(spec).some((key)=>!allowed.includes(key));
68
- }
69
- function parseList(file, location, spec, required, malformed) {
70
- if (typeof spec.of !== 'string' || !SCALAR_KINDS.has(spec.of)) {
71
- return refuse(file, 'definition-list-of', location);
72
- }
73
- const allowed = spec.of === 'enum' ? [
74
- 'kind',
75
- 'required',
76
- 'of',
77
- 'values'
78
- ] : spec.of === 'reference' ? [
79
- 'kind',
80
- 'required',
81
- 'of',
82
- 'to'
83
- ] : [
84
- 'kind',
85
- 'required',
86
- 'of'
348
+ for (const [name, facts] of Object.entries(conditional))
349
+ properties[name] = { ...facts, conditional: true };
350
+ return Object.keys(properties).length === 0 ? undefined : properties;
351
+ }
352
+ function nullOnly(facts) {
353
+ return facts.type === 'null' || (facts.values?.every((value) => value === null) ?? false);
354
+ }
355
+ function alternativesOf(held, variants) {
356
+ return held.flatMap((node) => [node.anyOf, node.oneOf].flatMap((branches) => {
357
+ if (!Array.isArray(branches))
358
+ return [];
359
+ const kept = branches
360
+ .flatMap((branch) => {
361
+ const facts = isRecord(branch) ? variants.get(branch) : undefined;
362
+ return facts === undefined ? [] : [facts];
363
+ })
364
+ .filter((facts) => !nullOnly(facts));
365
+ return kept.length === 0 ? [] : [kept];
366
+ }));
367
+ }
368
+ function inheritedOf(held) {
369
+ return held.flatMap((node) => {
370
+ const kept = Object.fromEntries(['type', 'items', 'prefixItems'].flatMap((key) => node[key] === undefined ? [] : [[key, node[key]]]));
371
+ return Object.keys(kept).length === 0 ? [] : [kept];
372
+ });
373
+ }
374
+ function factsOf(nodes, defs, ancestry) {
375
+ const { held, ancestry: reached } = conjoined(nodes, defs, ancestry);
376
+ const inherited = inheritedOf(held);
377
+ const variants = new Map(held
378
+ .flatMap(variantsOf)
379
+ .map((branch) => [branch, factsOf([branch, ...inherited], defs, reached)]));
380
+ const unions = alternativesOf(held, variants);
381
+ const alternatives = unions.map((kept) => kept.reduce(joined));
382
+ const listed = [
383
+ ...held.flatMap((node) => Array.isArray(node.enum) ? [node.enum] : node.const !== undefined ? [[node.const]] : []),
384
+ ...alternatives.flatMap((facts) => (facts.values === undefined ? [] : [facts.values])),
87
385
  ];
88
- if (extraKeys(spec, allowed)) return refuse(file, malformed, location);
89
- const inner = parseScalar(file, location, {
90
- ...spec,
91
- kind: spec.of
92
- }, false);
93
- if ('rule' in inner) return inner;
386
+ const values = listed.length === 0
387
+ ? undefined
388
+ : listed.reduce((kept, list) => kept.filter((value) => list.some((other) => equalValue(other, value))));
389
+ const type = firstOf(held, (node) => singleType(node.type)) ??
390
+ (values === undefined ? undefined : sharedType(values)) ??
391
+ alternatives.find((facts) => facts.type !== undefined)?.type;
392
+ const reference = firstOf(held, (node) => typeof node.reference === 'string'
393
+ ? [node.reference]
394
+ : Array.isArray(node.reference)
395
+ ? node.reference
396
+ : undefined) ?? alternatives.find((facts) => facts.reference !== undefined)?.reference;
397
+ const crossRoom = firstOf(held, (node) => node.reference === undefined ? undefined : node.cross_room === true) ?? alternatives.find((facts) => facts.reference !== undefined)?.crossRoom === true;
398
+ const format = firstOf(held, (node) => (typeof node.format === 'string' ? node.format : undefined)) ??
399
+ alternatives.find((facts) => facts.format !== undefined)?.format;
400
+ const prose = type === 'string' &&
401
+ values === undefined &&
402
+ format === undefined &&
403
+ reference === undefined &&
404
+ held.every((node) => node.pattern === undefined) &&
405
+ unions.every((kept) => kept.every((facts) => facts.type !== 'string' || facts.prose));
406
+ const listedItems = held.flatMap((node) => (node.items === undefined ? [] : [node.items]));
407
+ const items = type !== 'array'
408
+ ? undefined
409
+ : (alternatives.find((facts) => facts.items !== undefined)?.items ??
410
+ (listedItems.length > 0 ? factsOf(listedItems, defs, reached) : undefined));
411
+ const tuples = held.flatMap((node) => Array.isArray(node.prefixItems) ? [node.prefixItems] : []);
412
+ const prefix = type !== 'array'
413
+ ? undefined
414
+ : (alternatives.find((facts) => facts.prefix !== undefined)?.prefix ??
415
+ (tuples.length === 0
416
+ ? undefined
417
+ : Array.from({ length: Math.max(...tuples.map((tuple) => tuple.length)) }, (_, index) => factsOf(tuples.flatMap((tuple) => (index < tuple.length ? [tuple[index]] : [])), defs, reached))));
418
+ const mapped = type === 'object' || type === undefined;
419
+ const properties = mapped ? propertiesOf(held, variants, defs, reached) : undefined;
420
+ const patterns = mapped
421
+ ? held.flatMap((node) => Object.entries(isRecord(node.patternProperties) ? node.patternProperties : {}).map(([pattern, schema]) => ({ pattern, facts: factsOf([schema], defs, reached) })))
422
+ : [];
423
+ const opened = mapped
424
+ ? held.flatMap((node) => [node.additionalProperties, node.unevaluatedProperties].filter(isRecord))
425
+ : [];
426
+ const additional = opened.length === 0 ? undefined : factsOf(opened, defs, reached);
94
427
  return {
95
- kind: 'list',
96
- required,
97
- of: inner
428
+ ...(type === undefined ? {} : { type }),
429
+ ...(format === undefined ? {} : { format }),
430
+ ...(values === undefined ? {} : { values }),
431
+ ...(reference === undefined ? {} : { reference }),
432
+ ...(reference !== undefined && crossRoom ? { crossRoom: true } : {}),
433
+ prose,
434
+ ...(prefix === undefined ? {} : { prefix }),
435
+ ...(items === undefined ? {} : { items }),
436
+ ...(properties === undefined ? {} : { properties }),
437
+ ...(patterns.length === 0 ? {} : { patterns }),
438
+ ...(additional === undefined ? {} : { additional }),
98
439
  };
99
440
  }
100
- function parseField(file, location, value) {
101
- if (!isRecord(value) || typeof value.kind !== 'string') return refuse(file, 'definition-field', location);
102
- const required = requiredFlag(value.required);
103
- if (required === undefined) return refuse(file, 'definition-field', location);
104
- if (value.kind === 'list') return parseList(file, location, value, required, 'definition-field');
105
- const allowed = value.kind === 'enum' ? [
106
- 'kind',
107
- 'required',
108
- 'values'
109
- ] : value.kind === 'reference' ? [
110
- 'kind',
111
- 'required',
112
- 'to'
113
- ] : [
114
- 'kind',
115
- 'required'
441
+ export function valueFacts(node, defs) {
442
+ return factsOf([node], defs, new Set());
443
+ }
444
+ export function itemFacts(facts, index) {
445
+ return facts.prefix?.[index] ?? facts.items;
446
+ }
447
+ export function memberFacts(facts, key) {
448
+ if (facts.properties !== undefined && Object.hasOwn(facts.properties, key))
449
+ return facts.properties[key];
450
+ const pattern = facts.patterns?.find((one) => new RegExp(one.pattern, 'u').test(key));
451
+ return pattern === undefined ? facts.additional : pattern.facts;
452
+ }
453
+ export function crossedFacts(facts) {
454
+ if (facts.type !== 'array')
455
+ return [facts];
456
+ return [...(facts.prefix ?? []), ...(facts.items === undefined ? [] : [facts.items])].flatMap(crossedFacts);
457
+ }
458
+ export function fieldFacts(definition, key) {
459
+ if (Object.hasOwn(definition.fields, key))
460
+ return definition.fields[key];
461
+ if (Object.hasOwn(HOUSE_KEYS, key))
462
+ return undefined;
463
+ return memberFacts(definition.frontmatter, key);
464
+ }
465
+ function stepped({ facts, through, conditional }, token) {
466
+ if (facts.type === 'array' && ARRAY_INDEX.test(token)) {
467
+ const item = itemFacts(facts, Number(token));
468
+ return item === undefined ? [] : [{ facts: item, through, conditional }];
469
+ }
470
+ return crossedFacts(facts).flatMap((crossed) => {
471
+ const member = memberFacts(crossed, token);
472
+ return member === undefined
473
+ ? []
474
+ : [
475
+ {
476
+ facts: member,
477
+ through: through || facts.type === 'array',
478
+ conditional: conditional || member.conditional === true,
479
+ },
480
+ ];
481
+ });
482
+ }
483
+ export function pointerFacts(definition, pointer) {
484
+ const [field, ...rest] = pointerSegments(pointer);
485
+ const declared = field === undefined ? undefined : fieldFacts(definition, field);
486
+ if (declared === undefined)
487
+ return undefined;
488
+ let reached = [
489
+ { facts: declared, through: false, conditional: declared.conditional === true },
116
490
  ];
117
- if (extraKeys(value, allowed)) return refuse(file, 'definition-field', location);
118
- return parseScalar(file, location, value, required);
119
- }
120
- function parseSection(file, location, value) {
121
- if (!isRecord(value) || value.kind !== 'text' && value.kind !== 'list') {
122
- return refuse(file, 'definition-section-kind', location);
123
- }
124
- const required = requiredFlag(value.required);
125
- if (required === undefined) return refuse(file, 'definition-section', location);
126
- if (value.kind === 'list') return parseList(file, location, value, required, 'definition-section');
127
- if (extraKeys(value, [
128
- 'kind',
129
- 'required'
130
- ])) return refuse(file, 'definition-section', location);
131
- return {
132
- kind: 'text',
133
- required
134
- };
491
+ for (const token of rest)
492
+ reached = reached.flatMap((held) => stepped(held, token));
493
+ if (reached.length === 0)
494
+ return undefined;
495
+ return reached.reduce((kept, held) => ({
496
+ facts: joined(kept.facts, held.facts),
497
+ through: kept.through || held.through,
498
+ conditional: kept.conditional || held.conditional,
499
+ }));
135
500
  }
136
- export function readDefinition(file, document) {
137
- if (document.type !== 'definition') return refuse(file, 'definition-type');
138
- const name = typeNameFromPath(file);
139
- if (name === '') return refuse(file, 'definition-type');
140
- for (const key of Object.keys(document.fields)){
141
- if (key !== 'type' && key !== 'fields' && key !== 'sections') {
142
- return refuse(file, 'definition-shape', key);
501
+ function reachedDefs(value, defs, reached) {
502
+ if (Array.isArray(value)) {
503
+ for (const item of value)
504
+ reachedDefs(item, defs, reached);
505
+ return;
506
+ }
507
+ if (!isRecord(value))
508
+ return;
509
+ for (const [key, held] of Object.entries(value)) {
510
+ if (key === '$ref' && typeof held === 'string') {
511
+ const name = refTarget(held, defs)?.name;
512
+ if (name === undefined || Object.hasOwn(reached, name))
513
+ continue;
514
+ reached[name] = defs[name];
515
+ reachedDefs(defs[name], defs, reached);
516
+ continue;
143
517
  }
518
+ reachedDefs(held, defs, reached);
144
519
  }
145
- const fieldsValue = document.fields.fields;
146
- const sectionsValue = document.fields.sections;
147
- if (fieldsValue !== undefined && !isRecord(fieldsValue)) return refuse(file, 'definition-fields', 'fields');
148
- if (sectionsValue !== undefined && !isRecord(sectionsValue)) {
149
- return refuse(file, 'definition-sections', 'sections');
520
+ }
521
+ function readSections(value, at, context) {
522
+ const failed = (rule, location) => ({ failure: refuse(rule, location) });
523
+ if (!isRecord(value))
524
+ return failed('sections', at);
525
+ const sections = Object.create(null);
526
+ for (const [name, spec] of Object.entries(value)) {
527
+ const where = `${at}/${escapePointer(name)}`;
528
+ if (!isRecord(spec) || (spec.kind !== 'text' && spec.kind !== 'list'))
529
+ return failed('sections', where);
530
+ const allowed = spec.kind === 'list' ? ['kind', 'required', 'items'] : ['kind', 'required'];
531
+ const extra = Object.keys(spec).find((key) => !allowed.includes(key));
532
+ if (extra !== undefined)
533
+ return failed('sections', `${where}/${escapePointer(extra)}`);
534
+ if (spec.required !== undefined && typeof spec.required !== 'boolean')
535
+ return failed('sections', `${where}/required`);
536
+ const required = spec.required === true;
537
+ if (spec.kind === 'text') {
538
+ sections[name] = { kind: 'text', required };
539
+ continue;
540
+ }
541
+ if (spec.items === undefined)
542
+ return failed('sections', `${where}/items`);
543
+ const failure = schemaFailure(spec.items, `${where}/items`, context);
544
+ if (failure !== undefined)
545
+ return { failure };
546
+ const items = valueFacts(spec.items, context.defs);
547
+ if (items.type === undefined || !SCALAR_TYPES.has(items.type))
548
+ return failed('sections', `${where}/items`);
549
+ sections[name] = { kind: 'list', required, items };
150
550
  }
151
- const fields = Object.create(null);
152
- for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})){
153
- const parsed = parseField(file, fieldName, spec);
154
- if ('rule' in parsed) return parsed;
155
- fields[fieldName] = parsed;
551
+ return { sections };
552
+ }
553
+ function deepFreeze(value) {
554
+ if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
555
+ Object.freeze(value);
556
+ for (const held of Object.values(value))
557
+ deepFreeze(held);
156
558
  }
157
- const sections = Object.create(null);
158
- for (const [sectionName, spec] of Object.entries(sectionsValue ?? {})){
159
- const parsed = parseSection(file, sectionName, spec);
160
- if ('rule' in parsed) return parsed;
161
- sections[sectionName] = parsed;
559
+ return value;
560
+ }
561
+ function ruleValue(value) {
562
+ return value === null || typeof value === 'string' || typeof value === 'boolean' || finite(value);
563
+ }
564
+ function roleNames(value) {
565
+ return strings(value) && value.every((name) => name !== '');
566
+ }
567
+ function compositesOf(value) {
568
+ return Array.isArray(value) ? ['array'] : isRecord(value) ? ['object'] : [];
569
+ }
570
+ function typed(type) {
571
+ const types = typeof type === 'string' ? [type] : type;
572
+ return Array.isArray(types) ? COMPOSITES.filter((kind) => types.includes(kind)) : undefined;
573
+ }
574
+ function admittedWhole(node) {
575
+ if (node === true)
576
+ return COMPOSITES;
577
+ if (!isRecord(node) || Object.keys(node).some((key) => key !== 'type' && !ANNOTATIONS.has(key)))
578
+ return [];
579
+ return typed(node.type) ?? COMPOSITES;
580
+ }
581
+ function composites(node, defs, seen) {
582
+ if (node === false)
583
+ return [];
584
+ if (!isRecord(node))
585
+ return COMPOSITES;
586
+ const each = (nodes) => Array.isArray(nodes) ? nodes.map((one) => composites(one, defs, seen)) : [];
587
+ const target = typeof node.$ref === 'string' ? refTarget(node.$ref, defs)?.node : undefined;
588
+ const conditioned = () => {
589
+ const met = composites(node.then ?? true, defs, seen);
590
+ return COMPOSITES.filter((kind) => (composites(node.if, defs, seen).includes(kind) && met.includes(kind)) ||
591
+ composites(node.else ?? true, defs, seen).includes(kind));
592
+ };
593
+ const bounds = [
594
+ typed(node.type),
595
+ Array.isArray(node.enum) ? node.enum.flatMap(compositesOf) : undefined,
596
+ Object.hasOwn(node, 'const') ? compositesOf(node.const) : undefined,
597
+ target === undefined || seen.has(target)
598
+ ? undefined
599
+ : composites(target, defs, new Set([...seen, target])),
600
+ ...each(node.allOf),
601
+ ...[node.anyOf, node.oneOf].filter(Array.isArray).map((branches) => each(branches).flat()),
602
+ Object.hasOwn(node, 'if') ? conditioned() : undefined,
603
+ Object.hasOwn(node, 'not')
604
+ ? COMPOSITES.filter((kind) => !admittedWhole(node.not).includes(kind))
605
+ : undefined,
606
+ ];
607
+ return COMPOSITES.filter((kind) => bounds.every((bound) => bound?.includes(kind) ?? true));
608
+ }
609
+ function transitionOf(value) {
610
+ if (!isRecord(value) || !Object.hasOwn(value, 'from') || !Object.hasOwn(value, 'to'))
611
+ return undefined;
612
+ const { from, to, roles, ...rest } = value;
613
+ if (Object.keys(rest).length > 0 || !ruleValue(from) || !ruleValue(to))
614
+ return undefined;
615
+ if (roles === undefined)
616
+ return { from, to };
617
+ return roleNames(roles) ? { from, to, roles } : undefined;
618
+ }
619
+ function fieldRules(written, field, at, defs) {
620
+ const { change_roles: changeRoles, initial_roles: initialRoles, transitions } = written;
621
+ if (changeRoles !== undefined && !roleNames(changeRoles))
622
+ return refuse('change_roles', `${at}/change_roles`);
623
+ if (initialRoles !== undefined && !roleNames(initialRoles))
624
+ return refuse('initial_roles', `${at}/initial_roles`);
625
+ if (transitions === undefined)
626
+ return {
627
+ ...(changeRoles === undefined ? {} : { changeRoles }),
628
+ ...(initialRoles === undefined ? {} : { initialRoles }),
629
+ };
630
+ if (!Array.isArray(transitions) || composites(field, defs, new Set()).length > 0)
631
+ return refuse('transitions', `${at}/transitions`);
632
+ const listed = [];
633
+ for (const [index, held] of transitions.entries()) {
634
+ const transition = transitionOf(held);
635
+ if (transition === undefined)
636
+ return refuse('transitions', `${at}/transitions/${index}`);
637
+ listed.push(transition);
162
638
  }
639
+ return {
640
+ ...(changeRoles === undefined ? {} : { changeRoles }),
641
+ ...(initialRoles === undefined ? {} : { initialRoles }),
642
+ transitions: listed,
643
+ };
644
+ }
645
+ function unruled(schema) {
646
+ const written = new Map();
647
+ if (!isRecord(schema.properties))
648
+ return { schema, written };
649
+ const properties = Object.create(null);
650
+ for (const [field, node] of Object.entries(schema.properties)) {
651
+ if (!isRecord(node) || !FIELD_RULES.some((keyword) => Object.hasOwn(node, keyword))) {
652
+ properties[field] = node;
653
+ continue;
654
+ }
655
+ written.set(field, node);
656
+ properties[field] = Object.fromEntries(Object.entries(node).filter(([keyword]) => !FIELD_RULES.includes(keyword)));
657
+ }
658
+ return { schema: written.size === 0 ? schema : { ...schema, properties }, written };
659
+ }
660
+ function readType(name, value, context) {
661
+ const at = `/${escapePointer(name)}`;
662
+ if (!isRecord(value))
663
+ return refuse('schema', at);
664
+ const { sections: declared, member_document: mark, create_roles: createRoles, delete_roles: deleteRoles, ...ruled } = value;
665
+ if (mark !== undefined && typeof mark !== 'boolean')
666
+ return refuse('member_document', `${at}/member_document`);
667
+ if (createRoles !== undefined && !roleNames(createRoles))
668
+ return refuse('create_roles', `${at}/create_roles`);
669
+ if (deleteRoles !== undefined && !roleNames(deleteRoles))
670
+ return refuse('delete_roles', `${at}/delete_roles`);
671
+ const read = declared === undefined
672
+ ? { sections: Object.create(null) }
673
+ : readSections(declared, `${at}/sections`, context);
674
+ if ('failure' in read)
675
+ return read.failure;
676
+ const { schema, written } = unruled(ruled);
677
+ const failure = schemaFailure(schema, at, context);
678
+ if (failure !== undefined)
679
+ return failure;
680
+ const rules = Object.create(null);
681
+ for (const [field, keywords] of written) {
682
+ const properties = schema.properties;
683
+ const where = `${at}/properties/${escapePointer(field)}`;
684
+ const ruling = fieldRules(keywords, properties[field], where, context.defs);
685
+ if ('rule' in ruling)
686
+ return ruling;
687
+ rules[field] = ruling;
688
+ }
689
+ const memberDocument = mark === true;
690
+ const root = valueFacts(schema, context.defs);
691
+ const fields = Object.assign(Object.create(null), root.properties);
692
+ if (memberDocument && !Object.hasOwn(fields, MEMBER_FIELD))
693
+ fields[MEMBER_FIELD] = { type: 'string', prose: false };
694
+ const defs = Object.create(null);
695
+ reachedDefs(value, context.defs, defs);
696
+ const { create_roles: _create, delete_roles: _delete, ...shaped } = value;
163
697
  return {
164
698
  name,
165
- file,
699
+ memberDocument,
700
+ frontmatter: { ...root, properties: { ...HOUSE_KEYS, ...fields } },
166
701
  fields,
167
- sections
702
+ sections: read.sections,
703
+ rules,
704
+ ...(createRoles === undefined ? {} : { createRoles }),
705
+ ...(deleteRoles === undefined ? {} : { deleteRoles }),
706
+ shape: {
707
+ schema: written.size === 0 ? shaped : { ...shaped, properties: schema.properties },
708
+ defs,
709
+ },
168
710
  };
169
711
  }
170
-
171
- //# sourceMappingURL=definition.js.map
712
+ function lineAt(text, offset) {
713
+ return text.slice(0, offset).split(/\r\n|\r|\n/).length;
714
+ }
715
+ export function readSchema(text) {
716
+ let root;
717
+ try {
718
+ root = jsValue(parseYamlMapping(text, 0, text.length));
719
+ }
720
+ catch (error) {
721
+ if (error instanceof YamlError)
722
+ return refuse('schema-yaml', `line ${lineAt(text, error.offset)}`);
723
+ throw error;
724
+ }
725
+ const defs = root.$defs ?? Object.create(null);
726
+ if (!isRecord(defs))
727
+ return refuse('$defs', '/$defs');
728
+ const names = Object.keys(root).filter((key) => key !== '$defs');
729
+ for (const name of names) {
730
+ if (name === '' || name.startsWith('$') || name === BUILT_IN_TYPE || name === ATTACHMENT)
731
+ return refuse('schema-type-name', `/${escapePointer(name)}`);
732
+ }
733
+ const context = { defs, types: new Set(names) };
734
+ for (const [name, def] of Object.entries(defs)) {
735
+ const failure = schemaFailure(def, `/$defs/${escapePointer(name)}`, context);
736
+ if (failure !== undefined)
737
+ return failure;
738
+ }
739
+ const types = Object.create(null);
740
+ let marked = false;
741
+ for (const name of names) {
742
+ const definition = readType(name, root[name], context);
743
+ if ('rule' in definition)
744
+ return definition;
745
+ if (definition.memberDocument) {
746
+ if (marked)
747
+ return refuse('member_document', `/${escapePointer(name)}/member_document`);
748
+ marked = true;
749
+ }
750
+ types[name] = deepFreeze(definition);
751
+ }
752
+ return Object.freeze({ types: Object.freeze(types) });
753
+ }