@agentshouse/mdmodel 0.1.0-alpha.8 → 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 (407) hide show
  1. package/API.md +368 -0
  2. package/README.md +36 -180
  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 -25
  10. package/dist/definition.d.ts.map +1 -1
  11. package/dist/definition.js +726 -138
  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 +106 -74
  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 +45 -67
  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 -154
  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 +301 -202
  57. package/fixtures/README.md +91 -55
  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/context.json +1 -0
  207. package/fixtures/cases/missing-section-item-kind/expected.json +5 -0
  208. package/fixtures/cases/missing-section-item-kind/schema.yaml +6 -0
  209. package/fixtures/cases/misspelled-key/context.json +1 -0
  210. package/fixtures/cases/misspelled-key/expected.json +6 -0
  211. package/fixtures/cases/misspelled-key/library/companies/acme.md +4 -0
  212. package/fixtures/cases/misspelled-key/library/deals/renewal.md +32 -0
  213. package/fixtures/cases/misspelled-key/schema.yaml +56 -0
  214. package/fixtures/cases/nested-defs/context.json +1 -0
  215. package/fixtures/cases/nested-defs/expected.json +6 -0
  216. package/fixtures/cases/nested-defs/library/deal.md +6 -0
  217. package/fixtures/cases/nested-defs/schema.yaml +11 -0
  218. package/fixtures/cases/nested-object-reference/context.json +1 -0
  219. package/fixtures/cases/nested-object-reference/expected.json +6 -0
  220. package/fixtures/cases/nested-object-reference/library/companies/acme.md +4 -0
  221. package/fixtures/cases/nested-object-reference/library/deals/renewal.md +14 -0
  222. package/fixtures/cases/nested-object-reference/library/places/depot.md +4 -0
  223. package/fixtures/cases/nested-object-reference/library/products/seats.md +4 -0
  224. package/fixtures/cases/nested-object-reference/library/products/support.md +4 -0
  225. package/fixtures/cases/nested-object-reference/schema.yaml +32 -0
  226. package/fixtures/cases/nested-reference/context.json +1 -0
  227. package/fixtures/cases/nested-reference/expected.json +1 -0
  228. package/fixtures/cases/nested-reference/library/companies/acme.md +4 -0
  229. package/fixtures/cases/nested-reference/library/deals/renewal.md +15 -0
  230. package/fixtures/cases/nested-reference/library/places/depot.md +4 -0
  231. package/fixtures/cases/nested-reference/library/products/seats.md +4 -0
  232. package/fixtures/cases/nested-reference/library/products/support.md +4 -0
  233. package/fixtures/cases/nested-reference/schema.yaml +32 -0
  234. package/fixtures/cases/nested-required-field/context.json +1 -0
  235. package/fixtures/cases/nested-required-field/expected.json +6 -0
  236. package/fixtures/cases/nested-required-field/library/companies/acme.md +4 -0
  237. package/fixtures/cases/nested-required-field/library/deals/renewal.md +30 -0
  238. package/fixtures/cases/nested-required-field/schema.yaml +56 -0
  239. package/fixtures/cases/null-refused/context.json +1 -0
  240. package/fixtures/cases/null-refused/expected.json +6 -0
  241. package/fixtures/cases/null-refused/library/companies/acme.md +4 -0
  242. package/fixtures/cases/null-refused/library/deals/renewal.md +31 -0
  243. package/fixtures/cases/null-refused/schema.yaml +56 -0
  244. package/fixtures/cases/numeric-range/context.json +1 -0
  245. package/fixtures/cases/numeric-range/expected.json +6 -0
  246. package/fixtures/cases/numeric-range/library/companies/acme.md +4 -0
  247. package/fixtures/cases/numeric-range/library/deals/renewal.md +31 -0
  248. package/fixtures/cases/numeric-range/schema.yaml +56 -0
  249. package/fixtures/cases/one-of-variant/context.json +1 -0
  250. package/fixtures/cases/one-of-variant/expected.json +6 -0
  251. package/fixtures/cases/one-of-variant/library/companies/acme.md +4 -0
  252. package/fixtures/cases/one-of-variant/library/deals/renewal.md +31 -0
  253. package/fixtures/cases/one-of-variant/schema.yaml +56 -0
  254. package/fixtures/cases/open-map-value/context.json +1 -0
  255. package/fixtures/cases/open-map-value/expected.json +6 -0
  256. package/fixtures/cases/open-map-value/library/companies/acme.md +4 -0
  257. package/fixtures/cases/open-map-value/library/deals/renewal.md +31 -0
  258. package/fixtures/cases/open-map-value/schema.yaml +56 -0
  259. package/fixtures/cases/other-room-reference/context.json +1 -0
  260. package/fixtures/cases/other-room-reference/expected.json +6 -0
  261. package/fixtures/cases/other-room-reference/library/companies/acme.md +4 -0
  262. package/fixtures/cases/other-room-reference/library/deals/renewal.md +14 -0
  263. package/fixtures/cases/other-room-reference/library/places/depot.md +4 -0
  264. package/fixtures/cases/other-room-reference/library/products/seats.md +4 -0
  265. package/fixtures/cases/other-room-reference/library/products/support.md +4 -0
  266. package/fixtures/cases/other-room-reference/schema.yaml +32 -0
  267. package/fixtures/cases/paragraph-link-definition/schema.yaml +1 -0
  268. package/fixtures/cases/prototype-field/context.json +1 -0
  269. package/fixtures/cases/prototype-field/expected.json +6 -0
  270. package/fixtures/cases/prototype-field/library/item.md +9 -0
  271. package/fixtures/cases/prototype-field/schema.yaml +6 -0
  272. package/fixtures/cases/quoted-link-definition/expected.json +1 -2
  273. package/fixtures/cases/quoted-link-definition/library/notes/draft.md +1 -1
  274. package/fixtures/cases/quoted-link-definition/schema.yaml +1 -0
  275. package/fixtures/cases/referenced-missing-file/expected.json +0 -1
  276. package/fixtures/cases/referenced-missing-file/schema.yaml +11 -0
  277. package/fixtures/cases/remote-ref/context.json +1 -0
  278. package/fixtures/cases/remote-ref/expected.json +5 -0
  279. package/fixtures/cases/remote-ref/schema.yaml +3 -0
  280. package/fixtures/cases/second-member-document/context.json +1 -0
  281. package/fixtures/cases/second-member-document/expected.json +5 -0
  282. package/fixtures/cases/second-member-document/schema.yaml +4 -0
  283. package/fixtures/cases/section-item-enum/context.json +1 -0
  284. package/fixtures/cases/section-item-enum/expected.json +6 -0
  285. package/fixtures/cases/section-item-enum/library/task.md +8 -0
  286. package/fixtures/cases/section-item-enum/schema.yaml +3 -0
  287. package/fixtures/cases/section-item-kind/context.json +1 -0
  288. package/fixtures/cases/section-item-kind/expected.json +6 -0
  289. package/fixtures/cases/section-item-kind/library/task.md +8 -0
  290. package/fixtures/cases/section-item-kind/schema.yaml +3 -0
  291. package/fixtures/cases/section-items/context.json +1 -0
  292. package/fixtures/cases/section-items/expected.json +1 -0
  293. package/fixtures/cases/section-items/library/other.md +3 -0
  294. package/fixtures/cases/section-items/library/page.md +42 -0
  295. package/fixtures/cases/section-items/schema.yaml +10 -0
  296. package/fixtures/cases/section-reference-path/context.json +1 -0
  297. package/fixtures/cases/section-reference-path/expected.json +6 -0
  298. package/fixtures/cases/section-reference-path/library/other.md +3 -0
  299. package/fixtures/cases/section-reference-path/library/page.md +7 -0
  300. package/fixtures/cases/section-reference-path/schema.yaml +3 -0
  301. package/fixtures/cases/section-reference-type/context.json +1 -0
  302. package/fixtures/cases/section-reference-type/expected.json +6 -0
  303. package/fixtures/cases/section-reference-type/library/note.md +1 -0
  304. package/fixtures/cases/section-reference-type/library/page.md +7 -0
  305. package/fixtures/cases/section-reference-type/schema.yaml +3 -0
  306. package/fixtures/cases/shortcut-reference-link/context.json +1 -0
  307. package/fixtures/cases/shortcut-reference-link/expected.json +5 -0
  308. package/fixtures/cases/shortcut-reference-link/library/item.md +10 -0
  309. package/fixtures/cases/shortcut-reference-link/schema.yaml +6 -0
  310. package/fixtures/cases/string-length/context.json +1 -0
  311. package/fixtures/cases/string-length/expected.json +6 -0
  312. package/fixtures/cases/string-length/library/companies/acme.md +4 -0
  313. package/fixtures/cases/string-length/library/deals/renewal.md +31 -0
  314. package/fixtures/cases/string-length/schema.yaml +56 -0
  315. package/fixtures/cases/structured-section/expected.json +1 -2
  316. package/fixtures/cases/structured-section/schema.yaml +7 -0
  317. package/fixtures/cases/submission-keys/context.json +1 -0
  318. package/fixtures/cases/submission-keys/expected.json +1 -0
  319. package/fixtures/cases/submission-keys/library/notes/visitor.md +8 -0
  320. package/fixtures/cases/submission-keys/schema.yaml +4 -0
  321. package/fixtures/cases/text-field-kind/context.json +1 -0
  322. package/fixtures/cases/text-field-kind/expected.json +6 -0
  323. package/fixtures/cases/text-field-kind/library/page.md +4 -0
  324. package/fixtures/cases/text-field-kind/schema.yaml +4 -0
  325. package/fixtures/cases/truncated-link-definition/expected.json +1 -2
  326. package/fixtures/cases/truncated-link-definition/library/notes/draft.md +1 -1
  327. package/fixtures/cases/truncated-link-definition/schema.yaml +1 -0
  328. package/fixtures/cases/types-folder-content/context.json +1 -0
  329. package/fixtures/cases/types-folder-content/expected.json +1 -0
  330. package/fixtures/cases/types-folder-content/library/types/task.md +4 -0
  331. package/fixtures/cases/types-folder-content/schema.yaml +4 -0
  332. package/fixtures/cases/unclosed-frontmatter/expected.json +1 -2
  333. package/fixtures/cases/undeclared-field/context.json +1 -0
  334. package/fixtures/cases/undeclared-field/expected.json +6 -0
  335. package/fixtures/cases/undeclared-field/library/item.md +9 -0
  336. package/fixtures/cases/undeclared-field/schema.yaml +6 -0
  337. package/fixtures/cases/unevaluated-items-closed/context.json +1 -0
  338. package/fixtures/cases/unevaluated-items-closed/expected.json +6 -0
  339. package/fixtures/cases/unevaluated-items-closed/library/trip.md +6 -0
  340. package/fixtures/cases/unevaluated-items-closed/schema.yaml +10 -0
  341. package/fixtures/cases/unknown-type/context.json +1 -0
  342. package/fixtures/cases/unknown-type/expected.json +6 -0
  343. package/fixtures/cases/unknown-type/library/item.md +3 -0
  344. package/fixtures/cases/unknown-type/schema.yaml +3 -0
  345. package/fixtures/cases/unlisted-reference-type/context.json +1 -0
  346. package/fixtures/cases/unlisted-reference-type/expected.json +5 -0
  347. package/fixtures/cases/unlisted-reference-type/schema.yaml +3 -0
  348. package/fixtures/cases/unresolved-link/expected.json +1 -2
  349. package/fixtures/cases/unresolved-link/library/item.md +1 -1
  350. package/fixtures/cases/unresolved-link/schema.yaml +6 -0
  351. package/fixtures/cases/valid-typed-document/library/tasks/one.md +1 -0
  352. package/fixtures/cases/valid-typed-document/schema.yaml +16 -0
  353. package/fixtures/cases/wide-item-fence-link/schema.yaml +1 -0
  354. package/fixtures/division.json +409 -0
  355. package/fixtures/projection.json +109 -28
  356. package/package.json +6 -13
  357. package/dist/definition.js.map +0 -1
  358. package/dist/document.js.map +0 -1
  359. package/dist/index.js.map +0 -1
  360. package/dist/links.js.map +0 -1
  361. package/dist/paths.js.map +0 -1
  362. package/dist/profile.js.map +0 -1
  363. package/dist/project.js.map +0 -1
  364. package/dist/refuse.js.map +0 -1
  365. package/dist/schema.js.map +0 -1
  366. package/dist/sections.js.map +0 -1
  367. package/dist/types.js.map +0 -1
  368. package/dist/validate.js.map +0 -1
  369. package/dist/version.js.map +0 -1
  370. package/dist/yaml.js.map +0 -1
  371. package/fixtures/cases/binary-any-reference/library/types/note.md +0 -5
  372. package/fixtures/cases/binary-document-collision/library/types/note.md +0 -3
  373. package/fixtures/cases/binary-link-outside-collection/library/types/note.md +0 -3
  374. package/fixtures/cases/binary-prototype-reference/library/types/note.md +0 -5
  375. package/fixtures/cases/binary-typed-reference/library/types/note.md +0 -5
  376. package/fixtures/cases/binary-typed-reference/library/types/person.md +0 -3
  377. package/fixtures/cases/bracketed-link-definition/library/types/task.md +0 -7
  378. package/fixtures/cases/declared-binary-links/library/types/note.md +0 -3
  379. package/fixtures/cases/duplicate-link-definition/library/types/task.md +0 -7
  380. package/fixtures/cases/fenced-link-definition/library/types/task.md +0 -7
  381. package/fixtures/cases/field-enum/library/types/task.md +0 -8
  382. package/fixtures/cases/interrupted-link-definition/library/types/note.md +0 -3
  383. package/fixtures/cases/long-fence-link-definition/library/types/note.md +0 -3
  384. package/fixtures/cases/malformed-definition/library/types/task.md +0 -5
  385. package/fixtures/cases/missing-binary-image/expected.json +0 -6
  386. package/fixtures/cases/missing-binary-image/library/types/note.md +0 -3
  387. package/fixtures/cases/missing-binary-link/expected.json +0 -6
  388. package/fixtures/cases/missing-binary-link/library/types/note.md +0 -3
  389. package/fixtures/cases/missing-required-field/library/types/task.md +0 -8
  390. package/fixtures/cases/paragraph-link-definition/library/types/note.md +0 -3
  391. package/fixtures/cases/prd-definition/library/types/task.md +0 -15
  392. package/fixtures/cases/quoted-link-definition/library/types/note.md +0 -3
  393. package/fixtures/cases/referenced-missing-file/library/types/person.md +0 -5
  394. package/fixtures/cases/referenced-missing-file/library/types/task.md +0 -8
  395. package/fixtures/cases/structured-section/library/types/task.md +0 -8
  396. package/fixtures/cases/truncated-link-definition/library/types/note.md +0 -3
  397. package/fixtures/cases/unresolved-link/library/types/task.md +0 -7
  398. package/fixtures/cases/valid-typed-document/library/types/person.md +0 -5
  399. package/fixtures/cases/valid-typed-document/library/types/task.md +0 -12
  400. package/fixtures/cases/wide-item-fence-link/library/types/note.md +0 -3
  401. package/markdown-syntax-profile.md +0 -9
  402. /package/fixtures/cases/{prd-definition → absent-link-dangles}/context.json +0 -0
  403. /package/fixtures/cases/{prd-definition → absent-link-dangles}/expected.json +0 -0
  404. /package/fixtures/cases/{missing-binary-image → binary-image-dangles}/context.json +0 -0
  405. /package/fixtures/cases/{missing-binary-image → binary-image-dangles}/library/notes/draft.md +0 -0
  406. /package/fixtures/cases/{missing-binary-link → binary-link-dangles}/context.json +0 -0
  407. /package/fixtures/cases/{missing-binary-link → binary-link-dangles}/library/notes/draft.md +0 -0
