@openpresentation/opf 0.14.0 → 0.15.1

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 (348) hide show
  1. package/README.md +24 -38
  2. package/dist/catalog-refs-BSfGELpt.d.ts +128 -0
  3. package/dist/catalog-schemas-CinPh5WA.d.ts +12 -0
  4. package/dist/catalog.d.ts +91 -0
  5. package/dist/{chunk-XOZ4KMSR.js → catalog.js} +16514 -8800
  6. package/dist/{chart-data-B_3z9VTb.d.ts → chart-data-BnNqgnC-.d.ts} +1 -1
  7. package/dist/{chunk-LS2FMPI5.js → chunk-2CJPC4HI.js} +760 -851
  8. package/dist/{chunk-4VJDTF55.js → chunk-374R35TJ.js} +1 -1
  9. package/dist/{chunk-UPQQD7MA.js → chunk-3JG4YXWF.js} +7 -5
  10. package/dist/{chunk-4LDGKLUC.js → chunk-3RKB4RDJ.js} +1 -1
  11. package/dist/{chunk-BFLVSVA7.js → chunk-5FTUIDUH.js} +1 -1
  12. package/dist/{chunk-D3TY4TT6.js → chunk-HXHOZ7AH.js} +1407 -154
  13. package/dist/{chunk-6OXY2CP3.js → chunk-O744SXXA.js} +319 -162
  14. package/dist/{chunk-JDJBDYSR.js → chunk-QDI75P2M.js} +194 -846
  15. package/dist/chunk-SPFV27O5.js +210 -0
  16. package/dist/chunk-TRDXRRQK.js +17 -0
  17. package/dist/{chunk-Z65B2B77.js → chunk-TWQJLI6E.js} +2 -2
  18. package/dist/{chunk-Q2TCMN56.js → chunk-U4J75TRG.js} +1 -1
  19. package/dist/{chunk-XIZUK2XM.js → chunk-UBFJ2QHH.js} +5 -3
  20. package/dist/{chunk-CSQHPVGL.js → chunk-VGAOJEY7.js} +1 -1
  21. package/dist/{chunk-5ZU6JAPP.js → chunk-ZPU46TFA.js} +1 -1
  22. package/dist/{composition-_WEwBe2a.d.ts → composition-D2tghM82.d.ts} +233 -108
  23. package/dist/composition.d.ts +3 -2
  24. package/dist/composition.js +2 -2
  25. package/dist/convert.d.ts +14 -17
  26. package/dist/convert.js +36 -39
  27. package/dist/data.d.ts +1 -1
  28. package/dist/data.js +3 -3
  29. package/dist/diff.d.ts +1 -1
  30. package/dist/diff.js +7 -7
  31. package/dist/docs.js +29 -29
  32. package/dist/examples.d.ts +1 -1
  33. package/dist/examples.js +48431 -3697
  34. package/dist/{finding-C_por275.d.ts → finding-CT_f_vbD.d.ts} +2 -2
  35. package/dist/format.js +2 -2
  36. package/dist/index.d.ts +225 -76
  37. package/dist/index.js +341 -258
  38. package/dist/json-BFSdESOE.d.ts +19 -0
  39. package/dist/markdown.d.ts +19 -7
  40. package/dist/markdown.js +9 -9
  41. package/dist/{pagination-BZpXLvFL.d.ts → pagination-wedbe7eq.d.ts} +31 -31
  42. package/dist/pagination.d.ts +4 -5
  43. package/dist/pagination.js +6 -6
  44. package/dist/patch.d.ts +1 -1
  45. package/dist/patch.js +6 -6
  46. package/dist/{presentation-C5eHkevA.d.ts → presentation-CDKQVkyI.d.ts} +382 -550
  47. package/dist/repo-readme.js +1 -1
  48. package/dist/schemas.d.ts +284 -1
  49. package/dist/schemas.js +1 -1
  50. package/dist/spec/README.md +1 -1
  51. package/dist/spec/catalogs/font-schemes/angsana-new.json +1 -1
  52. package/dist/spec/catalogs/font-schemes/aparajita.json +2 -2
  53. package/dist/spec/catalogs/font-schemes/arabic-typesetting.json +1 -1
  54. package/dist/spec/catalogs/font-schemes/batang.json +1 -1
  55. package/dist/spec/catalogs/font-schemes/daunpenh.json +1 -1
  56. package/dist/spec/catalogs/font-schemes/david.json +1 -1
  57. package/dist/spec/catalogs/font-schemes/dilleniaupc.json +1 -1
  58. package/dist/spec/catalogs/font-schemes/fangsong.json +1 -1
  59. package/dist/spec/catalogs/font-schemes/gautami.json +1 -1
  60. package/dist/spec/catalogs/font-schemes/gisha.json +2 -2
  61. package/dist/spec/catalogs/font-schemes/gungsuh.json +1 -1
  62. package/dist/spec/catalogs/font-schemes/index.json +1 -1
  63. package/dist/spec/catalogs/font-schemes/kalinga.json +1 -1
  64. package/dist/spec/catalogs/font-schemes/kartika.json +1 -1
  65. package/dist/spec/catalogs/font-schemes/khmer-ui.json +1 -1
  66. package/dist/spec/catalogs/font-schemes/latha.json +1 -1
  67. package/dist/spec/catalogs/font-schemes/malgun-gothic.json +1 -1
  68. package/dist/spec/catalogs/font-schemes/mangal.json +3 -3
  69. package/dist/spec/catalogs/font-schemes/meiryo.json +1 -1
  70. package/dist/spec/catalogs/font-schemes/microsoft-jhenghei.json +1 -1
  71. package/dist/spec/catalogs/font-schemes/microsoft-yahei.json +4 -4
  72. package/dist/spec/catalogs/font-schemes/mingliu.json +1 -1
  73. package/dist/spec/catalogs/font-schemes/miriam.json +1 -1
  74. package/dist/spec/catalogs/font-schemes/ms-mincho.json +1 -1
  75. package/dist/spec/catalogs/font-schemes/nirmala-ui.json +1 -1
  76. package/dist/spec/catalogs/font-schemes/noto-naksh-arabic.json +1 -1
  77. package/dist/spec/catalogs/font-schemes/noto-nastaliq-urdu.json +2 -2
  78. package/dist/spec/catalogs/font-schemes/noto-sans-arabic.json +3 -3
  79. package/dist/spec/catalogs/font-schemes/noto-sans-armenian.json +1 -1
  80. package/dist/spec/catalogs/font-schemes/noto-sans-bengali.json +2 -2
  81. package/dist/spec/catalogs/font-schemes/noto-sans-devangari.json +2 -2
  82. package/dist/spec/catalogs/font-schemes/noto-sans-ethiopic.json +1 -1
  83. package/dist/spec/catalogs/font-schemes/noto-sans-georgian.json +1 -1
  84. package/dist/spec/catalogs/font-schemes/noto-sans-gujarati.json +1 -1
  85. package/dist/spec/catalogs/font-schemes/noto-sans-gurmukhi.json +1 -1
  86. package/dist/spec/catalogs/font-schemes/noto-sans-hebrew.json +1 -1
  87. package/dist/spec/catalogs/font-schemes/noto-sans-jp.json +1 -1
  88. package/dist/spec/catalogs/font-schemes/noto-sans-kannada.json +1 -1
  89. package/dist/spec/catalogs/font-schemes/noto-sans-khmer.json +1 -1
  90. package/dist/spec/catalogs/font-schemes/noto-sans-kr.json +1 -1
  91. package/dist/spec/catalogs/font-schemes/noto-sans-malayalam.json +1 -1
  92. package/dist/spec/catalogs/font-schemes/noto-sans-mongolian.json +1 -1
  93. package/dist/spec/catalogs/font-schemes/noto-sans-oriya.json +1 -1
  94. package/dist/spec/catalogs/font-schemes/noto-sans-sc.json +4 -4
  95. package/dist/spec/catalogs/font-schemes/noto-sans-tamil.json +1 -1
  96. package/dist/spec/catalogs/font-schemes/noto-sans-tc.json +1 -1
  97. package/dist/spec/catalogs/font-schemes/noto-sans-telugu.json +1 -1
  98. package/dist/spec/catalogs/font-schemes/noto-sans-thai.json +1 -1
  99. package/dist/spec/catalogs/font-schemes/noto-sans.json +4 -4
  100. package/dist/spec/catalogs/font-schemes/nyala.json +1 -1
  101. package/dist/spec/catalogs/font-schemes/pmingliu.json +1 -1
  102. package/dist/spec/catalogs/font-schemes/raavi.json +1 -1
  103. package/dist/spec/catalogs/font-schemes/sakkal-majalla.json +3 -3
  104. package/dist/spec/catalogs/font-schemes/shonar-bangla.json +2 -2
  105. package/dist/spec/catalogs/font-schemes/shruti.json +1 -1
  106. package/dist/spec/catalogs/font-schemes/simsun.json +1 -1
  107. package/dist/spec/catalogs/font-schemes/sylfaen.json +2 -2
  108. package/dist/spec/catalogs/font-schemes/traditional-arabic.json +3 -3
  109. package/dist/spec/catalogs/font-schemes/tunga.json +1 -1
  110. package/dist/spec/catalogs/font-schemes/vrinda.json +1 -1
  111. package/dist/spec/catalogs/font-schemes/yu-gothic.json +1 -1
  112. package/dist/spec/catalogs/layouts/capability-map.json +1 -4
  113. package/dist/spec/catalogs/layouts/chart-1x-title-center.json +30 -0
  114. package/dist/spec/catalogs/layouts/chart-2x-title-center.json +36 -0
  115. package/dist/spec/catalogs/layouts/chart-2x-vertical-title-left.json +37 -0
  116. package/dist/spec/catalogs/layouts/chart-3x-bottom-vertical-title-left.json +46 -0
  117. package/dist/spec/catalogs/layouts/chart-3x-left-title-center.json +45 -0
  118. package/dist/spec/catalogs/layouts/chart-3x-left.json +40 -0
  119. package/dist/spec/catalogs/layouts/chart-3x-right-title-center.json +45 -0
  120. package/dist/spec/catalogs/layouts/chart-3x-right.json +40 -0
  121. package/dist/spec/catalogs/layouts/chart-3x-title-center.json +39 -0
  122. package/dist/spec/catalogs/layouts/chart-3x-top-vertical-title-left.json +46 -0
  123. package/dist/spec/catalogs/layouts/competitive-landscape.json +1 -4
  124. package/dist/spec/catalogs/layouts/customer-journey.json +1 -4
  125. package/dist/spec/catalogs/layouts/decision-tree.json +1 -4
  126. package/dist/spec/catalogs/layouts/ecosystem-map.json +1 -4
  127. package/dist/spec/catalogs/layouts/extract/canonical.json +0 -9
  128. package/dist/spec/catalogs/layouts/geographic-map.json +1 -4
  129. package/dist/spec/catalogs/layouts/icon-grid.json +1 -4
  130. package/dist/spec/catalogs/layouts/image-1x-crop-title-center.json +32 -0
  131. package/dist/spec/catalogs/layouts/image-1x-crop-title-left.json +32 -0
  132. package/dist/spec/catalogs/layouts/image-1x-crop.json +27 -0
  133. package/dist/spec/catalogs/layouts/image-1x-fit-title-center.json +32 -0
  134. package/dist/spec/catalogs/layouts/image-1x.json +3 -0
  135. package/dist/spec/catalogs/layouts/image-2x-crop-title-center.json +38 -0
  136. package/dist/spec/catalogs/layouts/image-2x-crop-vertical-title-left.json +39 -0
  137. package/dist/spec/catalogs/layouts/image-2x-crop-vertical.json +34 -0
  138. package/dist/spec/catalogs/layouts/image-2x-crop.json +33 -0
  139. package/dist/spec/catalogs/layouts/image-2x-fit-title-center.json +38 -0
  140. package/dist/spec/catalogs/layouts/image-2x-fit-vertical-title-left.json +39 -0
  141. package/dist/spec/catalogs/layouts/image-2x-fit-vertical.json +34 -0
  142. package/dist/spec/catalogs/layouts/image-2x.json +3 -0
  143. package/dist/spec/catalogs/layouts/image-3x-crop-title-center.json +41 -0
  144. package/dist/spec/catalogs/layouts/image-3x-crop-vertical-title-left.json +42 -0
  145. package/dist/spec/catalogs/layouts/image-3x-crop-vertical.json +37 -0
  146. package/dist/spec/catalogs/layouts/image-3x-crop.json +36 -0
  147. package/dist/spec/catalogs/layouts/image-3x-fit-title-center.json +41 -0
  148. package/dist/spec/catalogs/layouts/image-3x-fit-vertical-title-left.json +42 -0
  149. package/dist/spec/catalogs/layouts/image-3x-fit-vertical.json +37 -0
  150. package/dist/spec/catalogs/layouts/image-3x-fit.json +36 -0
  151. package/dist/spec/catalogs/layouts/image-3x.json +3 -0
  152. package/dist/spec/catalogs/layouts/image-focus.json +3 -6
  153. package/dist/spec/catalogs/layouts/image-only-1x-crop-title-center.json +31 -0
  154. package/dist/spec/catalogs/layouts/image-only-1x-fit-title-center.json +31 -0
  155. package/dist/spec/catalogs/layouts/image-only-2x-crop-title-center.json +37 -0
  156. package/dist/spec/catalogs/layouts/image-only-2x-crop-vertical-title-left.json +38 -0
  157. package/dist/spec/catalogs/layouts/image-only-2x-crop-vertical.json +33 -0
  158. package/dist/spec/catalogs/layouts/image-only-2x-fit-title-center.json +37 -0
  159. package/dist/spec/catalogs/layouts/image-only-2x-fit-vertical-title-left.json +38 -0
  160. package/dist/spec/catalogs/layouts/image-only-2x-fit-vertical.json +33 -0
  161. package/dist/spec/catalogs/layouts/image-only-3x-crop-title-center.json +40 -0
  162. package/dist/spec/catalogs/layouts/image-only-3x-crop-vertical-title-left.json +41 -0
  163. package/dist/spec/catalogs/layouts/image-only-3x-crop-vertical.json +36 -0
  164. package/dist/spec/catalogs/layouts/image-only-3x-crop.json +35 -0
  165. package/dist/spec/catalogs/layouts/image-only-3x-fit-title-center.json +40 -0
  166. package/dist/spec/catalogs/layouts/image-only-3x-fit-vertical-title-left.json +41 -0
  167. package/dist/spec/catalogs/layouts/image-only-3x-fit-vertical.json +36 -0
  168. package/dist/spec/catalogs/layouts/image-only-3x-fit.json +35 -0
  169. package/dist/spec/catalogs/layouts/index.json +1041 -151
  170. package/dist/spec/catalogs/layouts/list-1x-box-title-center.json +32 -0
  171. package/dist/spec/catalogs/layouts/list-1x-box-vertical-title-center.json +33 -0
  172. package/dist/spec/catalogs/layouts/list-1x-box-vertical-title-left.json +33 -0
  173. package/dist/spec/catalogs/layouts/list-1x-box-vertical.json +28 -0
  174. package/dist/spec/catalogs/layouts/list-1x-box.json +27 -0
  175. package/dist/spec/catalogs/layouts/list-1x-itemimage-title-center.json +32 -0
  176. package/dist/spec/catalogs/layouts/list-1x-itemimage-vertical-title-center.json +33 -0
  177. package/dist/spec/catalogs/layouts/list-1x-title-center.json +31 -0
  178. package/dist/spec/catalogs/layouts/list-1x-vertical-title-center.json +32 -0
  179. package/dist/spec/catalogs/layouts/list-2x-box-title-center.json +38 -0
  180. package/dist/spec/catalogs/layouts/list-2x-box-vertical-title-center.json +39 -0
  181. package/dist/spec/catalogs/layouts/list-2x-box-vertical-title-left.json +39 -0
  182. package/dist/spec/catalogs/layouts/list-2x-box-vertical.json +34 -0
  183. package/dist/spec/catalogs/layouts/list-2x-box.json +33 -0
  184. package/dist/spec/catalogs/layouts/list-2x-itemimage-title-center.json +38 -0
  185. package/dist/spec/catalogs/layouts/list-2x-itemimage-vertical-title-center.json +39 -0
  186. package/dist/spec/catalogs/layouts/list-2x-itemimage-vertical-title-left.json +39 -0
  187. package/dist/spec/catalogs/layouts/list-2x-itemimage-vertical.json +34 -0
  188. package/dist/spec/catalogs/layouts/list-2x-title-center.json +37 -0
  189. package/dist/spec/catalogs/layouts/list-2x-vertical-title-center.json +38 -0
  190. package/dist/spec/catalogs/layouts/list-2x-vertical-title-left.json +38 -0
  191. package/dist/spec/catalogs/layouts/list-2x-vertical.json +33 -0
  192. package/dist/spec/catalogs/layouts/list-3x-box-title-center.json +41 -0
  193. package/dist/spec/catalogs/layouts/list-3x-box-vertical-title-center.json +42 -0
  194. package/dist/spec/catalogs/layouts/list-3x-box-vertical-title-left.json +42 -0
  195. package/dist/spec/catalogs/layouts/list-3x-box-vertical.json +37 -0
  196. package/dist/spec/catalogs/layouts/list-3x-box.json +36 -0
  197. package/dist/spec/catalogs/layouts/list-3x-itemimage-title-center.json +41 -0
  198. package/dist/spec/catalogs/layouts/list-3x-itemimage-vertical-title-center.json +42 -0
  199. package/dist/spec/catalogs/layouts/list-3x-itemimage-vertical-title-left.json +42 -0
  200. package/dist/spec/catalogs/layouts/list-3x-itemimage-vertical.json +37 -0
  201. package/dist/spec/catalogs/layouts/list-3x-itemimage.json +36 -0
  202. package/dist/spec/catalogs/layouts/list-3x-title-center.json +40 -0
  203. package/dist/spec/catalogs/layouts/list-3x-vertical-title-center.json +41 -0
  204. package/dist/spec/catalogs/layouts/list-3x-vertical-title-left.json +41 -0
  205. package/dist/spec/catalogs/layouts/list-3x-vertical.json +36 -0
  206. package/dist/spec/catalogs/layouts/list-4x-box-title-center.json +45 -0
  207. package/dist/spec/catalogs/layouts/list-4x-box-vertical-title-center.json +45 -0
  208. package/dist/spec/catalogs/layouts/list-4x-box-vertical-title-left.json +45 -0
  209. package/dist/spec/catalogs/layouts/list-4x-box-vertical.json +40 -0
  210. package/dist/spec/catalogs/layouts/list-4x-box.json +40 -0
  211. package/dist/spec/catalogs/layouts/list-4x-itemimage-title-center.json +45 -0
  212. package/dist/spec/catalogs/layouts/list-4x-itemimage-vertical-title-center.json +45 -0
  213. package/dist/spec/catalogs/layouts/list-4x-itemimage-vertical-title-left.json +45 -0
  214. package/dist/spec/catalogs/layouts/list-4x-itemimage-vertical.json +40 -0
  215. package/dist/spec/catalogs/layouts/list-4x-title-center.json +44 -0
  216. package/dist/spec/catalogs/layouts/list-4x-vertical-title-center.json +44 -0
  217. package/dist/spec/catalogs/layouts/list-4x-vertical-title-left.json +44 -0
  218. package/dist/spec/catalogs/layouts/list-4x-vertical.json +39 -0
  219. package/dist/spec/catalogs/layouts/list-5x-box-title-center.json +48 -0
  220. package/dist/spec/catalogs/layouts/list-5x-box-vertical-title-center.json +50 -0
  221. package/dist/spec/catalogs/layouts/list-5x-box-vertical-title-left.json +50 -0
  222. package/dist/spec/catalogs/layouts/list-5x-box-vertical.json +45 -0
  223. package/dist/spec/catalogs/layouts/list-5x-box.json +43 -0
  224. package/dist/spec/catalogs/layouts/list-5x-itemimage-title-center.json +48 -0
  225. package/dist/spec/catalogs/layouts/list-5x-itemimage-vertical-title-center.json +48 -0
  226. package/dist/spec/catalogs/layouts/list-5x-itemimage-vertical-title-left.json +48 -0
  227. package/dist/spec/catalogs/layouts/list-5x-itemimage-vertical.json +43 -0
  228. package/dist/spec/catalogs/layouts/list-5x-title-center.json +47 -0
  229. package/dist/spec/catalogs/layouts/list-5x-vertical-title-center.json +47 -0
  230. package/dist/spec/catalogs/layouts/list-5x-vertical-title-left.json +47 -0
  231. package/dist/spec/catalogs/layouts/list-5x-vertical.json +42 -0
  232. package/dist/spec/catalogs/layouts/list-6x-box-title-center.json +51 -0
  233. package/dist/spec/catalogs/layouts/list-6x-box-vertical-title-center.json +53 -0
  234. package/dist/spec/catalogs/layouts/list-6x-box-vertical-title-left.json +53 -0
  235. package/dist/spec/catalogs/layouts/list-6x-box-vertical.json +48 -0
  236. package/dist/spec/catalogs/layouts/list-6x-box.json +46 -0
  237. package/dist/spec/catalogs/layouts/list-6x-itemimage-title-center.json +51 -0
  238. package/dist/spec/catalogs/layouts/list-6x-itemimage-vertical-title-center.json +51 -0
  239. package/dist/spec/catalogs/layouts/list-6x-itemimage-vertical-title-left.json +51 -0
  240. package/dist/spec/catalogs/layouts/list-6x-itemimage-vertical.json +46 -0
  241. package/dist/spec/catalogs/layouts/list-6x-title-center.json +50 -0
  242. package/dist/spec/catalogs/layouts/list-6x-vertical-title-center.json +50 -0
  243. package/dist/spec/catalogs/layouts/list-6x-vertical-title-left.json +50 -0
  244. package/dist/spec/catalogs/layouts/list-6x-vertical.json +45 -0
  245. package/dist/spec/catalogs/layouts/network-dependency-map.json +1 -4
  246. package/dist/spec/catalogs/layouts/number-1x-box-title-center.json +30 -0
  247. package/dist/spec/catalogs/layouts/number-1x-box.json +25 -0
  248. package/dist/spec/catalogs/layouts/number-1x-title-center.json +29 -0
  249. package/dist/spec/catalogs/layouts/number-2x-box-title-center.json +36 -0
  250. package/dist/spec/catalogs/layouts/number-2x-box.json +31 -0
  251. package/dist/spec/catalogs/layouts/number-2x-title-center.json +35 -0
  252. package/dist/spec/catalogs/layouts/number-3x-box-title-center.json +39 -0
  253. package/dist/spec/catalogs/layouts/number-3x-box.json +34 -0
  254. package/dist/spec/catalogs/layouts/number-3x-title-center.json +38 -0
  255. package/dist/spec/catalogs/layouts/number-4x-box-title-center.json +43 -0
  256. package/dist/spec/catalogs/layouts/number-4x-box.json +38 -0
  257. package/dist/spec/catalogs/layouts/number-4x-title-center.json +42 -0
  258. package/dist/spec/catalogs/layouts/number-5x-box-title-center.json +46 -0
  259. package/dist/spec/catalogs/layouts/number-5x-box.json +41 -0
  260. package/dist/spec/catalogs/layouts/number-5x-title-center.json +45 -0
  261. package/dist/spec/catalogs/layouts/number-6x-box-title-center.json +49 -0
  262. package/dist/spec/catalogs/layouts/number-6x-box.json +44 -0
  263. package/dist/spec/catalogs/layouts/number-6x-title-center.json +48 -0
  264. package/dist/spec/catalogs/layouts/persona-grid.json +1 -4
  265. package/dist/spec/catalogs/layouts/photo-grid.json +1 -4
  266. package/dist/spec/catalogs/layouts/product-feature.json +1 -4
  267. package/dist/spec/catalogs/layouts/screenshot-walkthrough.json +1 -4
  268. package/dist/spec/catalogs/layouts/swimlane-process.json +1 -4
  269. package/dist/spec/catalogs/layouts/team-bio.json +1 -4
  270. package/dist/spec/catalogs/layouts/text-1x-box-title-center.json +31 -0
  271. package/dist/spec/catalogs/layouts/text-1x-box-title-left.json +31 -0
  272. package/dist/spec/catalogs/layouts/text-1x-center-box-title-center.json +31 -0
  273. package/dist/spec/catalogs/layouts/text-1x-center-box-title-left.json +31 -0
  274. package/dist/spec/catalogs/layouts/text-1x-center-box.json +26 -0
  275. package/dist/spec/catalogs/layouts/text-1x-center-title-center.json +30 -0
  276. package/dist/spec/catalogs/layouts/text-1x-center-title-left.json +30 -0
  277. package/dist/spec/catalogs/layouts/text-1x-center.json +25 -0
  278. package/dist/spec/catalogs/layouts/text-1x-left-box.json +26 -0
  279. package/dist/spec/catalogs/layouts/text-1x-title-center.json +30 -0
  280. package/dist/spec/catalogs/layouts/text-2x-box-title-center.json +37 -0
  281. package/dist/spec/catalogs/layouts/text-2x-box-vertical-title-left.json +37 -0
  282. package/dist/spec/catalogs/layouts/text-2x-center-box-title-center.json +37 -0
  283. package/dist/spec/catalogs/layouts/text-2x-center-box-vertical-title-left.json +37 -0
  284. package/dist/spec/catalogs/layouts/text-2x-center-box.json +32 -0
  285. package/dist/spec/catalogs/layouts/text-2x-center-title-center.json +36 -0
  286. package/dist/spec/catalogs/layouts/text-2x-center-vertical-title-left.json +36 -0
  287. package/dist/spec/catalogs/layouts/text-2x-center.json +31 -0
  288. package/dist/spec/catalogs/layouts/text-2x-left-box.json +32 -0
  289. package/dist/spec/catalogs/layouts/text-2x-title-center.json +36 -0
  290. package/dist/spec/catalogs/layouts/text-2x-vertical-title-left.json +36 -0
  291. package/dist/spec/catalogs/layouts/text-3x-box-title-center.json +40 -0
  292. package/dist/spec/catalogs/layouts/text-3x-box-vertical-title-left.json +41 -0
  293. package/dist/spec/catalogs/layouts/text-3x-center-box-title-center.json +40 -0
  294. package/dist/spec/catalogs/layouts/text-3x-center-box-vertical-title-left.json +41 -0
  295. package/dist/spec/catalogs/layouts/text-3x-center-box.json +35 -0
  296. package/dist/spec/catalogs/layouts/text-3x-center-title-center.json +39 -0
  297. package/dist/spec/catalogs/layouts/text-3x-center-vertical-title-left.json +40 -0
  298. package/dist/spec/catalogs/layouts/text-3x-center.json +34 -0
  299. package/dist/spec/catalogs/layouts/text-3x-left-box.json +35 -0
  300. package/dist/spec/catalogs/layouts/text-3x-left.json +34 -0
  301. package/dist/spec/catalogs/layouts/text-3x-title-center.json +39 -0
  302. package/dist/spec/catalogs/layouts/text-3x-vertical-title-left.json +40 -0
  303. package/dist/spec/catalogs/layouts/title-center-box.json +27 -0
  304. package/dist/spec/catalogs/layouts/title-center-image-bottom.json +34 -0
  305. package/dist/spec/catalogs/layouts/title-center-image-top.json +34 -0
  306. package/dist/spec/catalogs/layouts/title-center.json +26 -0
  307. package/dist/spec/catalogs/layouts/title-left-image-bottom.json +34 -0
  308. package/dist/spec/catalogs/layouts/title-left-image-left.json +34 -0
  309. package/dist/spec/catalogs/layouts/title-left-image-right.json +34 -0
  310. package/dist/spec/catalogs/layouts/title-left-image-top.json +34 -0
  311. package/dist/spec/catalogs/manifest.json +18 -18
  312. package/dist/spec/catalogs/narratives/heros-journey.json +1 -1
  313. package/dist/spec/catalogs/narratives/index.json +1 -1
  314. package/dist/spec/openapi.yaml +3 -3
  315. package/dist/spec/reference/engine-defaults.json +22 -30
  316. package/dist/spec/reference/engine-vocabularies.json +1577 -0
  317. package/dist/spec/schemas/audience.schema.json +5 -26
  318. package/dist/spec/schemas/catalog-manifest.schema.json +3 -3
  319. package/dist/spec/schemas/chart-type.schema.json +2 -35
  320. package/dist/spec/schemas/color-scheme.schema.json +3 -24
  321. package/dist/spec/schemas/finding.schema.json +1 -1
  322. package/dist/spec/schemas/font-scheme.schema.json +6 -37
  323. package/dist/spec/schemas/language.schema.json +7 -28
  324. package/dist/spec/schemas/layout.schema.json +56 -51
  325. package/dist/spec/schemas/narrative.schema.json +4 -24
  326. package/dist/spec/schemas/opf.schema.json +399 -368
  327. package/dist/spec/schemas/purpose.schema.json +5 -26
  328. package/dist/spec/schemas/social-platform.schema.json +2 -23
  329. package/dist/spec/schemas/theme.schema.json +9 -37
  330. package/dist/spec/schemas/tone.schema.json +4 -25
  331. package/dist/spec-files.d.ts +1 -1
  332. package/dist/spec-files.js +1 -1
  333. package/dist/types.d.ts +1125 -4
  334. package/dist/{validation-types-zh03LeZy.d.ts → validation-types-BOcY9GTs.d.ts} +7 -7
  335. package/dist/validator.d.ts +15 -12
  336. package/dist/validator.js +5 -5
  337. package/dist/yaml.d.ts +22 -7
  338. package/dist/yaml.js +10 -9
  339. package/package.json +5 -9
  340. package/dist/catalogs-D-yyQWCQ.d.ts +0 -1343
  341. package/dist/catalogs.d.ts +0 -2
  342. package/dist/catalogs.js +0 -2
  343. package/dist/chunk-PIQXLBBJ.js +0 -445
  344. package/dist/chunk-S5W34SIJ.js +0 -1
  345. package/dist/previews.d.ts +0 -40
  346. package/dist/previews.js +0 -1
  347. package/dist/schemas-DDpqAgyS.d.ts +0 -284
  348. package/dist/spec/catalogs/layouts/image-bleed.json +0 -20
