@astryxdesign/core 0.6.2 → 0.6.3-canary.0788c49

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 (558) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/BottomSheet/BottomSheet.d.ts +1 -1
  3. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  4. package/dist/BottomSheet/BottomSheet.js +3 -1
  5. package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
  6. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  7. package/dist/BottomSheet/BottomSheetPanel.js +56 -19
  8. package/dist/Button/Button.d.ts.map +1 -1
  9. package/dist/Button/Button.js +13 -28
  10. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  11. package/dist/Chat/ChatComposer.js +10 -5
  12. package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
  13. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  14. package/dist/Chat/ChatComposerDrawer.js +48 -23
  15. package/dist/Chat/ChatComposerInput.d.ts +11 -3
  16. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  17. package/dist/Chat/ChatComposerInput.js +63 -16
  18. package/dist/Chat/ChatDictationButton.d.ts +3 -2
  19. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  20. package/dist/Chat/ChatDictationButton.js +6 -4
  21. package/dist/Chat/ChatLayout.d.ts +19 -0
  22. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  23. package/dist/Chat/ChatLayout.js +19 -0
  24. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  25. package/dist/Chat/ChatLayoutScrollButton.js +44 -34
  26. package/dist/Chat/ChatMessageBubble.d.ts +2 -0
  27. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  28. package/dist/Chat/ChatMessageBubble.js +5 -3
  29. package/dist/Chat/ChatMessageList.d.ts +2 -1
  30. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  31. package/dist/Chat/ChatMessageList.js +4 -3
  32. package/dist/Chat/ChatMessageMetadata.d.ts +5 -4
  33. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  34. package/dist/Chat/ChatMessageMetadata.js +12 -9
  35. package/dist/Chat/ChatSendButton.d.ts +2 -1
  36. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  37. package/dist/Chat/ChatSendButton.js +6 -4
  38. package/dist/Chat/index.d.ts +1 -1
  39. package/dist/Chat/index.d.ts.map +1 -1
  40. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  41. package/dist/CheckboxInput/CheckboxInput.js +12 -2
  42. package/dist/Citation/Citation.d.ts +1 -1
  43. package/dist/Citation/Citation.d.ts.map +1 -1
  44. package/dist/Citation/Citation.js +3 -2
  45. package/dist/CodeBlock/highlightRanges.d.ts.map +1 -1
  46. package/dist/CodeBlock/highlightRanges.js +14 -3
  47. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  48. package/dist/Collapsible/Collapsible.js +6 -1
  49. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  50. package/dist/CommandPalette/CommandPaletteInput.js +1 -1
  51. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  52. package/dist/ComplexSelector/ComplexSelector.js +1 -1
  53. package/dist/DateInput/DateInput.d.ts.map +1 -1
  54. package/dist/DateInput/DateInput.js +4 -4
  55. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  56. package/dist/DateInput/NativeDateField.js +16 -16
  57. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  58. package/dist/DateInput/TouchDateField.js +2 -2
  59. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  60. package/dist/DateRangeInput/DateRangeInput.js +4 -4
  61. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  62. package/dist/DateTimeInput/DateTimeInput.js +8 -8
  63. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  64. package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
  65. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
  66. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
  67. package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
  68. package/dist/Dialog/DialogHeader.d.ts +8 -1
  69. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  70. package/dist/Dialog/DialogHeader.js +13 -4
  71. package/dist/Field/InputClearButton.d.ts +4 -2
  72. package/dist/Field/InputClearButton.d.ts.map +1 -1
  73. package/dist/Field/InputClearButton.js +4 -2
  74. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  75. package/dist/Field/PanelSearchInput.js +1 -1
  76. package/dist/FileInput/FileInput.d.ts.map +1 -1
  77. package/dist/FileInput/FileInput.js +7 -7
  78. package/dist/Icon/Icon.d.ts +6 -31
  79. package/dist/Icon/Icon.d.ts.map +1 -1
  80. package/dist/Icon/Icon.js +8 -71
  81. package/dist/Icon/IconDefaultSizeContext.d.ts +4 -0
  82. package/dist/Icon/IconDefaultSizeContext.d.ts.map +1 -0
  83. package/dist/Icon/IconDefaultSizeContext.js +18 -0
  84. package/dist/Icon/IconSize.stylex.d.ts +65 -0
  85. package/dist/Icon/IconSize.stylex.d.ts.map +1 -0
  86. package/dist/Icon/IconSize.stylex.js +75 -0
  87. package/dist/Item/Item.d.ts +1 -1
  88. package/dist/Item/Item.d.ts.map +1 -1
  89. package/dist/Item/Item.js +4 -3
  90. package/dist/Kbd/Kbd.d.ts +5 -3
  91. package/dist/Kbd/Kbd.d.ts.map +1 -1
  92. package/dist/Kbd/Kbd.js +36 -42
  93. package/dist/Link/Link.d.ts.map +1 -1
  94. package/dist/Link/Link.js +6 -2
  95. package/dist/Link/useLinkComponent.d.ts +5 -15
  96. package/dist/Link/useLinkComponent.d.ts.map +1 -1
  97. package/dist/Link/useLinkComponent.js +34 -51
  98. package/dist/List/List.d.ts +19 -1
  99. package/dist/List/List.d.ts.map +1 -1
  100. package/dist/List/List.js +9 -2
  101. package/dist/List/ListContext.d.ts +1 -0
  102. package/dist/List/ListContext.d.ts.map +1 -1
  103. package/dist/List/ListContext.js +2 -1
  104. package/dist/List/ListItem.d.ts +1 -1
  105. package/dist/List/ListItem.d.ts.map +1 -1
  106. package/dist/List/ListItem.js +9 -2
  107. package/dist/Markdown/Markdown.d.ts +8 -2
  108. package/dist/Markdown/Markdown.d.ts.map +1 -1
  109. package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
  110. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
  111. package/dist/Markdown/Markdown.fr23.bench.js +150 -0
  112. package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
  113. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
  114. package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
  115. package/dist/Markdown/Markdown.js +262 -109
  116. package/dist/Markdown/ast.d.ts +162 -0
  117. package/dist/Markdown/ast.d.ts.map +1 -0
  118. package/dist/Markdown/ast.js +74 -0
  119. package/dist/Markdown/index.d.ts +5 -3
  120. package/dist/Markdown/index.d.ts.map +1 -1
  121. package/dist/Markdown/index.js +3 -2
  122. package/dist/Markdown/parser/index.d.ts +10 -0
  123. package/dist/Markdown/parser/index.d.ts.map +1 -0
  124. package/dist/Markdown/parser/index.js +10 -0
  125. package/dist/Markdown/parser.d.ts +126 -58
  126. package/dist/Markdown/parser.d.ts.map +1 -1
  127. package/dist/Markdown/parser.js +726 -177
  128. package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
  129. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
  130. package/dist/Markdown/plugins/frontmatter.js +132 -0
  131. package/dist/Markdown/plugins/index.d.ts +17 -0
  132. package/dist/Markdown/plugins/index.d.ts.map +1 -0
  133. package/dist/Markdown/plugins/index.js +14 -0
  134. package/dist/Markdown/plugins/protocol.d.ts +191 -0
  135. package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
  136. package/dist/Markdown/plugins/protocol.js +957 -0
  137. package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
  138. package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
  139. package/dist/Markdown/plugins/semanticFence.js +213 -0
  140. package/dist/Markdown/plugins/softBreaks.d.ts +3 -0
  141. package/dist/Markdown/plugins/softBreaks.d.ts.map +1 -0
  142. package/dist/Markdown/plugins/softBreaks.js +172 -0
  143. package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
  144. package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
  145. package/dist/Markdown/plugins/sourceDecoration.js +393 -0
  146. package/dist/Markdown/plugins/textTransform.d.ts +30 -0
  147. package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
  148. package/dist/Markdown/plugins/textTransform.js +374 -0
  149. package/dist/Markdown/remark.d.ts +196 -0
  150. package/dist/Markdown/remark.d.ts.map +1 -0
  151. package/dist/Markdown/remark.js +1062 -0
  152. package/dist/Markdown/url.d.ts +6 -0
  153. package/dist/Markdown/url.d.ts.map +1 -0
  154. package/dist/Markdown/url.js +31 -0
  155. package/dist/Markdown/utils.d.ts +4 -2
  156. package/dist/Markdown/utils.d.ts.map +1 -1
  157. package/dist/Markdown/utils.js +2 -1
  158. package/dist/MetadataList/MetadataList.js +3 -3
  159. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  160. package/dist/NumberInput/NumberInput.js +4 -4
  161. package/dist/Outline/index.d.ts +1 -0
  162. package/dist/Outline/index.d.ts.map +1 -1
  163. package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
  164. package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
  165. package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
  166. package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
  167. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  168. package/dist/Outline/useOutlineFromMarkdown.js +8 -3
  169. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  170. package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
  171. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  172. package/dist/PowerSearch/PowerSearchValueEditor.js +5 -0
  173. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  174. package/dist/ProgressBar/ProgressBar.js +36 -31
  175. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  176. package/dist/RadioList/RadioListItem.js +13 -1
  177. package/dist/ScrollableArea/ScrollableArea.d.ts +1 -0
  178. package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
  179. package/dist/ScrollableArea/ScrollableArea.js +1 -0
  180. package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
  181. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  182. package/dist/SegmentedControl/SegmentedControl.js +1 -0
  183. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  184. package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
  185. package/dist/Selector/Selector.d.ts +9 -7
  186. package/dist/Selector/Selector.d.ts.map +1 -1
  187. package/dist/Selector/Selector.js +16 -7
  188. package/dist/SideNav/SideNav.d.ts +2 -1
  189. package/dist/SideNav/SideNav.d.ts.map +1 -1
  190. package/dist/SideNav/SideNav.js +9 -3
  191. package/dist/Slider/Slider.d.ts.map +1 -1
  192. package/dist/Slider/Slider.js +28 -12
  193. package/dist/Spinner/Spinner.d.ts.map +1 -1
  194. package/dist/Spinner/Spinner.js +23 -7
  195. package/dist/Switch/Switch.d.ts.map +1 -1
  196. package/dist/Switch/Switch.js +11 -0
  197. package/dist/TabList/Tab.d.ts +1 -1
  198. package/dist/TabList/Tab.d.ts.map +1 -1
  199. package/dist/TabList/Tab.js +20 -7
  200. package/dist/Table/Table.d.ts +1 -0
  201. package/dist/Table/Table.d.ts.map +1 -1
  202. package/dist/Table/Table.js +29 -13
  203. package/dist/TextArea/TextArea.d.ts.map +1 -1
  204. package/dist/TextArea/TextArea.js +1 -1
  205. package/dist/TextInput/TextInput.d.ts.map +1 -1
  206. package/dist/TextInput/TextInput.js +2 -2
  207. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  208. package/dist/TimeInput/TimeInput.js +4 -4
  209. package/dist/Timer/Timer.d.ts +49 -0
  210. package/dist/Timer/Timer.d.ts.map +1 -0
  211. package/dist/Timer/Timer.js +158 -0
  212. package/dist/Timer/index.d.ts +9 -0
  213. package/dist/Timer/index.d.ts.map +1 -0
  214. package/dist/Timer/index.js +10 -0
  215. package/dist/ToggleButton/ToggleButton.d.ts +9 -6
  216. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  217. package/dist/ToggleButton/ToggleButton.js +15 -27
  218. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  219. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  220. package/dist/TopNav/TopNavMenu.js +3 -2
  221. package/dist/TreeList/TreeList.d.ts.map +1 -1
  222. package/dist/TreeList/TreeList.js +3 -0
  223. package/dist/TreeList/TreeListItem.d.ts +6 -1
  224. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  225. package/dist/TreeList/TreeListItem.js +12 -2
  226. package/dist/TreeList/TreeListTypes.d.ts +8 -1
  227. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  228. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  229. package/dist/Typeahead/BaseTypeahead.js +16 -7
  230. package/dist/astryx.css +27 -11
  231. package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
  232. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
  233. package/dist/hooks/scrollKeyboardDelegation.js +146 -0
  234. package/dist/hooks/useClickableContainer.d.ts +10 -1
  235. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  236. package/dist/hooks/useClickableContainer.js +15 -4
  237. package/dist/hooks/useScrollableArea.d.ts +6 -2
  238. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  239. package/dist/hooks/useScrollableArea.js +17 -5
  240. package/dist/index.d.ts +1 -0
  241. package/dist/index.d.ts.map +1 -1
  242. package/dist/index.js +3 -0
  243. package/dist/theme/declarationBoundary.d.ts +17 -0
  244. package/dist/theme/declarationBoundary.d.ts.map +1 -0
  245. package/dist/theme/declarationBoundary.js +343 -0
  246. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  247. package/dist/theme/derivedVarRegistry.js +4 -0
  248. package/dist/theme/generateThemeRules.d.ts +13 -7
  249. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  250. package/dist/theme/generateThemeRules.js +140 -34
  251. package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
  252. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  253. package/dist/utils/interactionOverlay.stylex.js +9 -0
  254. package/dist/utils/safeUrl.d.ts +11 -0
  255. package/dist/utils/safeUrl.d.ts.map +1 -0
  256. package/dist/utils/safeUrl.js +78 -0
  257. package/locales/af-ZA.json +530 -1
  258. package/locales/ar-SA.json +490 -1
  259. package/locales/ca-ES.json +514 -1
  260. package/locales/cs-CZ.json +498 -1
  261. package/locales/da-DK.json +522 -1
  262. package/locales/de-DE.json +522 -1
  263. package/locales/el-GR.json +498 -1
  264. package/locales/es-ES.json +510 -1
  265. package/locales/fi-FI.json +498 -1
  266. package/locales/fr-FR.json +534 -1
  267. package/locales/he-IL.json +498 -1
  268. package/locales/hu-HU.json +498 -1
  269. package/locales/it-IT.json +510 -1
  270. package/locales/ja-JP.json +490 -1
  271. package/locales/ko-KR.json +498 -1
  272. package/locales/nl-NL.json +534 -1
  273. package/locales/no-NO.json +510 -1
  274. package/locales/pl-PL.json +506 -1
  275. package/locales/pt-BR.json +506 -1
  276. package/locales/pt-PT.json +506 -1
  277. package/locales/ro-RO.json +506 -1
  278. package/locales/ru-RU.json +498 -1
  279. package/locales/sr-SP.json +498 -1
  280. package/locales/sv-SE.json +502 -1
  281. package/locales/tr-TR.json +498 -1
  282. package/locales/uk-UA.json +498 -1
  283. package/locales/vi-VN.json +502 -1
  284. package/locales/zh-CN.json +490 -1
  285. package/locales/zh-TW.json +490 -1
  286. package/package.json +24 -4
  287. package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
  288. package/src/BottomSheet/BottomSheet.spec.md +46 -20
  289. package/src/BottomSheet/BottomSheet.test.tsx +6 -3
  290. package/src/BottomSheet/BottomSheet.tsx +3 -1
  291. package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
  292. package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
  293. package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
  294. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
  295. package/src/Button/Button.doc.mjs +5 -5
  296. package/src/Button/Button.tsx +15 -13
  297. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
  298. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
  299. package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
  300. package/src/Button/__tests__/Button.a11y.states.ts +9 -0
  301. package/src/Chat/ChatComposer.doc.mjs +14 -0
  302. package/src/Chat/ChatComposer.spec.md +230 -0
  303. package/src/Chat/ChatComposer.test.tsx +57 -0
  304. package/src/Chat/ChatComposer.tsx +21 -9
  305. package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
  306. package/src/Chat/ChatComposerDrawer.spec.md +267 -0
  307. package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
  308. package/src/Chat/ChatComposerDrawer.tsx +38 -9
  309. package/src/Chat/ChatComposerInput.doc.mjs +114 -26
  310. package/src/Chat/ChatComposerInput.spec.md +185 -0
  311. package/src/Chat/ChatComposerInput.test.tsx +113 -3
  312. package/src/Chat/ChatComposerInput.tsx +78 -13
  313. package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
  314. package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
  315. package/src/Chat/ChatDictationButton.doc.mjs +3 -3
  316. package/src/Chat/ChatDictationButton.spec.md +160 -0
  317. package/src/Chat/ChatDictationButton.test.tsx +92 -27
  318. package/src/Chat/ChatDictationButton.tsx +8 -6
  319. package/src/Chat/ChatLayout.doc.mjs +12 -4
  320. package/src/Chat/ChatLayout.spec.md +271 -0
  321. package/src/Chat/ChatLayout.test.tsx +28 -0
  322. package/src/Chat/ChatLayout.tsx +19 -0
  323. package/src/Chat/ChatLayoutScrollButton.spec.md +338 -0
  324. package/src/Chat/ChatLayoutScrollButton.test.tsx +31 -0
  325. package/src/Chat/ChatLayoutScrollButton.tsx +31 -14
  326. package/src/Chat/ChatMessageBubble.doc.mjs +28 -15
  327. package/src/Chat/ChatMessageBubble.spec.md +263 -0
  328. package/src/Chat/ChatMessageBubble.test.tsx +93 -0
  329. package/src/Chat/ChatMessageBubble.tsx +8 -3
  330. package/src/Chat/ChatMessageList.spec.md +222 -0
  331. package/src/Chat/ChatMessageList.test.tsx +64 -2
  332. package/src/Chat/ChatMessageList.tsx +4 -3
  333. package/src/Chat/ChatMessageMetadata.doc.mjs +57 -3
  334. package/src/Chat/ChatMessageMetadata.spec.md +220 -0
  335. package/src/Chat/ChatMessageMetadata.test.tsx +34 -0
  336. package/src/Chat/ChatMessageMetadata.tsx +13 -13
  337. package/src/Chat/ChatSendButton.doc.mjs +32 -0
  338. package/src/Chat/ChatSendButton.spec.md +227 -0
  339. package/src/Chat/ChatSendButton.test.tsx +128 -8
  340. package/src/Chat/ChatSendButton.tsx +6 -4
  341. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +514 -0
  342. package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +740 -0
  343. package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +457 -0
  344. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +91 -0
  345. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +91 -0
  346. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +456 -0
  347. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +413 -0
  348. package/src/Chat/__tests__/ChatSendButton.a11y.chromium.spec.ts +1522 -0
  349. package/src/Chat/index.ts +1 -0
  350. package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
  351. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  352. package/src/CheckboxInput/CheckboxInput.tsx +21 -1
  353. package/src/Citation/Citation.doc.mjs +2 -2
  354. package/src/Citation/Citation.test.tsx +17 -0
  355. package/src/Citation/Citation.tsx +4 -2
  356. package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
  357. package/src/ClickableCard/ClickableCard.test.tsx +102 -5
  358. package/src/CodeBlock/highlightRanges.test.ts +143 -1
  359. package/src/CodeBlock/highlightRanges.ts +15 -5
  360. package/src/Collapsible/Collapsible.doc.mjs +11 -0
  361. package/src/Collapsible/Collapsible.test.tsx +21 -0
  362. package/src/Collapsible/Collapsible.tsx +5 -0
  363. package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
  364. package/src/ComplexSelector/ComplexSelector.tsx +6 -1
  365. package/src/DateInput/DateInput.tsx +6 -1
  366. package/src/DateInput/NativeDateField.tsx +24 -8
  367. package/src/DateInput/TouchDateField.tsx +6 -2
  368. package/src/DateRangeInput/DateRangeInput.tsx +6 -1
  369. package/src/DateTimeInput/DateTimeInput.tsx +6 -1
  370. package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
  371. package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
  372. package/src/Dialog/Dialog.doc.mjs +2 -0
  373. package/src/Dialog/DialogHeader.doc.mjs +22 -0
  374. package/src/Dialog/DialogHeader.test.tsx +167 -3
  375. package/src/Dialog/DialogHeader.tsx +37 -6
  376. package/src/Dialog/modules/DialogHeader.spec.md +101 -42
  377. package/src/DropdownMenu/DropdownMenu.test.tsx +5 -2
  378. package/src/Field/InputClearButton.test.tsx +17 -3
  379. package/src/Field/InputClearButton.tsx +5 -2
  380. package/src/Field/PanelSearchInput.tsx +5 -2
  381. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
  382. package/src/FileInput/FileInput.tsx +11 -2
  383. package/src/Icon/Icon.doc.mjs +7 -5
  384. package/src/Icon/Icon.spec.md +81 -40
  385. package/src/Icon/Icon.test.tsx +6 -3
  386. package/src/Icon/Icon.tsx +20 -68
  387. package/src/Icon/IconDefaultSizeContext.ts +23 -0
  388. package/src/Icon/IconSize.stylex.ts +70 -0
  389. package/src/IconButton/IconButton.doc.mjs +3 -3
  390. package/src/IconButton/IconButton.test.tsx +40 -0
  391. package/src/Item/Item.doc.mjs +6 -2
  392. package/src/Item/Item.tsx +9 -3
  393. package/src/Kbd/Kbd.doc.mjs +3 -3
  394. package/src/Kbd/Kbd.test.tsx +57 -1
  395. package/src/Kbd/Kbd.tsx +57 -37
  396. package/src/Layout/LayoutFooter.doc.mjs +17 -0
  397. package/src/Link/Link.doc.mjs +17 -4
  398. package/src/Link/Link.test.tsx +24 -0
  399. package/src/Link/Link.tsx +5 -0
  400. package/src/Link/LinkProvider.doc.mjs +2 -2
  401. package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +261 -0
  402. package/src/Link/useLinkComponent.test.tsx +333 -0
  403. package/src/Link/useLinkComponent.ts +29 -57
  404. package/src/List/List.doc.mjs +6 -0
  405. package/src/List/List.spec.md +200 -0
  406. package/src/List/List.test.tsx +117 -1
  407. package/src/List/List.tsx +22 -2
  408. package/src/List/ListContext.tsx +3 -1
  409. package/src/List/ListItem.doc.mjs +2 -2
  410. package/src/List/ListItem.source-build.test.mjs +41 -0
  411. package/src/List/ListItem.tsx +26 -2
  412. package/src/Markdown/Markdown.doc.mjs +300 -2
  413. package/src/Markdown/Markdown.fr23.bench.ts +174 -0
  414. package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
  415. package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
  416. package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
  417. package/src/Markdown/Markdown.public.test.ts +130 -3
  418. package/src/Markdown/Markdown.renderBoundary.test.tsx +72 -0
  419. package/src/Markdown/Markdown.spec.md +210 -45
  420. package/src/Markdown/Markdown.test.tsx +87 -3
  421. package/src/Markdown/Markdown.tsx +414 -135
  422. package/src/Markdown/ast.test.ts +307 -0
  423. package/src/Markdown/ast.ts +337 -0
  424. package/src/Markdown/incremental.test.ts +43 -0
  425. package/src/Markdown/index.ts +37 -1
  426. package/src/Markdown/modules/remark.spec.md +269 -0
  427. package/src/Markdown/modules/softBreaks.spec.md +137 -0
  428. package/src/Markdown/parser/index.ts +64 -0
  429. package/src/Markdown/parser.public.test.ts +103 -0
  430. package/src/Markdown/parser.test.ts +38 -6
  431. package/src/Markdown/parser.ts +1221 -242
  432. package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
  433. package/src/Markdown/plugins/frontmatter.ts +198 -0
  434. package/src/Markdown/plugins/index.ts +54 -0
  435. package/src/Markdown/plugins/protocol.test.tsx +1022 -0
  436. package/src/Markdown/plugins/protocol.ts +1618 -0
  437. package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
  438. package/src/Markdown/plugins/semanticFence.ts +424 -0
  439. package/src/Markdown/plugins/softBreaks.test.tsx +172 -0
  440. package/src/Markdown/plugins/softBreaks.ts +169 -0
  441. package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
  442. package/src/Markdown/plugins/sourceDecoration.ts +539 -0
  443. package/src/Markdown/plugins/textTransform.test.ts +467 -0
  444. package/src/Markdown/plugins/textTransform.ts +554 -0
  445. package/src/Markdown/remark.test.tsx +1877 -0
  446. package/src/Markdown/remark.ts +1574 -0
  447. package/src/Markdown/url.ts +36 -0
  448. package/src/Markdown/utils.ts +13 -1
  449. package/src/MetadataList/MetadataList.test.tsx +4 -2
  450. package/src/MetadataList/MetadataList.tsx +3 -3
  451. package/src/MultiSelector/MultiSelector.test.tsx +1 -35
  452. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
  453. package/src/NumberInput/NumberInput.tsx +6 -1
  454. package/src/Outline/Outline.doc.mjs +7 -5
  455. package/src/Outline/Outline.spec.md +1 -1
  456. package/src/Outline/index.ts +1 -0
  457. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
  458. package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
  459. package/src/Outline/useOutlineFromMarkdown.ts +15 -3
  460. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  461. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
  462. package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
  463. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +51 -0
  464. package/src/PowerSearch/PowerSearchValueEditor.tsx +4 -0
  465. package/src/ProgressBar/ProgressBar.test.tsx +29 -11
  466. package/src/ProgressBar/ProgressBar.tsx +59 -72
  467. package/src/RadioList/RadioList.doc.mjs +11 -0
  468. package/src/RadioList/RadioList.test.tsx +32 -0
  469. package/src/RadioList/RadioListItem.tsx +25 -1
  470. package/src/ScrollableArea/ScrollableArea.tsx +1 -0
  471. package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
  472. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  473. package/src/SegmentedControl/SegmentedControl.test.tsx +61 -0
  474. package/src/SegmentedControl/SegmentedControl.tsx +2 -1
  475. package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
  476. package/src/Selector/Selector.doc.mjs +3 -3
  477. package/src/Selector/Selector.spec.md +51 -49
  478. package/src/Selector/Selector.test.tsx +61 -55
  479. package/src/Selector/Selector.tsx +34 -15
  480. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
  481. package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
  482. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
  483. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
  484. package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
  485. package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +45 -0
  486. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
  487. package/src/SideNav/SideNav.doc.mjs +1 -1
  488. package/src/SideNav/SideNav.test.tsx +10 -0
  489. package/src/SideNav/SideNav.tsx +14 -2
  490. package/src/Slider/Slider.doc.mjs +17 -3
  491. package/src/Slider/Slider.test.tsx +221 -0
  492. package/src/Slider/Slider.tsx +40 -9
  493. package/src/Spinner/Spinner.test.tsx +4 -0
  494. package/src/Spinner/Spinner.tsx +31 -18
  495. package/src/Switch/Switch.doc.mjs +11 -0
  496. package/src/Switch/Switch.test.tsx +16 -0
  497. package/src/Switch/Switch.tsx +28 -0
  498. package/src/TabList/Tab.tsx +35 -7
  499. package/src/TabList/TabList.doc.mjs +11 -0
  500. package/src/TabList/TabList.spec.md +204 -0
  501. package/src/TabList/TabList.test.tsx +66 -0
  502. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
  503. package/src/Table/Table.doc.mjs +1 -1
  504. package/src/Table/Table.spec.md +54 -40
  505. package/src/Table/Table.test.tsx +83 -10
  506. package/src/Table/Table.tsx +30 -22
  507. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
  508. package/src/TextArea/TextArea.tsx +6 -1
  509. package/src/TextInput/TextInput.test.tsx +20 -1
  510. package/src/TextInput/TextInput.tsx +6 -1
  511. package/src/TimeInput/TimeInput.tsx +6 -1
  512. package/src/Timer/Timer.doc.mjs +183 -0
  513. package/src/Timer/Timer.spec.md +215 -0
  514. package/src/Timer/Timer.test.tsx +302 -0
  515. package/src/Timer/Timer.tsx +258 -0
  516. package/src/Timer/index.ts +11 -0
  517. package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
  518. package/src/ToggleButton/ToggleButton.test.tsx +299 -4
  519. package/src/ToggleButton/ToggleButton.tsx +26 -33
  520. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
  521. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
  522. package/src/Token/Token.doc.mjs +2 -2
  523. package/src/Tokenizer/Tokenizer.spec.md +142 -75
  524. package/src/TopNav/TopNavMenu.doc.mjs +2 -2
  525. package/src/TopNav/TopNavMenu.test.tsx +30 -0
  526. package/src/TopNav/TopNavMenu.tsx +7 -2
  527. package/src/TreeList/TreeList.doc.mjs +3 -3
  528. package/src/TreeList/TreeList.spec.md +123 -75
  529. package/src/TreeList/TreeList.test.tsx +29 -0
  530. package/src/TreeList/TreeList.tsx +3 -0
  531. package/src/TreeList/TreeListItem.tsx +15 -1
  532. package/src/TreeList/TreeListTypes.ts +11 -1
  533. package/src/Typeahead/BaseTypeahead.spec.md +4 -3
  534. package/src/Typeahead/BaseTypeahead.tsx +21 -7
  535. package/src/Typeahead/Typeahead.test.tsx +53 -0
  536. package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
  537. package/src/__tests__/pressState.ts +93 -0
  538. package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
  539. package/src/hooks/scrollKeyboardDelegation.ts +233 -0
  540. package/src/hooks/useClickableContainer.test.tsx +236 -0
  541. package/src/hooks/useClickableContainer.ts +20 -4
  542. package/src/hooks/useScrollableArea.doc.mjs +15 -3
  543. package/src/hooks/useScrollableArea.test.tsx +59 -1
  544. package/src/hooks/useScrollableArea.ts +34 -10
  545. package/src/index.ts +3 -0
  546. package/src/inputFontFloor.test.ts +106 -0
  547. package/src/tailwind-theme.css +0 -6
  548. package/src/theme/Theme.test.tsx +32 -0
  549. package/src/theme/declarationBoundary.test.ts +126 -0
  550. package/src/theme/declarationBoundary.ts +347 -0
  551. package/src/theme/derivedVarRegistry.test.ts +7 -0
  552. package/src/theme/derivedVarRegistry.ts +1 -0
  553. package/src/theme/generateThemeRules.test.ts +526 -1
  554. package/src/theme/generateThemeRules.ts +228 -50
  555. package/src/theme/tokenValueCompat.test.ts +4 -1
  556. package/src/utils/interactionOverlay.stylex.ts +20 -0
  557. package/src/utils/safeUrl.test.ts +88 -0
  558. package/src/utils/safeUrl.ts +85 -0