@@ -1,165 +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', '~');
7
43
  }
8
- function isRecord(value) {
9
- return value !== null && typeof value === 'object' && !Array.isArray(value);
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
+ }
10
93
  }
11
- function requiredFlag(value) {
12
- if (value === undefined) return false;
13
- if (typeof value === 'boolean') return value;
94
+ function finite(value) {
95
+ return typeof value === 'number' && Number.isFinite(value);
96
+ }
97
+ function count(value) {
98
+ return Number.isSafeInteger(value) && value >= 0;
99
+ }
100
+ function strings(value) {
101
+ return (Array.isArray(value) &&
102
+ value.every((item) => typeof item === 'string') &&
103
+ new Set(value).size === value.length);
104
+ }
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
- 'string',
23
- 'number',
24
- 'date',
25
- 'enum',
26
- 'reference'
27
- ]);
28
- function parseScalar(file, location, spec, required) {
29
- const kind = spec.kind;
30
- if (kind === 'string') return {
31
- kind: 'string',
32
- required
33
- };
34
- if (kind === 'number') return {
35
- kind: 'number',
36
- 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);
37
270
  };
38
- if (kind === 'date') return {
39
- kind: 'date',
40
- 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 }),
41
325
  };
42
- if (kind === 'enum') {
43
- const values = stringList(spec.values);
44
- if (values === undefined) return refuse(file, 'definition-enum-values', location);
45
- return {
46
- kind: 'enum',
47
- required,
48
- values
49
- };
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]);
50
334
  }