@@ -1,6 +1,7 @@
1
- import { promotedRegionKeys, VARIABLE_KINDS, resolveChartData, chartPaletteForFill, tableGrid, timelineTextColor, visitContentPayloads, readingRows, visualReadingOrder, intrinsicImageSize, textWidthMeasurer, normalizeHexColor, resolveColorRef, resolveFontSchemeReference, DEFAULT_FONT_SCHEME, resolveColorRoles, resolveFontFamilies, resolveCanvasDimensions, defaultSlideBackground, isRecord, hasContentVariables, isTemplate, instantiateForValidation, unusedDatasets, MAX_COMPOSITION_DEPTH, datasetDiagnostics, pathFor, collectCitations, numberingFindings, walkCitationRuns, resolveTableData, bareIdPattern, resolveChartOptions, chartOptionTarget, codeHighlightLines, chartNumberFixesByCell, OPFCompositionError, composeSlide, resolveScriptFonts } from './chunk-6OXY2CP3.js';
2
- import { catalogs, catalogKinds, catalogEntries, catalogSchemaNames, themes } from './chunk-XOZ4KMSR.js';
3
- import { schemaEntries, schemas } from './chunk-LS2FMPI5.js';
1
+ import { promotedRegionKeys, VARIABLE_KINDS, resolveChartData, chartPaletteForFill, imageBackground, tableGrid, timelineTextColor, visitContentPayloads, readingRows, visualReadingOrder, intrinsicImageSize, textWidthMeasurer, normalizeHexColor, resolveColorRef, resolveDesignRecords, resolveColorRoles, resolveFontFamilies, resolveCanvasDimensions, defaultSlideBackground, isRecord, hasContentVariables, isTemplate, instantiateForValidation, unusedDatasets, MAX_COMPOSITION_DEPTH, datasetDiagnostics, pathFor, collectCitations, numberingFindings, walkCitationRuns, resolveTableData, resolveChartOptions, chartOptionTarget, codeHighlightLines, chartNumberFixesByCell, OPFCompositionError, composeSlide, resolveScriptFonts } from './chunk-O744SXXA.js';
2
+ import { catalogSchemaNames } from './chunk-TRDXRRQK.js';
3
+ import { resolveReference, checkCatalogsOption, provenanceOf, unresolvedReference, OPFUnresolvedReferenceError, catalogReferenceSites, parseReference, catalogGroupDeclared, pointerPath, catalogRecords, catalogKinds, catalogGroupSource, registeredCatalog } from './chunk-SPFV27O5.js';
4
+ import { schemaEntries, schemas } from './chunk-2CJPC4HI.js';
4
5
  import Ajv2020 from 'ajv/dist/2020.js';