@@ -0,0 +1,1062 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file remark.ts
5
+ * @input Synchronous transform-only Remark plugins over the supported MDAST subset
6
+ * @output A Markdown transform that applies a validated round trip or fails closed
7
+ * @position Optional tree-shakeable compatibility adapter; never imported by Markdown
8
+ */
9
+
10
+ import { isMarkdownPluginData } from "./plugins/protocol.js";
11
+ import { isSafeMarkdownParserUrl } from "./url.js";
12
+
13
+ /* ------------------------------------------------------------------ *
14
+ * Public mutable tree the adapted plugin observes
15
+ * ------------------------------------------------------------------ */
16
+
17
+ /** Astryx-owned citation. Read-only inside the adapter. */
18
+
19
+ /** Astryx-owned plugin extension node. Read-only inside the adapter. */
20
+
21
+ /* ------------------------------------------------------------------ *
22
+ * Public constrained file and plugin shapes
23
+ * ------------------------------------------------------------------ */
24
+
25
+ /**
26
+ * The isolated per-invocation file. It exposes readonly source text, finite
27
+ * JSON-like data, and diagnostics — never processor registration, cross-run
28
+ * state, a compiler, I/O, or asynchronous completion.
29
+ */
30
+
31
+ /**
32
+ * A Remark transformer either mutates the tree and returns nothing or returns
33
+ * a replacement root, and an attacher may legitimately return nothing at all.
34
+ * Both shapes have to stay assignable, so `void` belongs in these unions.
35
+ */
36
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- see above
37
+
38
+ /**
39
+ * The structural shape a conventional Unified/Remark plugin already has. Its
40
+ * declared transformer may take Unified's callback parameter and may declare
41
+ * an asynchronous return union, so an existing typed plugin type-checks at the
42
+ * callsite without being rewritten. The adapter rejects an actual promise, and
43
+ * a callback-style transformer, at run time instead.
44
+ *
45
+ * Authoring a new plugin against Astryx? Annotate it with
46
+ * `MarkdownRemarkPlugin` to keep a typed tree and file.
47
+ */
48
+
49
+ /* ------------------------------------------------------------------ *
50
+ * Internal helpers
51
+ * ------------------------------------------------------------------ */
52
+
53
+ /** Links a mutable copy back to the canonical node it was copied from. */
54
+ const REMARK_ORIGIN = Symbol('astryx.markdown.remarkOrigin');
55
+
56
+ /** hast escape channels; they are raw-markup sinks, not Markdown data. */
57
+ const RAW_MARKUP_DATA_KEYS = ['hName', 'hProperties', 'hChildren'];
58
+ const PHRASING_TYPES = new Set(['text', 'inlineCode', 'inlineMath', 'break', 'strong', 'emphasis', 'delete', 'link', 'image', 'citation']);
59
+ const BLOCK_TYPES = new Set(['heading', 'paragraph', 'code', 'math', 'blockquote', 'list', 'table', 'thematicBreak', 'image']);
60
+ const PHRASING_PARENTS = new Set(['heading', 'paragraph', 'strong', 'emphasis', 'delete', 'link', 'tableCell']);
61
+ const BLOCK_PARENTS = new Set(['root', 'blockquote', 'listItem']);
62
+ const FIELDS_BY_TYPE = {
63
+ root: ['children'],
64
+ paragraph: ['children'],
65
+ heading: ['depth', 'children'],
66
+ blockquote: ['children'],
67
+ strong: ['children'],
68
+ emphasis: ['children'],
69
+ delete: ['children'],
70
+ tableRow: ['children'],
71
+ tableCell: ['children'],
72
+ text: ['value'],
73
+ inlineCode: ['value'],
74
+ inlineMath: ['value'],
75
+ math: ['value'],
76
+ code: ['lang', 'meta', 'value'],
77
+ link: ['url', 'title', 'children'],
78
+ image: ['url', 'title', 'alt'],
79
+ list: ['ordered', 'start', 'spread', 'delimiter', 'children'],
80
+ listItem: ['checked', 'spread', 'children'],
81
+ table: ['align', 'children'],
82
+ thematicBreak: [],
83
+ break: [],
84
+ citation: ['sourceId'],
85
+ extension: ['plugin', 'name', 'display', 'source']
86
+ };
87
+
88
+ /**
89
+ * MDAST node kinds Astryx recognizes by name but deliberately does not
90
+ * support. Naming them makes a rejection actionable while keeping every
91
+ * diagnostic built from adapter-owned vocabulary only.
92
+ */
93
+ const NAMED_UNSUPPORTED_TYPES = new Set(['html', 'yaml', 'toml', 'definition', 'footnote', 'footnoteDefinition', 'footnoteReference', 'imageReference', 'linkReference', 'containerDirective', 'leafDirective', 'textDirective', 'mdxjsEsm', 'mdxFlowExpression', 'mdxTextExpression', 'mdxJsxFlowElement', 'mdxJsxTextElement']);
94
+
95
+ /**
96
+ * VFile keys the profile knows about and refuses. Naming them makes the
97
+ * refusal actionable while keeping diagnostics free of plugin-chosen text.
98
+ */
99
+ const NAMED_UNSUPPORTED_FILE_KEYS = new Set(['path', 'cwd', 'history', 'basename', 'dirname', 'extname', 'stem', 'stored', 'result', 'map', 'contents']);
100
+
101
+ /** The one reason reported when a plugin declares the document unsupported. */
102
+ const FAILED_BY_PLUGIN = 'the plugin reported the document as unsupported';
103
+
104
+ /**
105
+ * A closed rejection.
106
+ *
107
+ * Its reason is assembled only from this module's own constants, so it can
108
+ * never carry document source, plugin-authored text, or a plugin-chosen
109
+ * identifier — see `knownType` and `knownField`.
110
+ */
111
+ class RemarkAdapterRejection extends Error {}
112
+
113
+ /**
114
+ * The reason for each rejection this module raised, keyed by the thrown
115
+ * object.
116
+ *
117
+ * A plugin that catches one of our rejections can reach the class through
118
+ * `error.constructor` and throw a forgery, and `message` is writable on any
119
+ * Error — so neither the class nor the message is evidence. Only a throw this
120
+ * registry recorded is trusted, and its reason is read from here.
121
+ */
122
+ const adapterReasons = new WeakMap();
123
+
124
+ /**
125
+ * Sticky failure state for the run currently on the stack.
126
+ *
127
+ * Every rejection this module raises is recorded here, not only on the throw:
128
+ * a plugin can wrap any adapter call in `try`/`catch` — a prohibited file
129
+ * read, a write, a `delete`, a processor access — and carry on as if it had
130
+ * not happened. The run must still fail, so the verdict lives somewhere the
131
+ * plugin cannot reach or rewrite.
132
+ *
133
+ * Runs never overlap: the adapter is synchronous and rejects anything
134
+ * asynchronous, so a single module-level slot is the whole story.
135
+ */
136
+ let activeRun = null;
137
+ function createRunState() {
138
+ return {
139
+ failed: false,
140
+ reason: null
141
+ };
142
+ }
143
+ function reject(reason) {
144
+ if (activeRun != null && !activeRun.failed) {
145
+ activeRun.failed = true;
146
+ activeRun.reason = reason;
147
+ }
148
+ const rejection = new RemarkAdapterRejection(reason);
149
+ adapterReasons.set(rejection, reason);
150
+ throw rejection;
151
+ }
152
+
153
+ /**
154
+ * Runs `work` with `state` as the sticky failure target, restoring whatever
155
+ * was active before.
156
+ */
157
+ function withRunState(state, work) {
158
+ const previous = activeRun;
159
+ activeRun = state;
160
+ try {
161
+ return work();
162
+ } finally {
163
+ activeRun = previous;
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Reports whether a value is thenable and, if it is, attaches a handler.
169
+ *
170
+ * An already-rejected promise with no handler becomes an unhandled rejection:
171
+ * it ends a Node SSR process by default, and its reason came from the plugin,
172
+ * so it would print document text the diagnostics work hard to keep out. The
173
+ * value is refused either way; attaching a handler only makes the refusal
174
+ * quiet.
175
+ *
176
+ * `then` is read exactly once. It may be a hostile getter — reading it can
177
+ * throw, or trip a guard of its own — so this never reads it a second time to
178
+ * re-ask the same question.
179
+ */
180
+ function defuseThenable(value) {
181
+ if (typeof value !== 'object' && typeof value !== 'function' || value === null) {
182
+ return false;
183
+ }
184
+ let then;
185
+ try {
186
+ then = value.then;
187
+ } catch {
188
+ // A `then` accessor that throws is a thenable-shaped hostile value.
189
+ return true;
190
+ }
191
+ if (typeof then !== 'function') {
192
+ return false;
193
+ }
194
+ try {
195
+ then.call(value, () => {}, () => {});
196
+ } catch {
197
+ // A `then` that throws when called is refused all the same.
198
+ }
199
+ return true;
200
+ }
201
+
202
+ /** Echoes a node type only when it is adapter-owned vocabulary. */
203
+ function knownType(type) {
204
+ return typeof type === 'string' && (Object.prototype.hasOwnProperty.call(FIELDS_BY_TYPE, type) || NAMED_UNSUPPORTED_TYPES.has(type)) ? type : 'unknown';
205
+ }
206
+
207
+ /**
208
+ * Echoes a file key only when it is a name this module already documents —
209
+ * the supported surface, or an unsupported VFile key the profile explicitly
210
+ * names. A plugin-chosen key is never echoed.
211
+ */
212
+ function knownFileKey(property) {
213
+ const key = typeof property === 'symbol' ? 'unknown' : property;
214
+ return FILE_SURFACE.has(key) || NAMED_UNSUPPORTED_FILE_KEYS.has(key) ? key : 'unknown';
215
+ }
216
+
217
+ /** Echoes a field name only when it is adapter-owned vocabulary. */
218
+ function knownField(type, field) {
219
+ return field === 'position' || field === 'data' || field === 'type' || RAW_MARKUP_DATA_KEYS.includes(field) || (FIELDS_BY_TYPE[type]?.includes(field) ?? false) ? field : 'unknown';
220
+ }
221
+ function isPlainObject(value) {
222
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
223
+ return false;
224
+ }
225
+ const prototype = Object.getPrototypeOf(value);
226
+ return prototype === Object.prototype || prototype === null;
227
+ }
228
+ const POINT_FIELDS = ['line', 'column', 'offset'];
229
+ const POSITION_FIELDS = ['start', 'end'];
230
+ function samePoint(left, right) {
231
+ if (!isPlainObject(left) || !isPlainObject(right)) {
232
+ return false;
233
+ }
234
+ for (const point of [left, right]) {
235
+ for (const field of Object.keys(point)) {
236
+ if (!POINT_FIELDS.includes(field)) {
237
+ return false;
238
+ }
239
+ }
240
+ }
241
+ return POINT_FIELDS.every(field => left[field] === right[field]);
242
+ }
243
+
244
+ /**
245
+ * Exact provenance equality: every line, column, and offset on both points.
246
+ * Comparing offsets alone would let a shifted line or column through, and the
247
+ * adapter must never quietly restore Core's position over a changed one.
248
+ */
249
+ function samePosition(left, right) {
250
+ if (left === undefined || right === undefined) {
251
+ return left === right;
252
+ }
253
+ if (!isPlainObject(left) || !isPlainObject(right)) {
254
+ return false;
255
+ }
256
+ for (const position of [left, right]) {
257
+ for (const field of Object.keys(position)) {
258
+ if (!POSITION_FIELDS.includes(field)) {
259
+ return false;
260
+ }
261
+ }
262
+ }
263
+ return samePoint(left.start, right.start) && samePoint(left.end, right.end);
264
+ }
265
+ function copyPoint(point) {
266
+ if (!isPlainObject(point)) {
267
+ return undefined;
268
+ }
269
+ const copy = {};
270
+ if (typeof point.line === 'number') {
271
+ copy.line = point.line;
272
+ }
273
+ if (typeof point.column === 'number') {
274
+ copy.column = point.column;
275
+ }
276
+ if (typeof point.offset === 'number') {
277
+ copy.offset = point.offset;
278
+ }
279
+ return copy;
280
+ }
281
+ function copyPosition(position) {
282
+ if (!isPlainObject(position)) {
283
+ return undefined;
284
+ }
285
+ const start = copyPoint(position.start);
286
+ const end = copyPoint(position.end);
287
+ return start == null || end == null ? undefined : {
288
+ start,
289
+ end
290
+ };
291
+ }
292
+ function copyData(value) {
293
+ if (Array.isArray(value)) {
294
+ const copy = [];
295
+ for (const entry of value) {
296
+ copy.push(copyData(entry));
297
+ }
298
+ return copy;
299
+ }
300
+ if (isPlainObject(value)) {
301
+ const copy = {};
302
+ for (const [key, nested] of Object.entries(value)) {
303
+ copy[key] = copyData(nested);
304
+ }
305
+ return copy;
306
+ }
307
+ return value;
308
+ }
309
+ function sameJsonValue(left, right) {
310
+ if (left === right) {
311
+ return true;
312
+ }
313
+ if (Array.isArray(left) && Array.isArray(right)) {
314
+ return left.length === right.length && left.every((item, index) => sameJsonValue(item, right[index]));
315
+ }
316
+ if (isPlainObject(left) && isPlainObject(right)) {
317
+ const leftKeys = Object.keys(left);
318
+ const rightKeys = Object.keys(right);
319
+ return leftKeys.length === rightKeys.length && leftKeys.every(key => key in right && sameJsonValue(left[key], right[key]));
320
+ }
321
+ return false;
322
+ }
323
+
324
+ /* ------------------------------------------------------------------ *
325
+ * Canonical tree → fresh mutable Remark tree
326
+ * ------------------------------------------------------------------ */
327
+
328
+ function createOriginIndex() {
329
+ return {
330
+ all: new Set()
331
+ };
332
+ }
333
+ function indexOrigin(node, index) {
334
+ index.all.add(node);
335
+ }
336
+ function toRemarkChildren(children, index) {
337
+ return Array.isArray(children) ? children.map(child => toRemarkNode(child, index)) : [];
338
+ }
339
+ function toRemarkNode(node, index) {
340
+ indexOrigin(node, index);
341
+ const copy = {
342
+ type: node.type
343
+ };
344
+ switch (node.type) {
345
+ case 'root':
346
+ case 'paragraph':
347
+ case 'blockquote':
348
+ case 'strong':
349
+ case 'emphasis':
350
+ case 'delete':
351
+ case 'tableRow':
352
+ case 'tableCell':
353
+ case 'listItem':
354
+ if (node.type === 'listItem' && typeof node.checked === 'boolean') {
355
+ copy.checked = node.checked;
356
+ }
357
+ copy.children = toRemarkChildren(node.children, index);
358
+ break;
359
+ case 'heading':
360
+ copy.depth = node.depth;
361
+ copy.children = toRemarkChildren(node.children, index);
362
+ break;
363
+ case 'text':
364
+ case 'inlineCode':
365
+ case 'inlineMath':
366
+ case 'math':
367
+ copy.value = node.value;
368
+ break;
369
+ case 'code':
370
+ copy.lang = node.lang ?? null;
371
+ // Astryx stores an absent info string as no key; MDAST spells it
372
+ // `null`. Both conversions translate, so authored fence metadata —
373
+ // which the semantic-fence helper reads — survives the round trip.
374
+ copy.meta = node.meta ?? null;
375
+ copy.value = node.value;
376
+ break;
377
+ case 'link':
378
+ copy.url = node.url;
379
+ copy.title = null;
380
+ copy.children = toRemarkChildren(node.children, index);
381
+ break;
382
+ case 'image':
383
+ copy.url = node.url;
384
+ copy.title = null;
385
+ copy.alt = node.alt;
386
+ break;
387
+ case 'list':
388
+ copy.ordered = node.ordered;
389
+ if (node.start !== undefined) {
390
+ copy.start = node.start;
391
+ }
392
+ if (node.spread !== undefined) {
393
+ copy.spread = node.spread;
394
+ }
395
+ if (node.delimiter !== undefined) {
396
+ copy.delimiter = node.delimiter;
397
+ }
398
+ copy.children = toRemarkChildren(node.children, index);
399
+ break;
400
+ case 'table':
401
+ copy.align = Array.isArray(node.align) ? [...node.align] : [];
402
+ copy.children = toRemarkChildren(node.children, index);
403
+ break;
404
+ case 'citation':
405
+ copy.sourceId = node.sourceId;
406
+ break;
407
+ case 'extension':
408
+ copy.plugin = node.plugin;
409
+ copy.name = node.name;
410
+ copy.display = node.display;
411
+ if (node.source !== undefined) {
412
+ copy.source = node.source;
413
+ }
414
+ break;
415
+ default:
416
+ break;
417
+ }
418
+ if (node.data !== undefined) {
419
+ copy.data = copyData(node.data);
420
+ }
421
+ const position = copyPosition(node.position);
422
+ if (position != null) {
423
+ copy.position = position;
424
+ }
425
+ // Enumerable so an immutable-style plugin that spreads a node keeps its
426
+ // provenance; symbol-keyed so it never reaches JSON, data, or rendering.
427
+ Object.defineProperty(copy, REMARK_ORIGIN, {
428
+ configurable: false,
429
+ enumerable: true,
430
+ value: node,
431
+ writable: false
432
+ });
433
+ return copy;
434
+ }
435
+
436
+ /* ------------------------------------------------------------------ *
437
+ * Mutated Remark tree → validated canonical tree
438
+ * ------------------------------------------------------------------ */
439
+
440
+ /**
441
+ * Resolves the canonical node a transformed node came from.
442
+ *
443
+ * Provenance travels on an enumerable symbol the adapter puts on every copy,
444
+ * so a plugin that spreads a node (`{...node}`) keeps it. Nothing else counts:
445
+ * a node that merely looks like a source node — same position, same
446
+ * discriminants, rebuilt from scratch — is a forgery, not provenance, and is
447
+ * rejected rather than matched.
448
+ */
449
+ function resolveOrigin(node, type, context) {
450
+ const linked = node[REMARK_ORIGIN];
451
+ if (linked === undefined) {
452
+ return null;
453
+ }
454
+ if (!isPlainObject(linked) || !context.index.all.has(linked)) {
455
+ reject(`a "${knownType(type)}" node carries forged provenance`);
456
+ }
457
+ if (linked.type !== type) {
458
+ reject(`a source "${knownType(linked.type)}" node cannot be retyped`);
459
+ }
460
+ if (context.used.has(linked)) {
461
+ reject(`a source "${knownType(type)}" node cannot be duplicated`);
462
+ }
463
+ context.used.add(linked);
464
+ return linked;
465
+ }
466
+ function assertKnownFields(type, node) {
467
+ const allowed = FIELDS_BY_TYPE[type];
468
+ for (const key of Object.keys(node)) {
469
+ if (key !== 'type' && key !== 'position' && key !== 'data' && !allowed.includes(key)) {
470
+ reject(`a "${knownType(type)}" node cannot carry the unsupported field "${knownField(type, key)}"`);
471
+ }
472
+ }
473
+ }
474
+ function convertData(type, value) {
475
+ if (value === undefined) {
476
+ return undefined;
477
+ }
478
+ if (isPlainObject(value)) {
479
+ for (const key of RAW_MARKUP_DATA_KEYS) {
480
+ if (key in value) {
481
+ reject(`a "${knownType(type)}" node cannot carry the raw-markup data channel "${key}"`);
482
+ }
483
+ }
484
+ }
485
+ if (!isMarkdownPluginData(value)) {
486
+ reject(`a "${knownType(type)}" node's data must be finite JSON-like values`);
487
+ }
488
+ return copyData(value);
489
+ }
490
+ function requireString(type, field, value) {
491
+ if (typeof value !== 'string') {
492
+ reject(`a "${knownType(type)}" node requires a string "${knownField(type, field)}"`);
493
+ }
494
+ return value;
495
+ }
496
+ function requireAbsentText(type, field, value) {
497
+ if (value !== undefined && value !== null && value !== '') {
498
+ reject(`a "${knownType(type)}" node's "${knownField(type, field)}" has no Astryx representation`);
499
+ }
500
+ }
501
+ function assertPlacement(type, node, parentType, insideLink) {
502
+ if (parentType == null) {
503
+ return;
504
+ }
505
+ if (type === 'root') {
506
+ reject('a document can only contain one root');
507
+ }
508
+ const display = type === 'extension' ? node.display : undefined;
509
+ const phrasing = PHRASING_TYPES.has(type) || display === 'inline';
510
+ const block = BLOCK_TYPES.has(type) || display === 'block';
511
+ if (PHRASING_PARENTS.has(parentType) && !phrasing || BLOCK_PARENTS.has(parentType) && !block || parentType === 'list' && type !== 'listItem' || parentType === 'table' && type !== 'tableRow' || parentType === 'tableRow' && type !== 'tableCell') {
512
+ reject(`a "${knownType(type)}" node cannot be a child of a "${knownType(parentType)}" node`);
513
+ }
514
+ if (insideLink && type === 'link') {
515
+ reject('a link cannot be nested inside another link');
516
+ }
517
+ }
518
+ function sameCanonicalFields(origin, fields) {
519
+ // Canonical nodes may carry explicitly undefined optional keys; an absent
520
+ // key and an undefined key mean the same thing.
521
+ const originKeys = Object.keys(origin).filter(key => key !== 'type' && origin[key] !== undefined);
522
+ const fieldKeys = Object.keys(fields).filter(key => fields[key] !== undefined);
523
+ if (originKeys.length !== fieldKeys.length) {
524
+ return false;
525
+ }
526
+ for (const key of fieldKeys) {
527
+ const next = fields[key];
528
+ const previous = origin[key];
529
+ if (next === previous) {
530
+ continue;
531
+ }
532
+ if (Array.isArray(next) && Array.isArray(previous)) {
533
+ if (next.length !== previous.length || next.some((item, position) => item !== previous[position])) {
534
+ return false;
535
+ }
536
+ continue;
537
+ }
538
+ if (!sameJsonValue(next, previous)) {
539
+ return false;
540
+ }
541
+ }
542
+ return true;
543
+ }
544
+ function buildCanonicalNode(type, fields, origin) {
545
+ if (origin != null && sameCanonicalFields(origin, fields)) {
546
+ return origin;
547
+ }
548
+ const built = {
549
+ type,
550
+ ...fields
551
+ };
552
+ if (origin != null) {
553
+ // Carries Core's own enumerable symbol markers (source-heading identity)
554
+ // onto the replacement so Core still recognizes the node it authored.
555
+ for (const marker of Object.getOwnPropertySymbols(origin)) {
556
+ if (Object.prototype.propertyIsEnumerable.call(origin, marker)) {
557
+ Object.defineProperty(built, marker, {
558
+ configurable: false,
559
+ enumerable: true,
560
+ value: origin[marker],
561
+ writable: false
562
+ });
563
+ }
564
+ }
565
+ }
566
+ return built;
567
+ }
568
+ function fromRemarkChildren(children, type, insideLink, context) {
569
+ if (!Array.isArray(children)) {
570
+ reject(`a "${knownType(type)}" node requires a children array`);
571
+ }
572
+ return children.map(child => fromRemarkNode(child, type, insideLink || type === 'link', context));
573
+ }
574
+ function fromRemarkNode(value, parentType, insideLink, context) {
575
+ if (!isPlainObject(value)) {
576
+ reject('every transformed node must be a plain object');
577
+ }
578
+ const type = value.type;
579
+ if (typeof type !== 'string') {
580
+ reject('every transformed node requires a string type');
581
+ }
582
+ if (type === 'html') {
583
+ reject('raw HTML has no Astryx representation');
584
+ }
585
+ if (!(type in FIELDS_BY_TYPE)) {
586
+ reject(`the node type "${knownType(type)}" is outside the supported MDAST subset`);
587
+ }
588
+ assertKnownFields(type, value);
589
+ assertPlacement(type, value, parentType, insideLink);
590
+ const origin = resolveOrigin(value, type, context);
591
+ if (origin == null) {
592
+ if (value.position !== undefined) {
593
+ reject(`a new "${knownType(type)}" node cannot carry a source position`);
594
+ }
595
+ } else if (!samePosition(value.position, origin.position)) {
596
+ // Covers a removed, rebuilt, offset-shifted, and line/column-shifted
597
+ // position alike. Core's position is never restored over a changed one.
598
+ reject(`a source "${knownType(type)}" node's position must stay exactly as Core authored it`);
599
+ }
600
+ const fields = {};
601
+ switch (type) {
602
+ case 'root':
603
+ case 'paragraph':
604
+ case 'blockquote':
605
+ case 'strong':
606
+ case 'emphasis':
607
+ case 'delete':
608
+ case 'tableRow':
609
+ case 'tableCell':
610
+ fields.children = fromRemarkChildren(value.children, type, insideLink, context);
611
+ break;
612
+ case 'heading':
613
+ {
614
+ const depth = value.depth;
615
+ if (typeof depth !== 'number' || !Number.isInteger(depth) || depth < 1 || depth > 6) {
616
+ reject('a heading requires a depth between 1 and 6');
617
+ }
618
+ if (origin != null && origin.depth !== depth) {
619
+ reject("a source heading's depth cannot change");
620
+ }
621
+ fields.depth = depth;
622
+ fields.children = fromRemarkChildren(value.children, type, insideLink, context);
623
+ break;
624
+ }
625
+ case 'listItem':
626
+ {
627
+ const checked = value.checked;
628
+ if (checked !== undefined && checked !== null) {
629
+ if (typeof checked !== 'boolean') {
630
+ reject('a list item requires a boolean "checked" value');
631
+ }
632
+ fields.checked = checked;
633
+ }
634
+ if (value.spread === true) {
635
+ reject('a loose list item has no Astryx representation');
636
+ }
637
+ fields.children = fromRemarkChildren(value.children, type, insideLink, context);
638
+ break;
639
+ }
640
+ case 'text':
641
+ case 'inlineCode':
642
+ case 'inlineMath':
643
+ case 'math':
644
+ fields.value = requireString(type, 'value', value.value);
645
+ break;
646
+ case 'code':
647
+ {
648
+ const lang = value.lang;
649
+ if (lang !== undefined && lang !== null && typeof lang !== 'string') {
650
+ reject('a code node requires a string or null "lang"');
651
+ }
652
+ const meta = value.meta;
653
+ if (meta !== undefined && meta !== null && typeof meta !== 'string') {
654
+ reject('a code node requires a string or null "meta"');
655
+ }
656
+ fields.lang = lang ?? null;
657
+ if (meta != null && meta !== '') {
658
+ fields.meta = meta;
659
+ }
660
+ fields.value = requireString(type, 'value', value.value);
661
+ break;
662
+ }
663
+ case 'link':
664
+ {
665
+ const url = requireString(type, 'url', value.url);
666
+ if (!isSafeMarkdownParserUrl(url)) {
667
+ reject('a link destination was rejected by the navigation owner');
668
+ }
669
+ requireAbsentText(type, 'title', value.title);
670
+ fields.url = url;
671
+ fields.children = fromRemarkChildren(value.children, type, insideLink, context);
672
+ break;
673
+ }
674
+ case 'image':
675
+ {
676
+ const url = requireString(type, 'url', value.url);
677
+ if (!isSafeMarkdownParserUrl(url)) {
678
+ reject('an image source was rejected by the resource owner');
679
+ }
680
+ requireAbsentText(type, 'title', value.title);
681
+ if (typeof value.alt !== 'string') {
682
+ reject('an image requires its text alternative');
683
+ }
684
+ fields.url = url;
685
+ fields.alt = value.alt;
686
+ break;
687
+ }
688
+ case 'list':
689
+ {
690
+ if (typeof value.ordered !== 'boolean') {
691
+ reject('a list requires a boolean "ordered" value');
692
+ }
693
+ fields.ordered = value.ordered;
694
+ const start = value.start;
695
+ if (start !== undefined && start !== null) {
696
+ if (typeof start !== 'number' || !Number.isFinite(start)) {
697
+ reject('a list requires a finite "start" value');
698
+ }
699
+ fields.start = start;
700
+ }
701
+ if (typeof value.spread === 'boolean') {
702
+ fields.spread = value.spread;
703
+ }
704
+ const delimiter = value.delimiter;
705
+ if (delimiter !== undefined) {
706
+ if (delimiter !== '.' && delimiter !== ')') {
707
+ reject('a list requires a "." or ")" delimiter');
708
+ }
709
+ fields.delimiter = delimiter;
710
+ }
711
+ fields.children = fromRemarkChildren(value.children, type, insideLink, context);
712
+ break;
713
+ }
714
+ case 'table':
715
+ {
716
+ const align = value.align;
717
+ if (!Array.isArray(align) || !align.every(entry => entry === null || entry === 'left' || entry === 'center' || entry === 'right')) {
718
+ reject('a table requires normalized alignment values');
719
+ }
720
+ fields.align = [...align];
721
+ fields.children = fromRemarkChildren(value.children, type, insideLink, context);
722
+ break;
723
+ }
724
+ case 'thematicBreak':
725
+ case 'break':
726
+ break;
727
+ case 'citation':
728
+ case 'extension':
729
+ {
730
+ // Astryx owns these outright: the adapter can show one to a plugin but
731
+ // never lets one be authored or edited, so every field must come back
732
+ // exactly as it went out.
733
+ const unchanged = origin != null && sameJsonValue(value.data, origin.data) && (type === 'citation' ? value.sourceId === origin.sourceId : value.plugin === origin.plugin && value.name === origin.name && value.display === origin.display && value.source === origin.source);
734
+ if (!unchanged) {
735
+ reject(`an Astryx "${knownType(type)}" node cannot be authored or changed here`);
736
+ }
737
+ // Equality across every owned field proves the node round-tripped, so
738
+ // the canonical node itself stays in place.
739
+ return origin;
740
+ }
741
+ default:
742
+ reject(`the node type "${knownType(type)}" is outside the supported MDAST subset`);
743
+ }
744
+ const data = convertData(type, value.data);
745
+ if (data !== undefined) {
746
+ fields.data = data;
747
+ }
748
+ if (origin != null && origin.position !== undefined) {
749
+ fields.position = origin.position;
750
+ }
751
+ const node = buildCanonicalNode(type, fields, origin);
752
+ if (type === 'table' && node !== origin) {
753
+ const rows = fields.children;
754
+ const width = rows[0]?.children?.length ?? 0;
755
+ if (rows.some(row => row.children?.length !== width)) {
756
+ reject('a transformed table cannot have ragged rows');
757
+ }
758
+ }
759
+ return node;
760
+ }
761
+
762
+ /* ------------------------------------------------------------------ *
763
+ * Constrained file and processor guard
764
+ * ------------------------------------------------------------------ */
765
+
766
+ function createMessage(reason, place, ruleId) {
767
+ const text = reason instanceof Error ? reason.message : reason;
768
+ return {
769
+ reason: text,
770
+ fatal: false,
771
+ place: place ?? null,
772
+ ruleId: ruleId ?? null,
773
+ toString() {
774
+ return text;
775
+ }
776
+ };
777
+ }
778
+
779
+ /**
780
+ * The documented surface of the constrained file. Everything else — `path`,
781
+ * `cwd`, `history`, `basename`, `dirname`, `extname`, `stem`, `stored`, and
782
+ * any other key — is unsupported: the adapter has no filesystem, no processor,
783
+ * and no run history to answer with.
784
+ */
785
+ const FILE_SURFACE = new Set(['value', 'data', 'messages', 'message', 'fail', 'toString']);
786
+
787
+ /**
788
+ * Adapter-owned data for one invocation.
789
+ *
790
+ * It lives here rather than on the file the plugin holds, because everything
791
+ * the plugin can reach it can also rewrite — a plugin must not be able to
792
+ * fake a `fatal` message or hide one it caused. The failure verdict itself
793
+ * belongs to the run (`RunState`), which every rejection records.
794
+ */
795
+
796
+ function createConstrainedFile(source) {
797
+ const messages = [];
798
+ const state = {
799
+ data: {}
800
+ };
801
+ const target = {
802
+ get value() {
803
+ return source;
804
+ },
805
+ get data() {
806
+ return state.data;
807
+ },
808
+ get messages() {
809
+ return messages;
810
+ },
811
+ message(reason, place, ruleId) {
812
+ const message = createMessage(reason, place, ruleId);
813
+ messages.push(message);
814
+ return message;
815
+ },
816
+ fail(reason, place, ruleId) {
817
+ const message = createMessage(reason, place, ruleId);
818
+ message.fatal = true;
819
+ messages.push(message);
820
+ // `reject` records the verdict in run state, so a plugin that catches
821
+ // this and carries on has still declared the document unsupported and
822
+ // the run cannot succeed behind its back.
823
+ reject(FAILED_BY_PLUGIN);
824
+ },
825
+ toString() {
826
+ return source;
827
+ }
828
+ };
829
+
830
+ // Fails closed on every unsupported read and on every write. Returning
831
+ // `undefined` for `file.cwd` would let a plugin silently take a path that
832
+ // depends on a capability this profile does not have.
833
+ /* eslint-disable @typescript-eslint/promise-function-async -- these are
834
+ Proxy traps, not async work; the adapter is synchronous throughout. */
835
+ const file = new Proxy(target, {
836
+ get(_target, property, receiver) {
837
+ if (typeof property === 'symbol') {
838
+ // JS protocol (inspection, iteration, `instanceof`), not VFile
839
+ // surface. Answering `undefined` here cannot mislead a plugin.
840
+ return Reflect.get(target, property, receiver);
841
+ }
842
+ if (!FILE_SURFACE.has(property)) {
843
+ reject(`the file has no "${knownFileKey(property)}" in this profile`);
844
+ }
845
+ return Reflect.get(target, property, receiver);
846
+ },
847
+ set(_target, property) {
848
+ reject(`the file's "${knownFileKey(property)}" cannot be assigned in this profile`);
849
+ },
850
+ defineProperty(_target, property) {
851
+ reject(`the file's "${knownFileKey(property)}" cannot be assigned in this profile`);
852
+ },
853
+ deleteProperty(_target, property) {
854
+ reject(`the file's "${knownFileKey(property)}" cannot be assigned in this profile`);
855
+ },
856
+ // Truthfully answers "no such capability" so a plugin that feature-detects
857
+ // can take its own graceful path instead of being rejected.
858
+ has(_target, property) {
859
+ return typeof property === 'symbol' || FILE_SURFACE.has(property);
860
+ },
861
+ ownKeys() {
862
+ return [...FILE_SURFACE];
863
+ },
864
+ getOwnPropertyDescriptor(_target, property) {
865
+ return typeof property !== 'symbol' && !FILE_SURFACE.has(property) ? undefined : Reflect.getOwnPropertyDescriptor(target, property);
866
+ }
867
+ });
868
+ /* eslint-enable @typescript-eslint/promise-function-async */
869
+
870
+ return {
871
+ file,
872
+ state
873
+ };
874
+ }
875
+
876
+ /**
877
+ * Stands in for Unified's processor. Any access fails closed, so parser,
878
+ * compiler, and cross-run `data()` registration cannot be mistaken for
879
+ * supported behavior.
880
+ */
881
+ const PROCESSOR_ACCESS = 'processor registration is outside the adapter';
882
+ const processorGuard = new Proxy(Object.freeze({}), {
883
+ get() {
884
+ reject(PROCESSOR_ACCESS);
885
+ },
886
+ set() {
887
+ reject(PROCESSOR_ACCESS);
888
+ },
889
+ defineProperty() {
890
+ reject(PROCESSOR_ACCESS);
891
+ },
892
+ deleteProperty() {
893
+ reject(PROCESSOR_ACCESS);
894
+ },
895
+ apply() {
896
+ reject(PROCESSOR_ACCESS);
897
+ },
898
+ has() {
899
+ // Truthful: this stand-in offers no processor capability at all.
900
+ return false;
901
+ },
902
+ ownKeys() {
903
+ return [];
904
+ }
905
+ });
906
+
907
+ /* ------------------------------------------------------------------ *
908
+ * Public adapter
909
+ * ------------------------------------------------------------------ */
910
+
911
+ /**
912
+ * The one reason reported for a failed run.
913
+ *
914
+ * A rejection's reason is built from this module's own vocabulary, so it is
915
+ * safe to report. Anything a plugin authored — a thrown error's message, a
916
+ * `file.fail()` reason, a `file.message()` diagnostic — is not: the plugin
917
+ * read the document, so its text may quote it. Those stay on the file, which
918
+ * only the plugin sees.
919
+ */
920
+ function describeFailure(error) {
921
+ const reason = error instanceof RemarkAdapterRejection ? adapterReasons.get(error) : undefined;
922
+ return reason ?? 'the plugin threw an error';
923
+ }
924
+
925
+ /**
926
+ * Adapt one synchronous transform-only Remark plugin to a Markdown transform.
927
+ *
928
+ * The adapted plugin receives a fresh mutable copy of the canonical document
929
+ * and an isolated constrained file. Every returned or mutated tree round-trips
930
+ * through the supported MDAST subset before it becomes observable; anything
931
+ * unsupported — a parser or compiler plugin, asynchronous work, processor
932
+ * state, raw HTML, an unsupported node, a forged position, or unrepresentable
933
+ * metadata — keeps the last valid document and reports one diagnostic.
934
+ *
935
+ * Compatibility is per plugin and proven by fixtures, never inferred from a
936
+ * package name.
937
+ *
938
+ * @example
939
+ * ```
940
+ * import {createMarkdownPlugin} from '@astryxdesign/core/Markdown';
941
+ * import {createMarkdownRemarkTransform} from '@astryxdesign/core/Markdown/remark';
942
+ *
943
+ * const shouting = createMarkdownPlugin({
944
+ * name: 'shouting-headings',
945
+ * apiVersion: 1,
946
+ * transform: createMarkdownRemarkTransform(remarkShoutingHeadings),
947
+ * });
948
+ * ```
949
+ */
950
+
951
+ export function createMarkdownRemarkTransform(plugin, ...settings) {
952
+ if (typeof plugin !== 'function') {
953
+ throw new TypeError('Markdown Remark adapter: plugin must be a function');
954
+ }
955
+ let attached = false;
956
+ let transformer = null;
957
+ let attachFailure = null;
958
+ const attach = () => {
959
+ attached = true;
960
+ // The attacher can touch the processor guard and catch the rejection, so
961
+ // it gets its own sticky state; a swallowed capability access is still a
962
+ // failed attach.
963
+ const attachState = createRunState();
964
+ withRunState(attachState, () => {
965
+ try {
966
+ const created = plugin.apply(processorGuard, settings);
967
+ // Defuse before any verdict: an attacher that both tripped a guard
968
+ // and returned a rejected promise must not leave that promise
969
+ // unhandled just because the guard is reported instead.
970
+ const attacherIsAsync = defuseThenable(created);
971
+ if (attachState.failed) {
972
+ reject(attachState.reason ?? FAILED_BY_PLUGIN);
973
+ }
974
+ if (attacherIsAsync) {
975
+ reject('an asynchronous plugin is outside the adapter');
976
+ }
977
+ if (typeof created !== 'function') {
978
+ attachFailure = 'only a transform-only plugin returning one synchronous transformer is supported';
979
+ return;
980
+ }
981
+ if (created.length >= 3) {
982
+ attachFailure = 'a callback-style (asynchronous) transformer is outside the adapter';
983
+ return;
984
+ }
985
+ transformer = created;
986
+ } catch (error) {
987
+ attachFailure = describeFailure(error);
988
+ }
989
+ });
990
+ if (attachState.failed && attachFailure == null) {
991
+ attachFailure = attachState.reason;
992
+ transformer = null;
993
+ }
994
+ };
995
+ return (document, context) => {
996
+ if (!attached) {
997
+ attach();
998
+ }
999
+ const runner = transformer;
1000
+ if (runner == null) {
1001
+ context.report(`Remark adapter: ${attachFailure ?? 'the plugin failed'}`);
1002
+ return document;
1003
+ }
1004
+ const index = createOriginIndex();
1005
+ const {
1006
+ file,
1007
+ state
1008
+ } = createConstrainedFile(context.source);
1009
+ const run = createRunState();
1010
+ return withRunState(run, () => {
1011
+ try {
1012
+ const tree = toRemarkNode(document, index);
1013
+ const returned = runner(tree, file);
1014
+ // Defuse first, whatever else is wrong. A transformer that both
1015
+ // swallowed a guard refusal and returned a rejected promise still
1016
+ // gets that promise handled — the sticky verdict decides only what
1017
+ // is *reported*, never whether the promise is left dangling.
1018
+ const returnedIsAsync = defuseThenable(returned);
1019
+ if (run.failed) {
1020
+ // The plugin tripped a guard — a prohibited file key, a processor
1021
+ // access, its own fail() — and swallowed the rejection. The verdict
1022
+ // stands, and its original reason is the one reported.
1023
+ reject(run.reason ?? FAILED_BY_PLUGIN);
1024
+ }
1025
+ if (returnedIsAsync) {
1026
+ reject('an asynchronous transformer is outside the adapter');
1027
+ }
1028
+ const output = returned ?? tree;
1029
+ if (!isMarkdownPluginData(state.data)) {
1030
+ reject('file data must be finite JSON-like values');
1031
+ }
1032
+ const back = {
1033
+ index,
1034
+ used: new Set()
1035
+ };
1036
+ const root = fromRemarkNode(output, null, false, back);
1037
+ if (root.type !== 'root') {
1038
+ reject('a transformer must return the document root');
1039
+ }
1040
+ const children = root.children;
1041
+ if (context.display === 'inline' && (children.length !== 1 || children[0]?.type !== 'paragraph')) {
1042
+ reject('an inline document must stay one paragraph of phrasing content');
1043
+ }
1044
+ if (run.failed) {
1045
+ // Last word before the output becomes observable. A guard can fire
1046
+ // after the earlier check — a hostile `then` accessor, a getter on
1047
+ // a returned node — and a refusal the plugin caught must never end
1048
+ // with its output accepted.
1049
+ reject(run.reason ?? FAILED_BY_PLUGIN);
1050
+ }
1051
+ return root;
1052
+ } catch (error) {
1053
+ // Exactly one report per failed run, and never a second for the
1054
+ // plugin's own messages — see `describeFailure`. The first recorded
1055
+ // rejection outranks a later error, so swallowing one and throwing
1056
+ // something friendlier cannot change what is reported.
1057
+ context.report(`Remark adapter: ${run.reason ?? describeFailure(error)}`);
1058
+ return document;
1059
+ }
1060
+ });
1061
+ };
1062
+ }