51
- if (kind === 'reference') {
52
- if (typeof spec.to !== 'string' || spec.to === '') return refuse(file, 'definition-reference-to', location);
53
- return {
54
- kind: 'reference',
55
- required,
56
- to: spec.to
57
- };
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
+ }
58
347
  }
59
- return refuse(file, 'definition-field-kind', location);
348
+ for (const [name, facts] of Object.entries(conditional))
349
+ properties[name] = { ...facts, conditional: true };
350
+ return Object.keys(properties).length === 0 ? undefined : properties;
60
351
  }
61
- function extraKeys(spec, allowed) {
62
- return Object.keys(spec).some((key)=>!allowed.includes(key));
352
+ function nullOnly(facts) {
353
+ return facts.type === 'null' || (facts.values?.every((value) => value === null) ?? false);
63
354
  }
64
- function parseField(file, location, value) {
65
- if (!isRecord(value) || typeof value.kind !== 'string') return refuse(file, 'definition-field', location);
66
- const required = requiredFlag(value.required);
67
- if (required === undefined) return refuse(file, 'definition-field', location);
68
- if (value.kind === 'list') {
69
- if (typeof value.of !== 'string' || !SCALAR_KINDS.has(value.of)) {
70
- return refuse(file, 'definition-list-of', location);
71
- }
72
- const allowed = value.of === 'enum' ? [
73
- 'kind',
74
- 'required',
75
- 'of',
76
- 'values'
77
- ] : value.of === 'reference' ? [
78
- 'kind',
79
- 'required',
80
- 'of',
81
- 'to'
82
- ] : [
83
- 'kind',
84
- 'required',
85
- 'of'
86
- ];
87
- if (extraKeys(value, allowed)) return refuse(file, 'definition-field', location);
88
- const inner = parseScalar(file, location, {
89
- ...value,
90
- kind: value.of
91
- }, false);
92
- if ('rule' in inner) return inner;
93
- return {
94
- kind: 'list',
95
- required,
96
- of: inner
97
- };
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])),
385
+ ];
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);
427
+ return {
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 }),
439
+ };
440
+ }
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 }];
98
469
  }