5
6
  import addFormats from 'ajv-formats';
6
7
  import { parseTree, printParseErrorCode, getNodePath } from 'jsonc-parser';
@@ -71,450 +72,6 @@ function unusedReferenceWarnings(value) {
71
72
  return value.references.flatMap((reference, index) => isRecord(reference) && typeof reference.id === "string" && unused.includes(reference.id) ? [issue(`/references/${index}`, `reference '${reference.id}' is never cited; cite it with a run's cite field or remove it`, { code: "unused-reference", id: reference.id })] : []);
72
73
  }
73
74
 
74
- // src/generated/catalog-ids.ts
75
- var catalogIds = {
76
- audiences: [
77
- "board",
78
- "engineering-team",
79
- "all-hands",
80
- "candidates",
81
- "executive",
82
- "investor",
83
- "technical",
84
- "sales",
85
- "marketing",
86
- "academic",
87
- "internal-team",
88
- "customer",
89
- "general-public",
90
- "media",
91
- "partner",
92
- "regulatory"
93
- ],
94
- purposes: [
95
- "inform",
96
- "decide",
97
- "align",
98
- "persuade",
99
- "educate",
100
- "report",
101
- "pitch",
102
- "sell",
103
- "plan"
104
- ],
105
- tones: [
106
- "formal",
107
- "casual",
108
- "inspirational",
109
- "technical",
110
- "persuasive",
111
- "authoritative",
112
- "conversational"
113
- ],
114
- themes: [
115
- "minimal",
116
- "classic",
117
- "dark",
118
- "bold"
119
- ],
120
- layouts: [
121
- "blank",
122
- "chart-1x",
123
- "chart-2x",
124
- "chart-3x",
125
- "code-1x",
126
- "image-1x",
127
- "image-2x",
128
- "image-3x",
129
- "image-bleed",
130
- "list-1x",
131
- "list-2x",
132
- "list-3x",
133
- "list-4x",
134
- "list-5x",
135
- "list-6x",
136
- "media-1x",
137
- "number-1x",
138
- "number-2x",
139
- "number-3x",
140
- "number-4x",
141
- "number-5x",
142
- "number-6x",
143
- "quote-1x",
144
- "table-1x",
145
- "text-1x",
146
- "text-2x",
147
- "text-3x",
148
- "timeline-1x",
149
- "title",
150
- "title-subtitle",
151
- "title-slide",
152
- "two-column",
153
- "image-focus",
154
- "data-visualization",
155
- "quote-highlight",
156
- "section-divider",
157
- "agenda",
158
- "thank-you-cta",
159
- "bullet-list",
160
- "three-column",
161
- "icon-grid",
162
- "faq",
163
- "stats-metrics",
164
- "comparison",
165
- "swot-analysis",
166
- "matrix-quadrant",
167
- "funnel-pyramid",
168
- "timeline",
169
- "process-flow",
170
- "photo-grid",
171
- "before-after",
172
- "testimonial-grid",
173
- "team-bio",
174
- "pricing-table",
175
- "roadmap",
176
- "product-feature",
177
- "executive-summary",
178
- "key-takeaway",
179
- "chapter-recap",
180
- "qa-discussion",
181
- "single-message-statement",
182
- "one-column-explainer",
183
- "case-study",
184
- "pros-cons",
185
- "feature-comparison-matrix",
186
- "venn-overlap",
187
- "decision-tree",
188
- "kpi-scorecard",
189
- "dashboard",
190
- "waterfall-bridge",
191
- "benchmark-target-table",
192
- "heatmap-cohort",
193
- "risk-heatmap",
194
- "forecast-scenario",
195
- "swimlane-process",
196
- "gantt-project-plan",
197
- "circular-lifecycle",
198
- "customer-journey",
199
- "org-chart",
200
- "capability-map",
201
- "logic-tree",
202
- "hub-and-spoke",
203
- "architecture-stack",
204
- "ecosystem-map",
205
- "network-dependency-map",
206
- "wheel-radial",
207
- "geographic-map",
208
- "screenshot-walkthrough",
209
- "market-size",
210
- "persona-grid",
211
- "competitive-landscape",
212
- "business-model-canvas",
213
- "customer-logos",
214
- "executive-decision",
215
- "status-rag",
216
- "raci-matrix",
217
- "action-plan",
218
- "assumptions-dependencies",
219
- "appendix-index",
220
- "detailed-data-table"
221
- ],
222
- chartTypes: [
223
- "100pct-stacked-area",
224
- "100pct-stacked-bar",
225
- "100pct-stacked-column",
226
- "area",
227
- "bar",
228
- "box-and-whisker",
229
- "column",
230
- "combo",
231
- "doughnut",
232
- "filled-radar",
233
- "funnel",
234
- "histogram",
235
- "line",
236
- "line-with-markers",
237
- "pareto",
238
- "pie",
239
- "radar",
240
- "radar-with-markers",
241
- "scatter",
242
- "stacked-area",
243
- "stacked-bar",
244
- "stacked-column",
245
- "stacked-line",
246
- "stacked-line-with-markers",
247
- "treemap",
248
- "waterfall",
249
- "world"
250
- ],
251
- narratives: [
252
- "problem-solution",
253
- "scqa",
254
- "pyramid-principle",
255
- "situation-complication-resolution",
256
- "what-so-what-now-what",
257
- "strategic-narrative",
258
- "golden-circle",
259
- "conference-talk",
260
- "transformation-arc",
261
- "pitch-deck",
262
- "early-startup-pitch",
263
- "venture-pitch",
264
- "persuasive-sales",
265
- "sparkline",
266
- "company-intro",
267
- "marketing-strategy",
268
- "product-launch",
269
- "strategic-advisory",
270
- "challenge-resolution",
271
- "project-proposal",
272
- "vision-roadmap",
273
- "failure-analysis",
274
- "star-method",
275
- "classic-story",
276
- "heros-journey",
277
- "business-narrative",
278
- "change-story",
279
- "rags-to-riches",
280
- "underdog-victory",
281
- "survival-story",
282
- "educate",
283
- "persuade",
284
- "reveal",
285
- "justice",
286
- "innovation",
287
- "focus",
288
- "qbr",
289
- "business-review",
290
- "board-meeting",
291
- "weekly-progress",
292
- "status-update",
293
- "performance-review",
294
- "survey-analysis",
295
- "trend-analysis",
296
- "data-story",
297
- "employee-review",
298
- "performance-improvement-plan",
299
- "capacity-planning"
300
- ],
301
- socialPlatforms: [
302
- "linkedin",
303
- "x",
304
- "github",
305
- "youtube",
306
- "instagram",
307
- "facebook",
308
- "tiktok",
309
- "threads",
310
- "mastodon",
311
- "bluesky"
312
- ],
313
- languages: [
314
- "afrikaans",
315
- "albanian",
316
- "amharic",
317
- "arabic",
318
- "armenian",
319
- "aymara",
320
- "azerbaijani",
321
- "bengali",
322
- "berber-latin",
323
- "bosnian-latin",
324
- "bulgarian",
325
- "catalan",
326
- "cebuano",
327
- "chinese-simplified",
328
- "chinese-traditional",
329
- "chittagonian",
330
- "croatian",
331
- "czech",
332
- "danish",
333
- "dutch",
334
- "english",
335
- "english-au",
336
- "english-ca",
337
- "english-gb",
338
- "english-in",
339
- "english-us",
340
- "estonian",
341
- "filipino",
342
- "finnish",
343
- "french",
344
- "fulfulde",
345
- "galician",
346
- "georgian",
347
- "german",
348
- "greek",
349
- "gujarati",
350
- "hausa",
351
- "hebrew",
352
- "hindi",
353
- "hungarian",
354
- "igbo",
355
- "indonesian",
356
- "italian",
357
- "japanese",
358
- "kannada",
359
- "kazakh",
360
- "khmer",
361
- "kinyarwanda",
362
- "korean",
363
- "kurmanji",
364
- "latvian",
365
- "lithuanian",
366
- "macedonian",
367
- "malagasy",
368
- "malay",
369
- "malayalam",
370
- "maori",
371
- "marathi",
372
- "mongolian",
373
- "nepali",
374
- "norwegian",
375
- "odia",
376
- "oromo",
377
- "pashto",
378
- "persian",
379
- "polish",
380
- "portuguese",
381
- "punjabi-gurmukhi",
382
- "punjabi-shahmukhi",
383
- "romanian",
384
- "russian",
385
- "serbian-cyrillic",
386
- "serbian-latin",
387
- "shona",
388
- "slovak",
389
- "slovenian",
390
- "somali",
391
- "spanish",
392
- "swahili",
393
- "swedish",
394
- "tagalog",
395
- "tajik",
396
- "tamil",
397
- "telugu",
398
- "thai",
399
- "turkish",
400
- "ukrainian",
401
- "urdu",
402
- "uzbek-latin",
403
- "vietnamese-quoc-ngu",
404
- "xhosa",
405
- "yoruba",
406
- "zulu"
407
- ],
408
- colorSchemes: [
409
- "black-and-white",
410
- "bold-red",
411
- "boost",
412
- "burnt-orange",
413
- "cool-horizon",
414
- "corporate-blue",
415
- "deep-purple",
416
- "forest-green",
417
- "golden-yellow",
418
- "luxury",
419
- "pastel-red",
420
- "slate-gray",
421
- "steel-blue",
422
- "vibes"
423
- ],
424
- fontSchemes: [
425
- "consolas",
426
- "courier-new",
427
- "arial",
428
- "calibri",
429
- "impact",
430
- "lucida-sans",
431
- "segoe-ui",
432
- "segoe-ui-light",
433
- "tahoma",
434
- "trebuchet-ms",
435
- "verdana",
436
- "bookman",
437
- "century-schoolbook",
438
- "constantia",
439
- "garamond",
440
- "rockwell",
441
- "times-new-roman",
442
- "aptos",
443
- "grandview",
444
- "seaford",
445
- "skeena",
446
- "tenorite",
447
- "georgia",
448
- "microsoft-yahei",
449
- "simsun",
450
- "fangsong",
451
- "yu-gothic",
452
- "pmingliu",
453
- "mingliu",
454
- "ms-mincho",
455
- "malgun-gothic",
456
- "batang",
457
- "gungsuh",
458
- "mangal",
459
- "nirmala-ui",
460
- "latha",
461
- "david",
462
- "miriam",
463
- "gisha",
464
- "vrinda",
465
- "shruti",
466
- "tunga",
467
- "kartika",
468
- "kalinga",
469
- "raavi",
470
- "gautami",
471
- "arabic-typesetting",
472
- "microsoft-jhenghei",
473
- "meiryo",
474
- "angsana-new",
475
- "aparajita",
476
- "dilleniaupc",
477
- "sakkal-majalla",
478
- "shonar-bangla",
479
- "sylfaen",
480
- "traditional-arabic",
481
- "montserrat",
482
- "open-sans",
483
- "poppins",
484
- "pt-serif",
485
- "raleway",
486
- "roboto",
487
- "noto-sans-arabic",
488
- "noto-sans-armenian",
489
- "noto-sans-bengali",
490
- "noto-sans-devangari",
491
- "noto-sans-georgian",
492
- "noto-sans-gujarati",
493
- "noto-sans-gurmukhi",
494
- "noto-sans-hebrew",
495
- "noto-sans-jp",
496
- "noto-sans-kannada",
497
- "noto-sans-kr",
498
- "noto-sans-malayalam",
499
- "noto-sans-mongolian",
500
- "noto-sans-oriya",
501
- "noto-sans-sc",
502
- "noto-sans-tamil",
503
- "noto-sans-tc",
504
- "noto-sans-telugu",
505
- "noto-sans",
506
- "noto-sans-thai",
507
- "noto-nastaliq-urdu",
508
- "noto-naksh-arabic",
509
- "noto-sans-ethiopic",
510
- "noto-sans-khmer",
511
- "nyala",
512
- "daunpenh",
513
- "khmer-ui"
514
- ]
515
- };
516
- var deprecatedCatalogIds = {};
517
-
518
75
  // src/validation-definitions.ts
519
76
  var schemaLocations;
520
77
  var issueLocations = /* @__PURE__ */ new WeakMap();
@@ -618,6 +175,7 @@ var contentKindSpecs = {
618
175
  }
619
176
  };
620
177
  var captionableKinds = /* @__PURE__ */ new Set(["image", "chart", "table", "video"]);
178
+ var imageOptionFields = ["fit", "focus", "aspectRatio", "shape", "cornerRadius", "border", "opacity", "recolor", "overlay", "placement"];
621
179
  var columnSpans = {
622
180
  left: [0],
623
181
  center: [1],
@@ -733,15 +291,31 @@ function validateContentPayload(value, path, options = {}) {
733
291
  const payloadFields = presentFields(value, rootPayloadFields);
734
292
  const hasBlocks = hasOwn(value, "blocks");
735
293
  const captionIssue = (reason, params = {}) => semanticIssue(pathFor(path, "caption"), `caption is only valid on an image, chart, table or video payload; ${reason}`, { code: "caption-unsupported-payload", ...params });
294
+ const imageOptionIssues = (reason, params = {}) => {
295
+ for (const field of imageOptionFields) if (hasOwn(value, field)) issues.push(semanticIssue(pathFor(path, field), `${field} is only valid on an image payload; ${reason}`, { code: "image-option-unsupported-payload", field, ...params }));
296
+ };
297
+ if (hasOwn(value, "placement") && !options.topLevel && !hasBlocks && explicitType !== "group" && inferredKinds(value).includes("image")) {
298
+ issues.push(semanticIssue(pathFor(path, "placement"), "placement is only valid on a top-level block (slides.N.blocks.I); a block inside a group or a promoted region cannot bleed to a slide edge", { code: "image-placement-invalid" }));
299
+ }
736
300
  if (hasBlocks || explicitType === "group") {
737
301
  if (hasOwn(value, "caption")) issues.push(captionIssue("a group cannot carry one"));
302
+ imageOptionIssues("a group cannot carry them");
738
303
  if (explicitType !== void 0 && explicitType !== "group") issues.push(semanticIssue(path, "a group must use type 'group' or omit type"));
739
304
  const incompatible2 = payloadFields.filter((field) => field !== "blocks" && field !== "type");
740
305
  if (incompatible2.length) issues.push(semanticIssue(path, "blocks cannot be mixed with leaf payload fields", { fields: incompatible2 }));
741
306
  if (!Array.isArray(value.blocks) || value.blocks.length === 0 && !options.slideRoot) issues.push(semanticIssue(pathFor(path, "blocks"), "a group requires at least one block"));
742
307
  if (Array.isArray(value.blocks)) value.blocks.forEach((block, index) => {
743
- if (isRecord(block)) issues.push(...validateContentPayload(block, `${pathFor(path, "blocks")}/${index}`));
308
+ if (isRecord(block)) issues.push(...validateContentPayload(block, `${pathFor(path, "blocks")}/${index}`, { topLevel: options.slideRoot === true }));
744
309
  });
310
+ if (options.slideRoot && Array.isArray(value.blocks)) {
311
+ const edges = /* @__PURE__ */ new Map();
312
+ value.blocks.forEach((block, index) => {
313
+ const edge = isRecord(block) && isRecord(block.placement) ? block.placement.edge : void 0;
314
+ if (edge === void 0) return;
315
+ if (edges.has(edge)) issues.push(semanticIssue(`${pathFor(path, "blocks")}/${index}/placement/edge`, `blocks ${edges.get(edge)} and ${index} are both placed on the ${String(edge)} edge; a slide edge takes at most one placed image`, { code: "image-placement-invalid", edge, blocks: [edges.get(edge), index] }));
316
+ else edges.set(edge, index);
317
+ });
318
+ }
745
319
  return issues;
746
320
  }
747
321
  if (hasOwn(value, "composition") && !options.slideRoot) issues.push(semanticIssue(pathFor(path, "composition"), "composition is only valid on a group containing blocks"));
@@ -774,6 +348,7 @@ function validateContentPayload(value, path, options = {}) {
774
348
  }
775
349
  const spec = contentKindSpecs[resolvedKind];
776
350
  if (hasOwn(value, "caption") && !captionableKinds.has(resolvedKind)) issues.push(captionIssue(`this payload is '${resolvedKind}'`, { type: resolvedKind }));
351
+ if (resolvedKind !== "image") imageOptionIssues(`this payload is '${resolvedKind}'`, { type: resolvedKind });
777
352
  const allowedFields = /* @__PURE__ */ new Set([
778
353
  "type",
779
354
  ...spec.fields
@@ -937,77 +512,6 @@ function presentationSemanticIssues(value) {
937
512
  issues.push(...annotationIssues(value));
938
513
  return issues;
939
514
  }
940
- function inlineCatalogEntry(context, kind) {
941
- const catalogsField = context.document.catalogs;
942
- if (!isRecord(catalogsField)) {
943
- return void 0;
944
- }
945
- const entry = catalogsField[kind];
946
- return isRecord(entry) ? entry : void 0;
947
- }
948
- function unknownIdWarning(kind, value, path, context) {
949
- if (typeof value !== "string" || !bareIdPattern.test(value)) {
950
- return void 0;
951
- }
952
- if (context) {
953
- const entry = inlineCatalogEntry(context, kind);
954
- if (entry) {
955
- const inline = Array.isArray(entry.records) ? entry.records.find((record) => isRecord(record) && record.id === value) : void 0;
956
- if (isRecord(inline)) {
957
- const replacedBy = isRecord(inline.deprecation) ? inline.deprecation.replacedBy : void 0;
958
- return typeof replacedBy === "string" ? deprecatedIdWarning(kind, value, replacedBy, path) : void 0;
959
- }
960
- if (typeof entry.source === "string" || Array.isArray(entry.source) && entry.source.length > 0) {
961
- return void 0;
962
- }
963
- }
964
- }
965
- if (catalogIds[kind].includes(value)) {
966
- const replacedBy = deprecatedCatalogIds[`${kind}/${value}`];
967
- return replacedBy === void 0 ? void 0 : deprecatedIdWarning(kind, value, replacedBy, path);
968
- }
969
- return semanticIssue(path, `unknown ${kind} catalog id '${value}'`, { kind, id: value });
970
- }
971
- function deprecatedIdWarning(kind, id, replacedBy, path) {
972
- return semanticIssue(path, `deprecated ${kind} catalog id '${id}'; use '${replacedBy}'`, { kind, id, replacedBy });
973
- }
974
- function referenceObjectWarning(kind, value, path, context) {
975
- if (typeof value === "string") {
976
- return unknownIdWarning(kind, value, path, context);
977
- }
978
- if (isRecord(value)) {
979
- return unknownIdWarning(kind, value.id, pathFor(path, "id"), context);
980
- }
981
- return void 0;
982
- }
983
- function pushIfDefined(issues, issue2) {
984
- if (issue2) {
985
- issues.push(issue2);
986
- }
987
- }
988
- function designReferenceWarnings(design, path, context) {
989
- if (!isRecord(design)) {
990
- return [];
991
- }
992
- const issues = [];
993
- pushIfDefined(issues, referenceObjectWarning("themes", design.theme, pathFor(path, "theme"), context));
994
- pushIfDefined(issues, referenceObjectWarning("colorSchemes", design.colorScheme, pathFor(path, "colorScheme"), context));
995
- pushIfDefined(issues, referenceObjectWarning("fontSchemes", design.fontScheme, pathFor(path, "fontScheme"), context));
996
- if (isRecord(design.theme)) {
997
- const themePath = pathFor(path, "theme");
998
- pushIfDefined(issues, referenceObjectWarning("colorSchemes", design.theme.colorScheme, pathFor(themePath, "colorScheme"), context));
999
- pushIfDefined(issues, referenceObjectWarning("fontSchemes", design.theme.fontScheme, pathFor(themePath, "fontScheme"), context));
1000
- }
1001
- return issues;
1002
- }
1003
- function themeOf(reference, context) {
1004
- const id = typeof reference === "string" ? reference : isRecord(reference) ? reference.id : void 0;
1005
- const entry = inlineCatalogEntry(context, "themes");
1006
- const inline = typeof id === "string" && Array.isArray(entry?.records) ? entry.records.find((record) => isRecord(record) && record.id === id) : void 0;
1007
- const base = isRecord(inline) ? inline : typeof id === "string" ? themes.find((record) => isRecord(record) && record.id === id) : void 0;
1008
- if (isRecord(reference)) return { ...base ?? {}, ...reference };
1009
- return base;
1010
- }
1011
515
  function canvasSize(dimensions) {
1012
516
  try {
1013
517
  const { width, height } = resolveCanvasDimensions(dimensions);
@@ -1016,15 +520,16 @@ function canvasSize(dimensions) {
1016
520
  return "invalid";
1017
521
  }
1018
522
  }
1019
- function slideThemeDimensionsWarnings(document, slide, slidePath, context) {
523
+ function slideThemeDimensionsWarnings(document, slide, index, catalogs) {
524
+ const slidePath = `/slides/${index}`;
1020
525
  const slideDesign = isRecord(slide.design) ? slide.design : void 0;
1021
- if (!slideDesign || slideDesign.theme === void 0) return [];
1022
- const slideTheme = themeOf(slideDesign.theme, context);
1023
- if (!slideTheme || slideTheme.dimensions === void 0) return [];
526
+ if (!slideDesign || typeof slideDesign.theme !== "string") return [];
527
+ const options = { catalogs: catalogs ?? [] };
528
+ const slideTheme = resolveDesignRecords(document, index, options);
529
+ if (slideTheme.diagnostics.some((diagnostic) => diagnostic.kind === "themes") || slideTheme.theme.dimensions === void 0) return [];
1024
530
  const deckDesign = isRecord(document.design) ? document.design : {};
1025
- const deckTheme = themeOf(deckDesign.theme ?? "minimal", context);
1026
- const deckDimensions = deckDesign.dimensions ?? deckTheme?.dimensions;
1027
- const slideSize = canvasSize(slideTheme.dimensions);
531
+ const deckDimensions = deckDesign.dimensions ?? resolveDesignRecords(document, void 0, options).theme.dimensions;
532
+ const slideSize = canvasSize(slideTheme.theme.dimensions);
1028
533
  const deckSize = canvasSize(deckDimensions);
1029
534
  if (slideSize === deckSize) return [];
1030
535
  const explicit = deckDesign.dimensions !== void 0;
@@ -1034,20 +539,19 @@ function slideThemeDimensionsWarnings(document, slide, slidePath, context) {
1034
539
  { code: "slide-theme-dimensions", slideDimensions: slideSize, deckDimensions: deckSize }
1035
540
  )];
1036
541
  }
1037
- function chartTypeWarnings(payload, path, context) {
542
+ function chartTypeWarnings(payload, path) {
1038
543
  if (!isRecord(payload)) {
1039
544
  return [];
1040
545
  }
1041
546
  const issues = [];
1042
547
  if (isRecord(payload.chart)) {
1043
- pushIfDefined(issues, unknownIdWarning("chartTypes", payload.chart.type, `${pathFor(path, "chart")}/type`, context));
1044
548
  for (const diagnostic of resolveChartOptions(payload.chart, chartOptionTarget(payload.chart.type)).diagnostics) {
1045
549
  issues.push(semanticIssue(diagnostic.option.split(".").reduce(pathFor, pathFor(path, "chart")), diagnostic.message, { code: diagnostic.code, option: diagnostic.option, reason: diagnostic.reason }));
1046
550
  }
1047
551
  }
1048
552
  if (Array.isArray(payload.blocks)) {
1049
553
  payload.blocks.forEach((block, index) => {
1050
- issues.push(...chartTypeWarnings(block, `${pathFor(path, "blocks")}/${index}`, context));
554
+ issues.push(...chartTypeWarnings(block, `${pathFor(path, "blocks")}/${index}`));
1051
555
  });
1052
556
  }
1053
557
  return issues;
@@ -1216,34 +720,19 @@ function variableReferenceWarnings(value) {
1216
720
  });
1217
721
  return issues;
1218
722
  }
1219
- function presentationReferenceWarnings(value) {
723
+ function presentationReferenceWarnings(value, catalogs) {
1220
724
  if (!isRecord(value) || !Array.isArray(value.slides)) {
1221
725
  return [];
1222
726
  }
1223
- const context = { document: value };
1224
727
  const issues = [];
1225
- if (typeof value.narrative === "string") {
1226
- pushIfDefined(issues, unknownIdWarning("narratives", value.narrative, "/narrative", context));
1227
- }
1228
- if (Array.isArray(value.audience)) {
1229
- value.audience.forEach((entry, index) => {
1230
- pushIfDefined(issues, referenceObjectWarning("audiences", entry, `/audience/${index}`, context));
1231
- });
1232
- } else if (isRecord(value.audience)) {
1233
- pushIfDefined(issues, referenceObjectWarning("audiences", value.audience, "/audience", context));
1234
- } else {
1235
- pushIfDefined(issues, unknownIdWarning("audiences", value.audience, "/audience", context));
1236
- }
1237
- issues.push(...designReferenceWarnings(value.design, "/design", context));
1238
728
  issues.push(...variableReferenceWarnings(value));
1239
729
  value.slides.forEach((slide, index) => {
1240
730
  if (!isRecord(slide)) {
1241
731
  return;
1242
732
  }
1243
733
  const slidePath = `/slides/${index}`;
1244
- issues.push(...designReferenceWarnings(slide.design, pathFor(slidePath, "design"), context));
1245
- issues.push(...slideThemeDimensionsWarnings(value, slide, slidePath, context));
1246
- issues.push(...chartTypeWarnings(slide, slidePath, context));
734
+ issues.push(...slideThemeDimensionsWarnings(value, slide, index, catalogs));
735
+ issues.push(...chartTypeWarnings(slide, slidePath));
1247
736
  const numberingWarnings = (payload, path) => {
1248
737
  for (const finding2 of numberingFindings(payload).warnings) issues.push(semanticIssue(pathFor(path, finding2.key), finding2.message, { ...finding2.params, code: "numbering-start-ignored" }));
1249
738
  };
@@ -1261,34 +750,12 @@ function presentationReferenceWarnings(value) {
1261
750
  visitContentPayloads(slide, slidePath, highlightWarnings);
1262
751
  for (const key of Object.keys(slide)) {
1263
752
  if (promotedRegionKeySet.has(key)) {
1264
- issues.push(...chartTypeWarnings(slide[key], pathFor(slidePath, key), context));
753
+ issues.push(...chartTypeWarnings(slide[key], pathFor(slidePath, key)));
1265
754
  }
1266
755
  }
1267
756
  });
1268
757
  return issues;
1269
758
  }
1270
- var catalogCrossLinkFields = {
1271
- audience: { recommendedNarratives: "narratives", recommendedTones: "tones" },
1272
- purpose: { recommendedNarratives: "narratives", recommendedTones: "tones" },
1273
- tone: { recommendedNarratives: "narratives" }
1274
- };
1275
- function catalogCrossLinkWarnings(schemaName, value) {
1276
- const fields2 = catalogCrossLinkFields[schemaName];
1277
- if (!fields2 || !isRecord(value)) {
1278
- return [];
1279
- }
1280
- const issues = [];
1281
- for (const [field, kind] of Object.entries(fields2)) {
1282
- const links = value[field];
1283
- if (!Array.isArray(links)) {
1284
- continue;
1285
- }
1286
- links.forEach((link, index) => {
1287
- pushIfDefined(issues, unknownIdWarning(kind, link, `${pathFor("/", field)}/${index}`));
1288
- });
1289
- }
1290
- return issues;
1291
- }
1292
759
  function validateLanguageSemantics(value) {
1293
760
  if (!isRecord(value)) {
1294
761
  return [];
@@ -1435,13 +902,12 @@ function validateAgainstSchema(value, schemaOrKind = "presentation", options = {
1435
902
  errors.push(...variableIssues.errors);
1436
903
  const data = dataIssues(subject);
1437
904
  errors.push(...data.errors);
1438
- warnings.push(...presentationReferenceWarnings(subject));
905
+ warnings.push(...presentationReferenceWarnings(subject, options.catalogs));
1439
906
  warnings.push(...data.warnings);
1440
907
  warnings.push(...variableIssues.warnings);
1441
908
  } else if (resolved.schemaName === "language") {
1442
909
  errors.push(...validateLanguageSemantics(value));
1443
910
  }
1444
- warnings.push(...catalogCrossLinkWarnings(resolved.schemaName, value));
1445
911
  return {
1446
912
  valid: errors.length === 0,
1447
913
  errors,
@@ -1455,24 +921,13 @@ function validateAgainstSchema(value, schemaOrKind = "presentation", options = {
1455
921
 
1456
922
  // src/narrative-plan.ts
1457
923
  var isRec = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1458
- function resolveNarrative(document, loaded = []) {
924
+ function resolveNarrative(document, options = {}) {
1459
925
  if (!isRec(document) || typeof document.narrative !== "string") return void 0;
1460
- const id = document.narrative;
1461
- if (/^(?:https?:|pkg:)/i.test(id)) return void 0;
1462
- const entry = isRec(document.catalogs) && isRec(document.catalogs.narratives) ? document.catalogs.narratives : {};
1463
- const sources = [
1464
- ["document", Array.isArray(entry.records) ? entry.records : []],
1465
- ["loaded", loaded],
1466
- ["built-in", catalogs.narratives]
1467
- ];
1468
- for (const [origin, records] of sources) {
1469
- const record = records.find((candidate) => isRec(candidate) && candidate.id === id);
1470
- if (isRec(record)) {
1471
- const beats = Array.isArray(record.beats) ? record.beats.flatMap((beat) => isRec(beat) && typeof beat.id === "string" ? [beat.id] : []) : [];
1472
- return { record, origin, beats };
1473
- }
1474
- }
1475
- return void 0;
926
+ const found = resolveReference(document, "narratives", document.narrative, { catalogs: options.catalogs ?? [] });
927
+ if (!found) return void 0;
928
+ const record = found.record;
929
+ const beats = Array.isArray(record.beats) ? record.beats.flatMap((beat) => isRec(beat) && typeof beat.id === "string" ? [beat.id] : []) : [];
930
+ return { record, origin: found.origin, beats };
1476
931
  }
1477
932
  function slideBeatReferences(document) {
1478
933
  if (!isRec(document) || !Array.isArray(document.slides)) return [];
@@ -1590,19 +1045,13 @@ function simulateVision(hex, model) {
1590
1045
  const m = CVD_MATRICES[model];
1591
1046
  return toHex(m.map((row) => delinear(row[0] * (rgb[0] ?? 0) + row[1] * (rgb[1] ?? 0) + row[2] * (rgb[2] ?? 0))));
1592
1047
  }
1593
- function createLookup(document, extra) {
1594
- return (kind, id) => {
1595
- const inline = rec(rec(document.catalogs)[kind]).records;
1596
- const found = (Array.isArray(inline) ? inline : []).find((r) => r?.id === id) ?? (extra?.[kind] ?? []).find((r) => rec(r).id === id) ?? catalogs[kind]?.find((r) => rec(r).id === id);
1597
- return found === void 0 ? void 0 : rec(found);
1598
- };
1599
- }
1600
1048
  var PAGE = "#FFFFFF";
1601
1049
  var colorFrom = (scheme, slot, fallback) => typeof slot === "string" ? slot.startsWith("#") ? normalizeHexColor(slot) ?? fallback : normalizeHexColor(scheme[slot]) ?? fallback : fallback;
1602
1050
  function backdropOf(definition, scheme, text, variables) {
1603
1051
  const resolve2 = (value, fallback) => backgroundColorRef(value, scheme, variables, fallback);
1604
1052
  const canvas = defaultSlideBackground(scheme);
1605
1053
  if (!definition) return { kind: "solid", color: canvas };
1054
+ if (imageBackground(definition)) return { kind: "image", opacity: imageBackground(definition)?.opacity ?? 1, base: PAGE };
1606
1055
  if (typeof definition === "string") return { kind: "solid", color: colorFrom(scheme, definition, canvas) };
1607
1056
  const bg = rec(definition), opacity = typeof bg.opacity === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
1608
1057
  switch (bg.type) {
@@ -1653,6 +1102,7 @@ function decisionColor(definition, scheme, variables = {}) {
1653
1102
  if (!definition) return void 0;
1654
1103
  const canvas = defaultSlideBackground(scheme);
1655
1104
  const reference = (value) => backgroundColorRef(value, scheme, variables, PAGE);
1105
+ if (imageBackground(definition)) return void 0;
1656
1106
  if (typeof definition === "string") return colorFrom(scheme, definition, canvas);
1657
1107
  const bg = rec(definition);
1658
1108
  switch (bg.type) {
@@ -1671,15 +1121,15 @@ function resolveDesign(document, index, context) {
1671
1121
  const { options, diagnostics, resolved } = context;
1672
1122
  const { theme, colorScheme, fontScheme, fontSchemePath } = resolved;
1673
1123
  const fontPath = `/${fontSchemePath.split(".").join("/")}`;
1674
- const fontDiagnostic = diagnostics.find((diagnostic) => diagnostic.code === "unresolved-font-scheme");
1124
+ const fontDiagnostic = diagnostics.find((diagnostic) => diagnostic.kind === "fontSchemes");
1675
1125
  const dimensions = { width: options.width, height: options.height };
1676
1126
  const variables = rec(document.variables);
1677
1127
  const roles = resolveColorRoles(colorScheme, { background: decisionColor(own2.background ?? deck.background ?? theme.background, colorScheme, variables) });
1678
1128
  const dark = roles.dark;
1679
1129
  const text = roles.text;
1680
1130
  const backdrop = backdropOf(own2.background ?? deck.background ?? theme.background, colorScheme, text, variables);
1681
- const definition = rec(own2.background ?? deck.background ?? theme.background);
1682
- const backgroundImage = definition.type === "image" && own2.background !== void 0 ? { source: rec(definition.image).src, fit: rec(definition.image).fit ?? "cover", path: `/slides/${index}/design/background/image` } : definition.type === "image" && deck.background !== void 0 ? { source: rec(definition.image).src, fit: rec(definition.image).fit ?? "cover", path: "/design/background/image" } : void 0;
1131
+ const picture = imageBackground(own2.background ?? deck.background ?? theme.background);
1132
+ const backgroundImage = picture && own2.background !== void 0 ? { source: picture.src, fit: picture.fit, path: `/slides/${index}/design/background` } : picture && deck.background !== void 0 ? { source: picture.src, fit: picture.fit, path: "/design/background" } : void 0;
1683
1133
  return {
1684
1134
  theme,
1685
1135
  colorScheme,
@@ -1700,7 +1150,7 @@ function resolveDesign(document, index, context) {
1700
1150
  variables,
1701
1151
  ...backgroundImage ? { backgroundImage } : {},
1702
1152
  fontSchemePath: fontPath,
1703
- ...fontDiagnostic ? { unresolvedFontScheme: fontDiagnostic.id } : {}
1153
+ ...fontDiagnostic ? { unresolvedFontScheme: fontDiagnostic.reference } : {}
1704
1154
  };
1705
1155
  }
1706
1156
  function resolveTextColor(reference, design, fallback) {
@@ -1896,9 +1346,6 @@ function assetRefs(document, slide, slidePath, includeDeck) {
1896
1346
  if (rec(payload.node.quote).photo !== void 0) out.push({ path: at2("quote", "photo"), value: rec(payload.node.quote).photo, kind: "quote-photo" });
1897
1347
  }
1898
1348
  const designRefs = (design, base) => {
1899
- const slideImage = design.slideImage;
1900
- if (slideImage && (typeof slideImage === "string" || typeof slideImage.src === "string"))
1901
- out.push({ path: `${base}/slideImage`, value: slideImage, kind: "slide-image" });
1902
1349
  const logo = design.logo;
1903
1350
  if (typeof logo === "string" || logo && typeof logo.src === "string") out.push({ path: `${base}/logo`, value: logo, kind: "logo" });
1904
1351
  else if (logo && typeof logo === "object") {
@@ -1940,10 +1387,10 @@ var isLarge = (sizePx, bold) => {
1940
1387
  };
1941
1388
  function slideBackdrop(context, box) {
1942
1389
  const { design, composition } = context;
1943
- const image = composition?.slideImage;
1944
- if (image?.position === "background") {
1945
- const overlay = image.overlay && image.overlay.box.width >= composition.width * 0.99 && image.overlay.box.height >= composition.height * 0.99 ? { color: resolveTextColor(image.overlay.color, design, "#000000") ?? "#000000", opacity: image.overlay.opacity } : void 0;
1946
- return backdropColors({ kind: "image", opacity: image.opacity ?? 1, base: design.backdrop.kind === "solid" ? design.backdrop.color : "#FFFFFF" }, box, design.dimensions, { overlay });
1390
+ const image = composition?.backgroundImage;
1391
+ if (image) {
1392
+ const overlay = image.overlay && !image.overlay.edge ? { color: resolveTextColor(image.overlay.color, design, "#000000") ?? "#000000", opacity: image.overlay.opacity } : void 0;
1393
+ return backdropColors({ kind: "image", opacity: image.opacity ?? 1, base: "#FFFFFF" }, box, design.dimensions, { overlay });
1947
1394
  }
1948
1395
  return backdropColors(design.backdrop, box, design.dimensions);
1949
1396
  }
@@ -2055,7 +1502,7 @@ var onImageRule = rule(
2055
1502
  standard: "WCAG 2.2 SC 1.4.3 Contrast (Minimum), level AA",
2056
1503
  thresholds: ["contrastNormal", "contrastLarge"],
2057
1504
  cost: "composition",
2058
- approximations: "Core never reads picture pixels. The picture is bounded by a grey ramp from black to white, composited through the image opacity and a full-frame design.slideImage.overlay; the text passes only when every step of that ramp passes. An edge-banded overlay is not counted."
1505
+ approximations: "Core never reads picture pixels. The picture is bounded by a grey ramp from black to white, composited through the image opacity and a full-frame design.background overlay; the text passes only when every step of that ramp passes. An edge-banded overlay is not counted."
2059
1506
  }
2060
1507
  );
2061
1508
  var contrastRules = [
@@ -2078,7 +1525,7 @@ var contrastRules = [
2078
1525
  path: sample.path,
2079
1526
  slide,
2080
1527
  message: `${sample.label} sits on a background picture. Contrast cannot be guaranteed from the document (against the lightest or darkest possible pixels it is as low as ${worst.ratio.toFixed(1)}:1; ${needed}:1 is needed at this size).`,
2081
- help: "Add a full-frame overlay to design.slideImage (overlay colour and an opacity high enough that text passes on any picture), use a solid or gradient background behind text, or place text on a card.",
1528
+ help: "Add a full-frame overlay to the image background (design.background.overlay: a colour and an opacity high enough that text passes on any picture), use a solid or gradient background behind text, or place text on a card.",
2082
1529
  measured: { ratio: round(worst.ratio), needed, textColor: sample.color }
2083
1530
  });
2084
1531
  }
@@ -2126,7 +1573,7 @@ var altRule = rule(
2126
1573
  'People using a screen reader get nothing for a picture without alternative text. A picture that is purely decorative should say so with an empty alt (alt: ""), which is an explicit, reviewed choice instead of an omission.',
2127
1574
  {
2128
1575
  standard: "WCAG 2.2 SC 1.1.1 Non-text Content, level A",
2129
- approximations: "Checks the alt field of images, video, the slide image, logos (design.logo and each LogoSet variant, organization.logo), header/footer images, quote photos and speaker photos, following asset: references to the assets registry. Whether the text describes the picture well is not judged here (see opf/poor-alt-text). Charts carry `chart.alt` and are checked by opf/chart-text-alternative. Background images and watermarks are decorative by definition and are not checked."
1576
+ approximations: "Checks the alt field of images (image blocks, Slide.image and region images, placed or not), video, logos (design.logo and each LogoSet variant, organization.logo), header/footer images, quote photos and speaker photos, following asset: references to the assets registry. Whether the text describes the picture well is not judged here (see opf/poor-alt-text). Charts carry `chart.alt` and are checked by opf/chart-text-alternative. Picture backgrounds are decorative unless they carry their own alt, and watermarks are decorative, so neither is checked."
2130
1577
  }
2131
1578
  );
2132
1579
  var poorAltRule = rule(
@@ -2140,7 +1587,7 @@ var poorAltRule = rule(
2140
1587
  var GENERIC_ALT = /^(image|picture|photo|photograph|graphic|img|icon|figure|screenshot|untitled|alt|alt text|logo)$/i;
2141
1588
  var FILE_ALT = /(\.(png|jpe?g|gif|svg|webp|bmp|tiff?|heic|avif)$)|^(img|dsc|image|screenshot|screen shot|photo|pic)[ _-]?\d+/i;
2142
1589
  var GENERIC_CHART_ALT = /^((a|an|the)\s+)?([a-z-]+\s+){0,2}(chart|graph|plot|diagram|figure)$/i;
2143
- var kindLabel = (kind) => ({ chart: "Chart", image: "Image", video: "Video", "slide-image": "Slide image", logo: "Logo", furniture: "Header/footer image", speaker: "Speaker photo", "quote-photo": "Quote photo", organization: "Organization logo" })[kind] ?? "Picture";
1590
+ var kindLabel = (kind) => ({ chart: "Chart", image: "Image", video: "Video", logo: "Logo", furniture: "Header/footer image", speaker: "Speaker photo", "quote-photo": "Quote photo", organization: "Organization logo" })[kind] ?? "Picture";
2144
1591
  function altFixes(path, value) {
2145
1592
  const decorative = typeof value === "string" ? { id: "mark-decorative", title: "Mark as decorative (empty alt)", kind: "patch", safe: false, patch: [{ op: "replace", path, value: { src: value, alt: "" } }] } : { id: "mark-decorative", title: "Mark as decorative (empty alt)", kind: "patch", safe: false, patch: [{ op: "add", path: `${path}/alt`, value: "" }] };
2146
1593
  return [{ id: "focus-alt", title: "Write alt text", kind: "focus", safe: true, focus: { path, field: "alt", value } }, decorative];
@@ -2481,7 +1928,7 @@ var languageRules = [
2481
1928
  context.report(languageRule, {
2482
1929
  path: "",
2483
1930
  message: "The presentation has no language set.",
2484
- help: 'Set `language` to a language id from the languages catalog or a BCP 47 tag, for example "en-US".',
1931
+ help: 'Set `language` to a BCP 47 tag, for example "en-US".',
2485
1932
  fixes: [{ id: "focus-language", title: "Set the language", kind: "focus", safe: true, focus: { path: "/language", field: "language" } }]
2486
1933
  });
2487
1934
  }
@@ -2641,7 +2088,7 @@ var resolutionRule = rule(
2641
2088
  {
2642
2089
  cost: "composition",
2643
2090
  thresholds: ["minImagePpi"],
2644
- approximations: "Only embedded data: images (and asset: references to them) have readable pixel sizes; URLs and files are never fetched, so they are not checked. The displayed size is the composed box (cropped images are measured as the cover scale, fitted ones as the contain scale). Effective ppi is the image pixels per inch of the 96 px/inch reference slide. SVG is vector and exempt."
2091
+ approximations: "Only embedded data: images (and asset: references to them) have readable pixel sizes; URLs and files are never fetched, so they are not checked. The displayed size is the composed frame (cover and stretch are measured as the cover scale, contain as the contain scale). Effective ppi is the image pixels per inch of the 96 px/inch reference slide. SVG is vector and exempt."
2645
2092
  }
2646
2093
  );
2647
2094
  var resolutionRules = [
@@ -2669,12 +2116,10 @@ var resolutionRules = [
2669
2116
  for (const slide of context.slides) {
2670
2117
  const composition = slide.composition;
2671
2118
  if (composition) {
2672
- const fill = composition.design.imageFill;
2673
- for (const item of composition.items) if (item.field === "image") check(pointerOfDotted(item.path), item.value, item.box, fill === "crop", slide);
2674
- if (composition.slideImage) check(pointerOfDotted(composition.slideImage.sourcePath), composition.slideImage.value, composition.slideImage.box, composition.slideImage.fill === "crop", slide);
2119
+ for (const item of composition.items) if (item.field === "image") check(pointerOfDotted(item.path), item.value, item.image?.box ?? item.box, item.image?.fit !== "contain", slide);
2675
2120
  }
2676
2121
  const background = slide.design.backgroundImage;
2677
- if (background && background.fit !== "tile") check(background.path, rec({ src: background.source }), slide.design.dimensions, background.fit === "cover", background.path.startsWith("/slides/") ? slide : void 0);
2122
+ if (background && background.fit !== "tile") check(background.path, rec({ src: background.source }), slide.design.dimensions, background.fit !== "contain", background.path.startsWith("/slides/") ? slide : void 0);
2678
2123
  }
2679
2124
  }
2680
2125
  }
@@ -2708,7 +2153,7 @@ var unusedBeatRule = rule(
2708
2153
  "A beat of the narrative has no slide that references it.",
2709
2154
  "The narrative is the plan and the slides are the product. When some slides name a beat (slides[].beat) and a beat of the plan has none, the deck skips a step of the story or the plan is out of date.",
2710
2155
  {
2711
- approximations: "Resolved offline like every catalog reference: the inline catalogs.narratives.records of the document, then records passed in the `catalogs` option, then the bundled catalog. A narrative given as a URL or a pkg: reference, or an id no local source defines, is not checked. A deck in which no slide references any beat is not checked either, because it has not linked its slides to the plan. A slide that lists several beats covers each of them."
2156
+ approximations: "Resolved like every content reference: the document's catalogs groups, then the registered catalogs. A narrative that resolves nowhere is not checked. A deck in which no slide references any beat is not checked either, because it has not linked its slides to the plan. A slide that lists several beats covers each of them."
2712
2157
  }
2713
2158
  );
2714
2159
  var PLACEHOLDERS = [
@@ -2758,7 +2203,7 @@ var contentRules = [
2758
2203
  {
2759
2204
  info: unusedBeatRule,
2760
2205
  run(context) {
2761
- const narrative = resolveNarrative(context.document, context.options.catalogs?.narratives);
2206
+ const narrative = resolveNarrative(context.document, context.options);
2762
2207
  if (!narrative) return;
2763
2208
  const id = String(context.document.narrative);
2764
2209
  for (const { beat, index } of unreferencedBeats(context.document, narrative))
@@ -2778,8 +2223,8 @@ var contentRules = [
2778
2223
  const has = (value) => value !== void 0 && value !== null && !(typeof value === "string" && value.trim() === "") && !(Array.isArray(value) && value.length === 0);
2779
2224
  const hasText = slide.texts.some((tv) => plainText(tv.value).trim() !== "");
2780
2225
  const hasObject = slidePayloads(slide.slide, slide.path).some((p) => ["image", "video", "chart", "table", "code", "metric", "quote", "timeline"].some((field) => has(p.node[field])));
2781
- const hasSlideImage = has(rec(slide.slide.design).slideImage);
2782
- if (hasText || hasObject || hasSlideImage) continue;
2226
+ const hasBackgroundImage = imageBackground(rec(slide.slide.design).background) !== void 0;
2227
+ if (hasText || hasObject || hasBackgroundImage) continue;
2783
2228
  context.report(emptySlideRule, { path: slide.path, slide, message: `Slide ${slide.index + 1} has no title and no content.`, help: "Add content, delete the slide, or give it the blank layout if it is intentionally empty." });
2784
2229
  }
2785
2230
  }
@@ -2840,6 +2285,8 @@ var formatRules = [
2840
2285
  rule("cite-unknown-reference", "format", "error", "A citation names a reference that does not exist.", "A cited id with no entry in `references` has nothing to show in the footnote area.", { standard: SCHEMA }),
2841
2286
  rule("cite-unsupported-location", "format", "error", "A citation or footnote sits where no engine draws it.", "`cite` and `footnote` apply to runs in text, bullets and list items; table cells, captions, and reference and footnote texts have no marker.", { standard: SCHEMA }),
2842
2287
  rule("caption-unsupported-payload", "format", "error", "A caption is on a payload that cannot carry one.", "A caption belongs to exactly one image, chart, table or video; a group, text or code block has no place to draw it.", { standard: SCHEMA }),
2288
+ rule("image-option-unsupported-payload", "format", "error", "An image option is on a payload that is not an image.", "`fit`, `focus`, the image treatments (`shape`, `cornerRadius`, `border`, `opacity`, `recolor`, `overlay`, `aspectRatio`) and `placement` describe how a picture is drawn; a group, text or chart block has no picture for them to apply to.", { standard: SCHEMA }),
2289
+ rule("image-placement-invalid", "format", "error", "An image placement cannot be honoured.", "A placed image bleeds to a slide edge and the rest of the slide composes beside it. Only a top-level block (slides.N.blocks.I) can do that, and a slide edge holds one placed image; a block in a group or a promoted region, or a second block on the same edge, has nowhere to go.", { standard: SCHEMA }),
2843
2290
  rule("dataset-unknown", "format", "error", "A chart or table names a dataset that does not exist.", "The data cannot be drawn without the dataset it refers to.", { standard: SCHEMA }),
2844
2291
  rule("dataset-field-unknown", "format", "error", "A table asks a dataset for a column it does not have.", "The column cannot be shown when the dataset has no column of that name.", { standard: SCHEMA }),
2845
2292
  rule("data-column-duplicate", "format", "error", "A dataset or table has two columns with the same name.", "Series, mappings and fields address columns by name, so a repeated name makes them ambiguous.", { standard: SCHEMA }),
@@ -2876,23 +2323,30 @@ var referenceRules = [
2876
2323
  "catalog-record",
2877
2324
  "references",
2878
2325
  "error",
2879
- "A supplied or inline catalog record is invalid, or repeats an id.",
2880
- "A record that fails its catalog schema cannot be resolved, and a repeated id makes the override ambiguous. Invalid records are left out of the lookup, so the references to them are reported too.",
2326
+ "An embedded or registered catalog record is invalid.",
2327
+ "A record that fails its companion schema cannot be resolved. Invalid records are left out of the lookup, so the references to them are reported too.",
2881
2328
  { standard: "spec/schemas/<kind>.schema.json" }
2882
2329
  ),
2883
2330
  rule(
2884
- "catalog-reference",
2331
+ "unresolved-reference",
2885
2332
  "references",
2886
2333
  "warning",
2887
- "A catalog id is not in the available context.",
2888
- "A theme, layout, font scheme or other catalog id that no record defines falls back to the engine default. Custom ids are legitimate when the host supplies their records, so this is advisory.",
2889
- { approximations: "Resolved against the document's inline records, the records the host passed in `catalogs`, then the bundled catalogs. External sources and `pkg:` records are never fetched. Free-form audience and purpose text, and BCP 47 language tags, are not catalog references." }
2334
+ "A content reference resolves nowhere.",
2335
+ "A layout, theme, colour scheme, font scheme, narrative, audience, purpose or tone reference that neither the document embeds nor a registered catalog defines falls back: a slide composes automatically, a design uses the engine default. A strict export fails instead. A slide with no layout is automatic composition and is never reported.",
2336
+ { standard: SCHEMA, approximations: "Resolved like every engine resolves it: catalogs.custom, then the records embedded under catalogs.default, then the catalog registered for its source (the first registered catalog when `default` is omitted); `name:id` in catalogs.<name>, then the catalog registered for its source. Nothing is fetched. Free-form audience and purpose text is not a reference." }
2890
2337
  ),
2891
- rule("deprecated-catalog-id", "references", "warning", "A catalog id is deprecated.", "A deprecated record still resolves, so nothing breaks, but the replacement is the one that will be maintained.", { standard: "spec/catalogs `deprecation.replacedBy`" }),
2892
- rule("catalog-source", "references", "info", "An external catalog source was not fetched.", "A catalog `source` is a URL or package the checker never loads, so ids defined there are not verified."),
2338
+ rule(
2339
+ "catalog-record-not-in-source",
2340
+ "references",
2341
+ "warning",
2342
+ "A record embedded under a catalog group is not in that catalog.",
2343
+ "A record under catalogs.default or a named group says it came from the catalog its source names. When the catalog the host registered for that source has no record of that kind and id, the record is the document's own and belongs in catalogs.custom, where an update from the catalog never looks for it. Rendering is unchanged: the embedded record still wins.",
2344
+ { standard: SCHEMA, approximations: "Checked only against a catalog the host registered for the group's source (the first registered catalog for an omitted default.source); with none registered for it the check is silent. A record the catalog has with different content is an update difference (updateFromCatalog), not this finding. catalogs.custom is never checked." }
2345
+ ),
2346
+ rule("undeclared-catalog", "format", "error", "A reference names a catalog group the document does not declare.", "The prefix of a `name:id` reference names the group of `catalogs` it resolves in. A prefix with no group can never resolve, whatever the host registers, so it is a format error: engines reject the document at their format check instead of drawing a fallback.", { standard: SCHEMA }),
2893
2347
  rule("unused-reference", "references", "warning", "A reference is never cited.", "A listed reference that no run cites is not drawn anywhere.", { standard: SCHEMA }),
2894
2348
  rule("unused-dataset", "references", "warning", "A dataset is never used.", "A dataset no chart or table references is not drawn anywhere.", { standard: SCHEMA }),
2895
- rule("unknown-beat", "references", "warning", "A slide names a beat its narrative does not define.", "`slides[].beat` links a slide to a step of the narrative plan. A beat id the narrative does not have links to nothing; nothing is drawn from a beat.", { standard: SCHEMA, approximations: "The narrative resolves offline: the inline catalogs.narratives.records, then the `catalogs` option, then the bundled catalog. A narrative no local source defines is not checked." }),
2349
+ rule("unknown-beat", "references", "warning", "A slide names a beat its narrative does not define.", "`slides[].beat` links a slide to a step of the narrative plan. A beat id the narrative does not have links to nothing; nothing is drawn from a beat.", { standard: SCHEMA, approximations: "The narrative resolves like every content reference: the document's catalogs groups, then the registered catalogs. A narrative that resolves nowhere is not checked." }),
2896
2350
  rule("slide-theme-dimensions", "references", "warning", "A slide theme sets a slide size that differs from the deck.", "A PPTX has one slide size. The size a slide-level theme carries is never used: design.dimensions of the deck (or of its theme) wins in every engine, and without them the exporter stops with mixed slide sizes.", { standard: SCHEMA }),
2897
2351
  rule("variable-unknown", "references", "warning", "A `{{token}}` names a variable that is not declared.", "An undeclared token is shown literally.", { standard: SCHEMA }),
2898
2352
  rule("variable-unknown-value", "references", "warning", "A value was supplied for a variable that is not declared.", "The value is never used.", { standard: SCHEMA }),
@@ -2972,12 +2426,7 @@ function at(value, path) {
2972
2426
  );
2973
2427
  }
2974
2428
  function checkDocumentOptions(options) {
2975
- if (options.catalogs !== void 0 && (!object(options.catalogs) || Object.entries(options.catalogs).some(
2976
- ([kind, records]) => !catalogKinds.includes(kind) || !Array.isArray(records)
2977
- )))
2978
- throw new TypeError(
2979
- "Validate catalogs must map known catalog kinds to arrays of loaded records."
2980
- );
2429
+ checkCatalogsOption(options.catalogs, "validate");
2981
2430
  if (options.contracts !== void 0 && !Array.isArray(options.contracts))
2982
2431
  throw new TypeError("Validate contracts must be an array.");
2983
2432
  for (const contract of options.contracts ?? []) {
@@ -3094,36 +2543,6 @@ function active(cursor, value) {
3094
2543
  const selected = candidates.sort((a, b) => score(b.schema, value) - score(a.schema, value))[0];
3095
2544
  return selected ? { ...selected, baseSchemas: [...selected.baseSchemas ?? [], resolved] } : resolved;
3096
2545
  }
3097
- function catalogIn(schema) {
3098
- const text = String(schema.description ?? "");
3099
- if (/\bfont-scheme id\b/.test(text)) return "fontSchemes";
3100
- return catalogKinds.find(
3101
- (kind) => text.includes(`catalogs.${kind}`) || new RegExp(`\\b${kind}['\u2019]? catalog`).test(text)
3102
- );
3103
- }
3104
- var languageTagSyntax = new RegExp(
3105
- "^(?:(?:[a-z]{2,3}(?:-[a-z]{3}){0,3}|[a-z]{4}|[a-z]{5,8})(?:-[a-z]{4})?(?:-(?:[a-z]{2}|[0-9]{3}))?(?:-(?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*(?:-[0-9a-wy-z](?:-[a-z0-9]{2,8})+)*(?:-x(?:-[a-z0-9]{1,8})+)?|x(?:-[a-z0-9]{1,8})+)$",
3106
- "i"
3107
- );
3108
- var irregularLanguageTags = /* @__PURE__ */ new Set([
3109
- "en-gb-oed",
3110
- "i-ami",
3111
- "i-bnn",
3112
- "i-default",
3113
- "i-enochian",
3114
- "i-hak",
3115
- "i-klingon",
3116
- "i-lux",
3117
- "i-mingo",
3118
- "i-navajo",
3119
- "i-pwn",
3120
- "i-tao",
3121
- "i-tay",
3122
- "i-tsu",
3123
- "sgn-be-fr",
3124
- "sgn-be-nl",
3125
- "sgn-ch-de"
3126
- ]);
3127
2546
  function childCursor(cursors, key) {
3128
2547
  for (const keyword of [
3129
2548
  "properties",
@@ -3164,7 +2583,7 @@ function fields(document) {
3164
2583
  const entry = stack.pop();
3165
2584
  if (!entry) break;
3166
2585
  if (entry.ancestors.includes(entry.value)) continue;
3167
- const resolved = resolve(entry.cursor), selected = active(entry.cursor, entry.value), description = String(resolved.schema.description ?? "");
2586
+ const resolved = resolve(entry.cursor), selected = active(entry.cursor, entry.value);
3168
2587
  const assetReference = [resolved, selected].some(
3169
2588
  (cursor) => cursor.root.$id === schemas.presentation.$id && (cursor.path === "/$defs/Asset" || cursor.path === "/$defs/Asset/oneOf/0" || cursor.path === "/$defs/Watermark/properties/src") || String(cursor.schema.description ?? "").includes("asset:") || Array.isArray(cursor.schema.examples) && cursor.schema.examples.some(
3170
2589
  (example) => typeof example === "string" && example.startsWith("asset:")
@@ -3174,8 +2593,6 @@ function fields(document) {
3174
2593
  path: pointer3(entry.path),
3175
2594
  value: entry.value,
3176
2595
  cursor: resolved,
3177
- kind: catalogIn(resolved.schema),
3178
- description,
3179
2596
  assetReference
3180
2597
  });
3181
2598
  const ancestors = [...entry.ancestors, entry.value];
@@ -3209,74 +2626,39 @@ function fields(document) {
3209
2626
  }
3210
2627
  return result;
3211
2628
  }
3212
- function catalogContext(document, options, findings) {
3213
- const result = /* @__PURE__ */ new Map();
3214
- for (const entry of catalogEntries) {
3215
- const kind = entry.kind, map = /* @__PURE__ */ new Map();
3216
- result.set(kind, map);
3217
- for (const record of entry.records)
3218
- map.set(record.id, {
3219
- value: record.id,
3220
- label: String(
3221
- record.name ?? record.id
3222
- ),
3223
- origin: "built-in",
3224
- definition: `spec/${entry.dir}/${entry.index.records.find((item) => item.id === record.id)?.file ?? `${record.id}.json`}`
3225
- });
3226
- const local = object(document) && object(document.catalogs) && object(document.catalogs[kind]) ? document.catalogs[kind] : {};
3227
- if (local.source !== void 0)
3228
- findings.push(
3229
- finding("opf/catalog-source", {
3230
- path: `/catalogs/${kind}/source`,
3231
- message: "External catalog source was not fetched.",
3232
- help: "This run checks built-in, supplied and inline records only. Load external catalogs in the host and pass their records explicitly to verify that context."
3233
- })
3234
- );
3235
- for (const group of [
3236
- {
3237
- records: options.catalogs?.[kind] ?? [],
3238
- origin: "loaded",
3239
- scope: "context",
3240
- path: `/catalogs/${kind}`
3241
- },
3242
- {
3243
- records: Array.isArray(local.records) ? local.records : [],
3244
- origin: "document",
3245
- scope: "document",
3246
- path: `/catalogs/${kind}/records`
2629
+ var recordKey = (group, kind, id) => `${group}/${kind}/${id}`;
2630
+ function recordIssues(kind, id, value) {
2631
+ const schemaName = catalogSchemaNames[kind];
2632
+ return validateAgainstSchema(object(value) ? { $schema: schemas[schemaName].$id, id, ...value } : value, kind);
2633
+ }
2634
+ function embeddedRecordFindings(document, options, findings) {
2635
+ const invalid = /* @__PURE__ */ new Set();
2636
+ if (!object(document) || !object(document.catalogs)) return invalid;
2637
+ for (const [group, value] of Object.entries(document.catalogs)) {
2638
+ if (!object(value)) continue;
2639
+ for (const kind of catalogKinds)
2640
+ for (const [id, record] of Object.entries(object(value[kind]) ? value[kind] : {})) {
2641
+ const path = pointer3(["catalogs", group, kind, id]);
2642
+ if (object(record) && (Object.hasOwn(record, "$schema") || Object.hasOwn(record, "id"))) continue;
2643
+ const validation = recordIssues(kind, id, record);
2644
+ for (const issue2 of validation.errors) findings.push(issueFinding(issue2, "opf/catalog-record", catalogSchemaNames[kind], path, "document"));
2645
+ if (!validation.valid) invalid.add(recordKey(group, kind, id));
2646
+ if (group === "custom") continue;
2647
+ const source = catalogGroupSource(document, group, options);
2648
+ const registered = registeredCatalog(source, options);
2649
+ if (!registered || Object.hasOwn(registered[kind] ?? {}, id)) continue;
2650
+ findings.push(
2651
+ finding("opf/catalog-record-not-in-source", {
2652
+ path,
2653
+ message: `Record ${JSON.stringify(id)} is embedded under catalogs.${group}.${kind}, but the catalog registered for ${source} has no ${kind} record ${JSON.stringify(id)}; move it to catalogs.custom.`,
2654
+ help: `Move the record to catalogs.custom (and drop the ${group === "default" ? "" : `${group}:`}prefix from its references), or use the id the catalog publishes. The embedded record still renders.`,
2655
+ definition: `${schemas.presentation.$id}#/$defs/Catalogs`,
2656
+ lookup: ["opf", "catalog", kind]
2657
+ })
2658
+ );
3247
2659
  }
3248
- ]) {
3249
- const seen = /* @__PURE__ */ new Set();
3250
- group.records.forEach((value, index) => {
3251
- const path = `${group.path}/${index}`, schemaName = catalogSchemaNames[kind], record = object(value) ? { $schema: schemas[schemaName].$id, ...value } : value;
3252
- const validation = validateAgainstSchema(record, kind);
3253
- for (const issue2 of validation.errors)
3254
- findings.push(issueFinding(issue2, "opf/catalog-record", schemaName, path, group.scope));
3255
- if (!object(value) || typeof value.id !== "string") return;
3256
- if (seen.has(value.id))
3257
- findings.push(
3258
- finding("opf/catalog-record", {
3259
- scope: group.scope,
3260
- path: `${path}/id`,
3261
- message: `Duplicate ${kind} record id ${JSON.stringify(value.id)} in this catalog.`,
3262
- help: "Give distinct records distinct IDs, or combine the intended override explicitly. Preserve their authored content."
3263
- })
3264
- );
3265
- seen.add(value.id);
3266
- if (!validation.valid) {
3267
- map.delete(value.id);
3268
- return;
3269
- }
3270
- map.set(value.id, {
3271
- value: value.id,
3272
- label: typeof value.name === "string" ? value.name : value.id,
3273
- origin: group.origin,
3274
- definition: `${group.scope}#${path}`
3275
- });
3276
- });
3277
- }
3278
2660
  }
3279
- return result;
2661
+ return invalid;
3280
2662
  }
3281
2663
  function distance(a, b) {
3282
2664
  a = a.slice(0, 128);
@@ -3411,14 +2793,59 @@ function variableFindings(document, engine, schemaValid) {
3411
2793
  walk(document, [], 0);
3412
2794
  return findings;
3413
2795
  }
3414
- function hasExternalSource(document, kind) {
3415
- if (!object(document) || !object(document.catalogs)) return false;
3416
- const entry = document.catalogs[kind];
3417
- return object(entry) && (typeof entry.source === "string" || Array.isArray(entry.source) && entry.source.length > 0);
2796
+ function undeclaredCatalogFindings(document) {
2797
+ const findings = [];
2798
+ const reported = /* @__PURE__ */ new Set();
2799
+ for (const site of catalogReferenceSites(document)) {
2800
+ const parsed = parseReference(site.reference);
2801
+ if (parsed?.group === void 0 || catalogGroupDeclared(document, parsed.group)) continue;
2802
+ const path = pointerPath(site.path);
2803
+ if (reported.has(path)) continue;
2804
+ reported.add(path);
2805
+ findings.push(
2806
+ finding("opf/undeclared-catalog", {
2807
+ path,
2808
+ message: `Reference ${JSON.stringify(site.reference)} names catalog group ${JSON.stringify(parsed.group)}, which the document does not declare, so it can never resolve.`,
2809
+ help: `Declare catalogs.${parsed.group} with the catalog's source (and embed the record), or write the reference without the prefix.`,
2810
+ definition: `${schemas.presentation.$id}#/$defs/CatalogReference`,
2811
+ lookup: ["opf", "schema", "presentation", "/$defs/CatalogReference"]
2812
+ })
2813
+ );
2814
+ }
2815
+ return findings;
2816
+ }
2817
+ function contentReferenceFindings(document, options, findings) {
2818
+ const invalid = embeddedRecordFindings(document, options, findings);
2819
+ const registeredChecked = /* @__PURE__ */ new Set();
2820
+ for (const site of catalogReferenceSites(document)) {
2821
+ const path = pointerPath(site.path);
2822
+ const parsed = parseReference(site.reference);
2823
+ if (parsed?.group !== void 0 && !catalogGroupDeclared(document, parsed.group)) continue;
2824
+ const found = resolveReference(document, site.kind, site.reference, { ...options, ...site.group !== void 0 ? { group: site.group } : {} });
2825
+ if (found?.origin === "host" && !registeredChecked.has(recordKey(found.group, site.kind, found.id))) {
2826
+ registeredChecked.add(recordKey(found.group, site.kind, found.id));
2827
+ for (const issue2 of recordIssues(site.kind, found.id, found.record).errors)
2828
+ findings.push(issueFinding(issue2, "opf/catalog-record", catalogSchemaNames[site.kind], pointer3(["catalogs", found.group, site.kind, found.id]), "context"));
2829
+ }
2830
+ if (found && !(found.origin === "document" && invalid.has(recordKey(found.group, site.kind, found.id)))) continue;
2831
+ const diagnostic = unresolvedReference(document, site.kind, site.reference, path, options);
2832
+ const suggestions = catalogRecords(document, site.kind, options).map((entry) => ({ value: entry.reference, label: typeof entry.record.name === "string" ? entry.record.name : entry.reference, origin: entry.origin === "host" ? "registered" : "document", definition: entry.origin === "document" ? `document#${pointer3(["catalogs", entry.group, site.kind, entry.id])}` : `${entry.source ?? "context"}#/${site.kind}/${entry.id}` })).sort((a, b) => distance(site.reference, a.value) - distance(site.reference, b.value) || (a.value < b.value ? -1 : a.value > b.value ? 1 : 0)).slice(0, 5);
2833
+ findings.push(
2834
+ finding("opf/unresolved-reference", {
2835
+ path,
2836
+ message: diagnostic.message,
2837
+ help: site.kind === "layouts" ? "Embed the layout record (embed(), or opf embed), register the catalog that defines it, choose one of the suggested layouts, or remove the reference to compose the slide automatically." : "Embed the record (embed(), or opf embed), register the catalog that defines it, or choose one of the suggested records.",
2838
+ definition: `${schemas.presentation.$id}#/$defs/Catalogs`,
2839
+ lookup: ["opf", "catalog", site.kind],
2840
+ suggestions
2841
+ })
2842
+ );
2843
+ }
3418
2844
  }
3419
2845
  function referenceFindings(document, engine, options) {
3420
2846
  const findings = [];
3421
- const catalogs2 = catalogContext(document, options, findings), seen = /* @__PURE__ */ new Set();
2847
+ const catalogs = { catalogs: options.catalogs ?? [] };
2848
+ contentReferenceFindings(document, catalogs, findings);
3422
2849
  const assetValues = object(document) && object(document.assets) ? document.assets : {};
3423
2850
  for (const field of fields(document)) {
3424
2851
  if (typeof field.value === "string" && field.value.startsWith("asset:") && field.assetReference) {
@@ -3442,30 +2869,6 @@ function referenceFindings(document, engine, options) {
3442
2869
  })
3443
2870
  );
3444
2871
  }
3445
- if (!field.path || !field.kind) continue;
3446
- const { kind } = field;
3447
- if (kind === "languages" && field.path === "/language" && typeof field.value === "string" && (languageTagSyntax.test(field.value) || irregularLanguageTags.has(field.value.toLowerCase())))
3448
- continue;
3449
- if (kind !== "layouts" && /free-form/i.test(field.description)) continue;
3450
- const value = object(field.value) ? field.value.id : field.value, path = object(field.value) ? `${field.path}/id` : field.path;
3451
- if (typeof value !== "string" || !value || /^(?:https?:|pkg:)/i.test(value) || catalogs2.get(kind)?.has(value) || seen.has(path))
3452
- continue;
3453
- seen.add(path);
3454
- if (!options.catalogs?.[kind]?.length && hasExternalSource(document, kind)) continue;
3455
- const suggestions = [...catalogs2.get(kind)?.values() ?? []].sort(
3456
- (a, b) => distance(value, String(a.value)) - distance(value, String(b.value)) || (String(a.value) < String(b.value) ? -1 : String(a.value) > String(b.value) ? 1 : 0)
3457
- ).slice(0, 5);
3458
- const definition = String(field.cursor.root.$id) + `#${field.cursor.path}`;
3459
- findings.push(
3460
- finding("opf/catalog-reference", {
3461
- path,
3462
- message: `Unknown ${kind} catalog id ${JSON.stringify(value)} in the available local context.`,
3463
- help: kind === "layouts" ? "Choose an available layout or supply the intended custom record. Engine-defined layouts may be valid; preview with the target renderer before changing content." : "Choose an available record or supply the intended custom catalog context. External references and native rendering are not verified by this check.",
3464
- definition,
3465
- lookup: ["opf", "catalog", kind],
3466
- suggestions
3467
- })
3468
- );
3469
2872
  }
3470
2873
  const reportedCycles = /* @__PURE__ */ new Set();
3471
2874
  for (const id of Object.keys(assetValues)) {
@@ -3492,33 +2895,7 @@ function referenceFindings(document, engine, options) {
3492
2895
  current = typeof source === "string" && source.startsWith("asset:") ? source.slice(6) : void 0;
3493
2896
  }
3494
2897
  }
3495
- for (const issue2 of engine.warnings) {
3496
- if (typeof issue2.params.code === "string") continue;
3497
- const kind = issue2.params.kind, id = issue2.params.id, replacedBy = issue2.params.replacedBy;
3498
- if (kind === void 0) continue;
3499
- if (typeof replacedBy === "string" && typeof id === "string") {
3500
- const target = catalogs2.get(kind)?.get(replacedBy);
3501
- findings.push({
3502
- ...issueFinding(issue2, "opf/deprecated-catalog-id"),
3503
- message: `Deprecated ${kind} catalog id ${JSON.stringify(id)}; use ${JSON.stringify(replacedBy)} instead.`,
3504
- help: "The deprecated id still resolves to its original record, so nothing breaks. Switch to the replacement when you next edit this reference.",
3505
- lookup: ["opf", "catalog", kind],
3506
- ...target ? { suggestions: [target] } : {}
3507
- });
3508
- continue;
3509
- }
3510
- if (seen.has(issue2.path) || typeof id === "string" && catalogs2.get(kind)?.has(id))
3511
- continue;
3512
- const dir = catalogEntries.find((entry) => entry.kind === kind)?.dir;
3513
- findings.push({
3514
- ...issueFinding(issue2, "opf/catalog-reference"),
3515
- message: `Unknown ${kind} catalog id ${JSON.stringify(id)} in the available local context.`,
3516
- help: "Inspect the referenced catalog and supply the intended record if this is a custom context.",
3517
- ...dir ? { definition: `spec/${dir}/index.json` } : {},
3518
- lookup: ["opf", "catalog", kind]
3519
- });
3520
- }
3521
- findings.push(...narrativeFindings(document, options));
2898
+ findings.push(...narrativeFindings(document, catalogs));
3522
2899
  for (const issue2 of unusedReferenceWarnings(document))
3523
2900
  findings.push(
3524
2901
  finding("opf/unused-reference", {
@@ -3545,16 +2922,16 @@ function referenceFindings(document, engine, options) {
3545
2922
  function narrativeFindings(document, options) {
3546
2923
  const findings = [];
3547
2924
  if (!object(document)) return findings;
3548
- const narrative = resolveNarrative(document, options.catalogs?.narratives);
2925
+ const narrative = resolveNarrative(document, options);
3549
2926
  if (narrative) {
3550
2927
  const id = String(document.narrative);
3551
- const beatSuggestions = (beat) => narrative.beats.slice().sort((a, b) => distance(beat, a) - distance(beat, b) || (a < b ? -1 : a > b ? 1 : 0)).slice(0, 5).map((value) => ({ value, label: value, origin: narrative.origin === "built-in" ? "built-in" : narrative.origin, definition: `narratives/${id}#/beats` }));
2928
+ const beatSuggestions = (beat) => narrative.beats.slice().sort((a, b) => distance(beat, a) - distance(beat, b) || (a < b ? -1 : a > b ? 1 : 0)).slice(0, 5).map((value) => ({ value, label: value, origin: narrative.origin, definition: `narratives/${id}#/beats` }));
3552
2929
  for (const reference of unknownBeatReferences(document, narrative))
3553
2930
  findings.push(
3554
2931
  finding("opf/unknown-beat", {
3555
2932
  path: reference.path,
3556
2933
  message: `Slide ${reference.slide + 1} names beat ${JSON.stringify(reference.beat)}, which narrative ${JSON.stringify(id)} does not define.`,
3557
- help: `Use one of the narrative's beat ids (${narrative.beats.join(", ")}), add the beat to the narrative record (an inline record in catalogs.narratives.records), or remove the beat link. Nothing is drawn from a beat.`,
2934
+ help: `Use one of the narrative's beat ids (${narrative.beats.join(", ")}), add the beat to the narrative record (a record the document embeds or defines in catalogs.custom.narratives), or remove the beat link. Nothing is drawn from a beat.`,
3558
2935
  definition: schemas.presentation.$id + "#/$defs/Slide/properties/beat",
3559
2936
  lookup: ["opf", "catalog", "narratives"],
3560
2937
  suggestions: beatSuggestions(reference.beat)
@@ -3572,20 +2949,19 @@ function narrativeFindings(document, options) {
3572
2949
  })
3573
2950
  );
3574
2951
  }
3575
- const inlineNarratives = object(document.catalogs) && object(document.catalogs.narratives) ? document.catalogs.narratives.records : void 0;
3576
- if (Array.isArray(inlineNarratives))
3577
- inlineNarratives.forEach((record, index) => {
2952
+ for (const [group, value] of Object.entries(object(document.catalogs) ? document.catalogs : {}))
2953
+ for (const [id, record] of Object.entries(object(value) && object(value.narratives) ? value.narratives : {})) {
3578
2954
  if (durationRangeInverted(record))
3579
2955
  findings.push(
3580
2956
  finding("opf/narrative-duration-range", {
3581
- path: `/catalogs/narratives/records/${index}/duration`,
2957
+ path: pointer3(["catalogs", group, "narratives", id, "duration"]),
3582
2958
  message: "The narrative duration range has min greater than max.",
3583
2959
  help: "Swap the bounds so min is the shortest and max the longest talk length, in minutes.",
3584
2960
  definition: schemas.narrative.$id + "#/properties/duration",
3585
2961
  lookup: ["opf", "schema", "narrative", "/properties/duration"]
3586
2962
  })
3587
2963
  );
3588
- });
2964
+ }
3589
2965
  return findings;
3590
2966
  }
3591
2967
  function contractFindings(document, contracts) {
@@ -3742,52 +3118,27 @@ function parseSource(source) {
3742
3118
  }
3743
3119
 
3744
3120
  // src/slide-context.ts
3745
- var DEFAULT_THEME = "minimal";
3746
- var DEFAULT_COLOR_SCHEME = "cool-horizon";
3747
3121
  var rec2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
3748
3122
  function resolveSlideContext(presentation, index, options = {}) {
3749
3123
  const deck = rec2(presentation);
3750
3124
  const slides = Array.isArray(deck.slides) ? deck.slides : [];
3751
3125
  if (!Number.isInteger(index) || index < 0 || index >= slides.length) throw new RangeError(`Slide index ${String(index)} is outside the presentation's ${slides.length} slides.`);
3752
3126
  const slide = rec2(slides[index]);
3753
- const diagnostics = [];
3754
- const lookup = (kind, id) => {
3755
- const inline = rec2(rec2(deck.catalogs)[kind]).records;
3756
- const found = (Array.isArray(inline) ? inline : []).find((record) => record?.id === id) ?? (options.catalogs?.[kind] ?? []).find((record) => rec2(record).id === id) ?? catalogs[kind].find((record) => rec2(record).id === id);
3757
- return found === void 0 ? void 0 : rec2(found);
3758
- };
3127
+ const catalogs = { catalogs: checkCatalogsOption(options.catalogs, "resolveSlideContext") };
3128
+ const records = resolveDesignRecords(presentation, index, catalogs);
3129
+ const diagnostics = [...records.diagnostics];
3130
+ const { theme, colorScheme, fontScheme } = records;
3759
3131
  const design = { ...rec2(deck.design), ...rec2(slide.design) };
3760
- const own2 = rec2(slide.design), shared = rec2(deck.design);
3761
- const resolveReference = (kind, reference, path, code, fallbackId) => {
3762
- const object2 = typeof reference === "object" && reference !== null && !Array.isArray(reference) ? rec2(reference) : {};
3763
- const id = typeof reference === "string" ? reference : typeof object2.id === "string" ? object2.id : void 0;
3764
- if (id === void 0 && typeof reference === "object" && reference !== null && !Array.isArray(reference)) return { ...lookup(kind, fallbackId), ...object2 };
3765
- const found = id === void 0 ? void 0 : lookup(kind, id);
3766
- const inline = Object.keys(object2).some((key) => key !== "id");
3767
- if (id !== void 0 && found === void 0 && !inline) {
3768
- diagnostics.push({
3769
- code,
3770
- path,
3771
- id,
3772
- fallback: fallbackId,
3773
- message: `${kind === "themes" ? "Theme" : "Colour scheme"} '${id}' is not in the inline, host or bundled catalogs; using '${fallbackId}'.`
3774
- });
3775
- return { ...lookup(kind, fallbackId), ...object2 };
3776
- }
3777
- return { ...found, ...object2 };
3778
- };
3779
- const themePath = own2.theme !== void 0 ? `slides.${index}.design.theme` : "design.theme";
3780
- const theme = resolveReference("themes", design.theme ?? DEFAULT_THEME, themePath, "unresolved-theme", DEFAULT_THEME);
3781
- const colorSchemePath = own2.colorScheme !== void 0 ? `slides.${index}.design.colorScheme` : shared.colorScheme !== void 0 ? "design.colorScheme" : themePath;
3782
- const colorScheme = resolveReference("colorSchemes", design.colorScheme ?? theme.colorScheme ?? DEFAULT_COLOR_SCHEME, colorSchemePath, "unresolved-color-scheme", DEFAULT_COLOR_SCHEME);
3783
- const fontSchemePath = own2.fontScheme !== void 0 ? `slides.${index}.design.fontScheme` : shared.fontScheme !== void 0 ? "design.fontScheme" : themePath;
3784
- const font = resolveFontSchemeReference(design.fontScheme ?? theme.fontScheme ?? DEFAULT_FONT_SCHEME, (id) => lookup("fontSchemes", id), fontSchemePath);
3785
- if (font.diagnostic) diagnostics.push(font.diagnostic);
3786
3132
  let layout;
3133
+ let layoutProvenance;
3787
3134
  if (typeof slide.layout === "string") {
3788
- layout = lookup("layouts", slide.layout);
3789
- if (!layout) diagnostics.push({ code: "unresolved-layout", path: `slides.${index}.layout`, id: slide.layout, message: `Layout '${slide.layout}' is not in the inline or bundled catalogs.` });
3135
+ const found = resolveReference(presentation, "layouts", slide.layout, catalogs);
3136
+ if (found) {
3137
+ layout = { ...found.record };
3138
+ layoutProvenance = provenanceOf(found);
3139
+ } else diagnostics.push(unresolvedReference(presentation, "layouts", slide.layout, `slides.${index}.layout`, catalogs));
3790
3140
  }
3141
+ if (options.strictReferences && diagnostics.length) throw new OPFUnresolvedReferenceError(diagnostics);
3791
3142
  const composeOptions = {
3792
3143
  ...resolveCanvasDimensions(design.dimensions ?? theme.dimensions),
3793
3144
  ...layout ? { layout } : {},
@@ -3795,13 +3146,13 @@ function resolveSlideContext(presentation, index, options = {}) {
3795
3146
  slideIndex: index,
3796
3147
  slideNumber: options.slideNumber ?? index + 1,
3797
3148
  slideCount: options.slideCount ?? slides.length,
3798
- fontFamilies: resolveFontFamilies(font.scheme),
3149
+ fontFamilies: resolveFontFamilies(fontScheme),
3799
3150
  darkBackground: resolveColorRoles(colorScheme, { background: decisionColor(design.background ?? theme.background, colorScheme, rec2(deck.variables)) }).dark,
3800
- socialPlatforms: catalogs.socialPlatforms,
3151
+ ...theme.background !== void 0 ? { themeBackground: theme.background } : {},
3801
3152
  ...options.fonts?.textMeasurement ? { textMeasurement: options.fonts.textMeasurement } : {},
3802
3153
  ...options.date !== void 0 ? { date: options.date } : {}
3803
3154
  };
3804
- return { options: composeOptions, diagnostics, resolved: { theme, colorScheme, fontScheme: font.scheme, fontSchemePath } };
3155
+ return { options: composeOptions, diagnostics, resolved: { theme, colorScheme, fontScheme, fontSchemePath: records.fontSchemePath, ...layout ? { layout } : {}, provenance: { ...layoutProvenance ? { layout: layoutProvenance } : {}, ...records.provenance } } };
3805
3156
  }
3806
3157
 
3807
3158
  // src/rule-slides.ts
@@ -4023,7 +3374,7 @@ function syntaxReport(parsed, run) {
4023
3374
  return { valid: tally.error === 0, schemaValid: null, findings, counts: tally, checks };
4024
3375
  }
4025
3376
  function validateDocument(document, run, parsed) {
4026
- const engine = validateAgainstSchema(document, "presentation", { template: run.options.template, values: run.options.values });
3377
+ const engine = validateAgainstSchema(document, "presentation", { template: run.options.template, values: run.options.values, ...run.options.catalogs ? { catalogs: run.options.catalogs } : {} });
4027
3378
  const schemaValid = engine.errors.length === 0;
4028
3379
  const slides = isObject(document) && Array.isArray(document.slides) ? document.slides : [];
4029
3380
  const auditWanted = auditInfos.some((info) => run.enabled(info));
@@ -4032,6 +3383,7 @@ function validateDocument(document, run, parsed) {
4032
3383
  const findings = [];
4033
3384
  findings.push(...engineFindings(document, engine, (ruleId) => enabledRule(findValidationRule(ruleId))));
4034
3385
  if (enabledRule(findValidationRule("opf/variable-unfilled"))) findings.push(...variableFindings(document, engine, schemaValid));
3386
+ if (enabledRule(findValidationRule("opf/undeclared-catalog"))) findings.push(...undeclaredCatalogFindings(document));
4035
3387
  if (parsed) {
4036
3388
  findings.push(...parsed.duplicates.filter((entry) => enabledRule(findValidationRule(entry.ruleId))));
4037
3389
  }
@@ -4048,13 +3400,11 @@ function validateDocument(document, run, parsed) {
4048
3400
  const auditRan = /* @__PURE__ */ new Set();
4049
3401
  if (schemaValid && auditWanted) {
4050
3402
  const doc = document;
4051
- const lookup = createLookup(doc, run.options.catalogs);
4052
3403
  const context = {
4053
3404
  document: doc,
4054
3405
  slides: buildSlides(doc, run.options),
4055
3406
  thresholds: run.thresholds,
4056
3407
  options: run.options,
4057
- lookup,
4058
3408
  chartPalette: run.chartPalette,
4059
3409
  report(info, input) {
4060
3410
  const severity = run.severity(info) ?? input.severity ?? info.severity;
@@ -4140,12 +3490,10 @@ function assertValid(value, options = {}) {
4140
3490
  if (!report.valid) throw new OPFValidationError(report);
4141
3491
  }
4142
3492
  function validateCatalogRecord(kind, value) {
4143
- if (!catalogKinds.includes(kind)) throw new TypeError(`Unknown catalog kind ${JSON.stringify(kind)}. Kinds: ${catalogKinds.join(", ")}.`);
3493
+ const kinds = Object.keys(catalogSchemaNames);
3494
+ if (!kinds.includes(kind)) throw new TypeError(`Unknown catalog kind ${JSON.stringify(kind)}. Kinds: ${kinds.join(", ")}.`);
4144
3495
  const engine = validateAgainstSchema(value, kind);
4145
- const findings = [
4146
- ...engine.errors.map((issue2) => issueFinding(issue2, issueRuleId(issue2), engine.schemaName)),
4147
- ...engine.warnings.map((issue2) => issueFinding(issue2, "opf/catalog-reference", engine.schemaName, "", "document", "warning"))
4148
- ];
3496
+ const findings = engine.errors.map((issue2) => issueFinding(issue2, issueRuleId(issue2), engine.schemaName));
4149
3497
  const tally = counts(findings);
4150
3498
  const checks = {
4151
3499
  syntax: "not-applicable",