99
- const allowed = value.kind === 'enum' ? [
100
- 'kind',
101
- 'required',
102
- 'values'
103
- ] : value.kind === 'reference' ? [
104
- 'kind',
105
- 'required',
106
- 'to'
107
- ] : [
108
- 'kind',
109
- 'required'
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 },
110
490
  ];
111
- if (extraKeys(value, allowed)) return refuse(file, 'definition-field', location);
112
- return parseScalar(file, location, value, required);
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
+ }));
113
500
  }
114
- function parseSection(file, location, value) {
115
- if (!isRecord(value) || value.kind !== 'text' && value.kind !== 'list') {
116
- return refuse(file, 'definition-section-kind', location);
501
+ function reachedDefs(value, defs, reached) {
502
+ if (Array.isArray(value)) {
503
+ for (const item of value)
504
+ reachedDefs(item, defs, reached);
505
+ return;
117
506
  }
118
- const required = requiredFlag(value.required);
119
- if (required === undefined || extraKeys(value, [
120
- 'kind',
121
- 'required'
122
- ])) {
123
- return refuse(file, 'definition-section', location);
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;
517
+ }
518
+ reachedDefs(held, defs, reached);
124
519
  }
125
- return {
126
- kind: value.kind,
127
- required
128
- };
129
520
  }
130
- export function readDefinition(file, document) {
131
- if (document.type !== 'definition') return refuse(file, 'definition-type');
132
- const name = typeNameFromPath(file);
133
- if (name === '') return refuse(file, 'definition-type');
134
- for (const key of Object.keys(document.fields)){
135
- if (key !== 'type' && key !== 'fields' && key !== 'sections') {
136
- return refuse(file, 'definition-shape', key);
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;
137
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 };
138
550
  }
139
- const fieldsValue = document.fields.fields;
140
- const sectionsValue = document.fields.sections;
141
- if (fieldsValue !== undefined && !isRecord(fieldsValue)) return refuse(file, 'definition-fields', 'fields');
142
- if (sectionsValue !== undefined && !isRecord(sectionsValue)) {
143
- return refuse(file, 'definition-sections', 'sections');
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);
144
558
  }
145
- const fields = {};
146
- for (const [fieldName, spec] of Object.entries(fieldsValue ?? {})){
147
- const parsed = parseField(file, fieldName, spec);
148
- if ('rule' in parsed) return parsed;
149
- fields[fieldName] = 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);
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)));
150
657
  }
151
- const sections = {};
152
- for (const [sectionName, spec] of Object.entries(sectionsValue ?? {})){
153
- const parsed = parseSection(file, sectionName, spec);
154
- if ('rule' in parsed) return parsed;
155
- sections[sectionName] = parsed;
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;
156
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;
157
697
  return {
158
698
  name,
159
- file,
699
+ memberDocument,
700
+ frontmatter: { ...root, properties: { ...HOUSE_KEYS, ...fields } },
160
701
  fields,
161
- 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
+ },
162
710
  };
163
711
  }
164
-
165
- //# 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
+ }