@astryxdesign/core 0.6.2 → 0.6.3-canary.0899f21
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.
- package/CHANGELOG.md +81 -0
- package/dist/BottomSheet/BottomSheet.d.ts +1 -1
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +3 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +56 -19
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +13 -28
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +10 -5
- package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +48 -23
- package/dist/Chat/ChatComposerInput.d.ts +11 -3
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +63 -16
- package/dist/Chat/ChatDictationButton.d.ts +3 -2
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +6 -4
- package/dist/Chat/ChatLayout.d.ts +19 -0
- package/dist/Chat/ChatLayout.d.ts.map +1 -1
- package/dist/Chat/ChatLayout.js +19 -0
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +44 -34
- package/dist/Chat/ChatMessageBubble.d.ts +2 -0
- package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.js +5 -3
- package/dist/Chat/ChatMessageList.d.ts +2 -1
- package/dist/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/Chat/ChatMessageList.js +4 -3
- package/dist/Chat/ChatMessageMetadata.d.ts +5 -4
- package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
- package/dist/Chat/ChatMessageMetadata.js +12 -9
- package/dist/Chat/ChatSendButton.js +1 -1
- package/dist/Chat/index.d.ts +1 -1
- package/dist/Chat/index.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +12 -2
- package/dist/Citation/Citation.d.ts +1 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +3 -2
- package/dist/CodeBlock/highlightRanges.d.ts.map +1 -1
- package/dist/CodeBlock/highlightRanges.js +14 -3
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +6 -1
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +1 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +4 -4
- package/dist/DateInput/NativeDateField.d.ts.map +1 -1
- package/dist/DateInput/NativeDateField.js +16 -16
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +2 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +4 -4
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +8 -8
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
- package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
- package/dist/Dialog/DialogHeader.d.ts +8 -1
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +13 -4
- package/dist/Field/InputClearButton.d.ts +4 -2
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +4 -2
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +1 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +7 -7
- package/dist/Icon/Icon.d.ts +6 -31
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +8 -71
- package/dist/Icon/IconDefaultSizeContext.d.ts +4 -0
- package/dist/Icon/IconDefaultSizeContext.d.ts.map +1 -0
- package/dist/Icon/IconDefaultSizeContext.js +18 -0
- package/dist/Icon/IconSize.stylex.d.ts +65 -0
- package/dist/Icon/IconSize.stylex.d.ts.map +1 -0
- package/dist/Icon/IconSize.stylex.js +75 -0
- package/dist/Item/Item.d.ts +1 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +4 -3
- package/dist/Kbd/Kbd.d.ts +5 -3
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +36 -42
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +6 -2
- package/dist/Link/useLinkComponent.d.ts +5 -15
- package/dist/Link/useLinkComponent.d.ts.map +1 -1
- package/dist/Link/useLinkComponent.js +34 -51
- package/dist/List/List.d.ts +19 -1
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +9 -2
- package/dist/List/ListContext.d.ts +1 -0
- package/dist/List/ListContext.d.ts.map +1 -1
- package/dist/List/ListContext.js +2 -1
- package/dist/List/ListItem.d.ts +1 -1
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +9 -2
- package/dist/Markdown/Markdown.d.ts +8 -2
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
- package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
- package/dist/Markdown/Markdown.fr23.bench.js +150 -0
- package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
- package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
- package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
- package/dist/Markdown/Markdown.js +262 -109
- package/dist/Markdown/ast.d.ts +162 -0
- package/dist/Markdown/ast.d.ts.map +1 -0
- package/dist/Markdown/ast.js +74 -0
- package/dist/Markdown/index.d.ts +5 -3
- package/dist/Markdown/index.d.ts.map +1 -1
- package/dist/Markdown/index.js +3 -2
- package/dist/Markdown/parser/index.d.ts +10 -0
- package/dist/Markdown/parser/index.d.ts.map +1 -0
- package/dist/Markdown/parser/index.js +10 -0
- package/dist/Markdown/parser.d.ts +126 -58
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +716 -167
- package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
- package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
- package/dist/Markdown/plugins/frontmatter.js +132 -0
- package/dist/Markdown/plugins/index.d.ts +17 -0
- package/dist/Markdown/plugins/index.d.ts.map +1 -0
- package/dist/Markdown/plugins/index.js +14 -0
- package/dist/Markdown/plugins/protocol.d.ts +191 -0
- package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
- package/dist/Markdown/plugins/protocol.js +957 -0
- package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
- package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
- package/dist/Markdown/plugins/semanticFence.js +213 -0
- package/dist/Markdown/plugins/softBreaks.d.ts +3 -0
- package/dist/Markdown/plugins/softBreaks.d.ts.map +1 -0
- package/dist/Markdown/plugins/softBreaks.js +172 -0
- package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
- package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
- package/dist/Markdown/plugins/sourceDecoration.js +393 -0
- package/dist/Markdown/plugins/textTransform.d.ts +30 -0
- package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
- package/dist/Markdown/plugins/textTransform.js +374 -0
- package/dist/Markdown/remark.d.ts +196 -0
- package/dist/Markdown/remark.d.ts.map +1 -0
- package/dist/Markdown/remark.js +1062 -0
- package/dist/Markdown/url.d.ts +6 -0
- package/dist/Markdown/url.d.ts.map +1 -0
- package/dist/Markdown/url.js +31 -0
- package/dist/Markdown/utils.d.ts +4 -2
- package/dist/Markdown/utils.d.ts.map +1 -1
- package/dist/Markdown/utils.js +2 -1
- package/dist/MetadataList/MetadataList.js +3 -3
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +4 -4
- package/dist/Outline/index.d.ts +1 -0
- package/dist/Outline/index.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
- package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
- package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
- package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/useOutlineFromMarkdown.js +8 -3
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +5 -0
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +36 -31
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +13 -1
- package/dist/ScrollableArea/ScrollableArea.d.ts +1 -0
- package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
- package/dist/ScrollableArea/ScrollableArea.js +1 -0
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
- package/dist/Selector/Selector.d.ts +9 -7
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +16 -7
- package/dist/SideNav/SideNav.d.ts +2 -1
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +9 -3
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +28 -12
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +23 -7
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +11 -0
- package/dist/TabList/Tab.d.ts +1 -1
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +20 -7
- package/dist/Table/Table.d.ts +1 -0
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +29 -13
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +1 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +2 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +4 -4
- package/dist/Timer/Timer.d.ts +49 -0
- package/dist/Timer/Timer.d.ts.map +1 -0
- package/dist/Timer/Timer.js +158 -0
- package/dist/Timer/index.d.ts +9 -0
- package/dist/Timer/index.d.ts.map +1 -0
- package/dist/Timer/index.js +10 -0
- package/dist/ToggleButton/ToggleButton.d.ts +9 -6
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +15 -27
- package/dist/TopNav/TopNavMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +3 -2
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +3 -0
- package/dist/TreeList/TreeListItem.d.ts +6 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +12 -2
- package/dist/TreeList/TreeListTypes.d.ts +8 -1
- package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +16 -7
- package/dist/astryx.css +27 -11
- package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
- package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
- package/dist/hooks/scrollKeyboardDelegation.js +146 -0
- package/dist/hooks/useClickableContainer.d.ts +10 -1
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +15 -4
- package/dist/hooks/useScrollableArea.d.ts +6 -2
- package/dist/hooks/useScrollableArea.d.ts.map +1 -1
- package/dist/hooks/useScrollableArea.js +17 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/theme/declarationBoundary.d.ts +17 -0
- package/dist/theme/declarationBoundary.d.ts.map +1 -0
- package/dist/theme/declarationBoundary.js +343 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +4 -0
- package/dist/theme/generateThemeRules.d.ts +13 -7
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +140 -34
- package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +9 -0
- package/dist/utils/safeUrl.d.ts +11 -0
- package/dist/utils/safeUrl.d.ts.map +1 -0
- package/dist/utils/safeUrl.js +78 -0
- package/locales/af-ZA.json +530 -1
- package/locales/ar-SA.json +490 -1
- package/locales/ca-ES.json +514 -1
- package/locales/cs-CZ.json +498 -1
- package/locales/da-DK.json +522 -1
- package/locales/de-DE.json +522 -1
- package/locales/el-GR.json +498 -1
- package/locales/es-ES.json +510 -1
- package/locales/fi-FI.json +498 -1
- package/locales/fr-FR.json +534 -1
- package/locales/he-IL.json +498 -1
- package/locales/hu-HU.json +498 -1
- package/locales/it-IT.json +510 -1
- package/locales/ja-JP.json +490 -1
- package/locales/ko-KR.json +498 -1
- package/locales/nl-NL.json +534 -1
- package/locales/no-NO.json +510 -1
- package/locales/pl-PL.json +506 -1
- package/locales/pt-BR.json +506 -1
- package/locales/pt-PT.json +506 -1
- package/locales/ro-RO.json +506 -1
- package/locales/ru-RU.json +498 -1
- package/locales/sr-SP.json +498 -1
- package/locales/sv-SE.json +502 -1
- package/locales/tr-TR.json +498 -1
- package/locales/uk-UA.json +498 -1
- package/locales/vi-VN.json +502 -1
- package/locales/zh-CN.json +490 -1
- package/locales/zh-TW.json +490 -1
- package/package.json +24 -4
- package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
- package/src/BottomSheet/BottomSheet.spec.md +46 -20
- package/src/BottomSheet/BottomSheet.test.tsx +6 -3
- package/src/BottomSheet/BottomSheet.tsx +3 -1
- package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
- package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
- package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
- package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
- package/src/Button/Button.doc.mjs +5 -5
- package/src/Button/Button.tsx +15 -13
- package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
- package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
- package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
- package/src/Button/__tests__/Button.a11y.states.ts +9 -0
- package/src/Chat/ChatComposer.doc.mjs +14 -0
- package/src/Chat/ChatComposer.spec.md +230 -0
- package/src/Chat/ChatComposer.test.tsx +57 -0
- package/src/Chat/ChatComposer.tsx +21 -9
- package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
- package/src/Chat/ChatComposerDrawer.spec.md +267 -0
- package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
- package/src/Chat/ChatComposerDrawer.tsx +38 -9
- package/src/Chat/ChatComposerInput.doc.mjs +114 -26
- package/src/Chat/ChatComposerInput.spec.md +185 -0
- package/src/Chat/ChatComposerInput.test.tsx +113 -3
- package/src/Chat/ChatComposerInput.tsx +78 -13
- package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
- package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
- package/src/Chat/ChatDictationButton.doc.mjs +3 -3
- package/src/Chat/ChatDictationButton.spec.md +160 -0
- package/src/Chat/ChatDictationButton.test.tsx +92 -27
- package/src/Chat/ChatDictationButton.tsx +8 -6
- package/src/Chat/ChatLayout.doc.mjs +12 -4
- package/src/Chat/ChatLayout.spec.md +271 -0
- package/src/Chat/ChatLayout.test.tsx +28 -0
- package/src/Chat/ChatLayout.tsx +19 -0
- package/src/Chat/ChatLayoutScrollButton.spec.md +338 -0
- package/src/Chat/ChatLayoutScrollButton.test.tsx +31 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +31 -14
- package/src/Chat/ChatMessageBubble.doc.mjs +28 -15
- package/src/Chat/ChatMessageBubble.spec.md +263 -0
- package/src/Chat/ChatMessageBubble.test.tsx +93 -0
- package/src/Chat/ChatMessageBubble.tsx +8 -3
- package/src/Chat/ChatMessageList.spec.md +222 -0
- package/src/Chat/ChatMessageList.test.tsx +64 -2
- package/src/Chat/ChatMessageList.tsx +4 -3
- package/src/Chat/ChatMessageMetadata.doc.mjs +57 -3
- package/src/Chat/ChatMessageMetadata.spec.md +220 -0
- package/src/Chat/ChatMessageMetadata.test.tsx +34 -0
- package/src/Chat/ChatMessageMetadata.tsx +13 -13
- package/src/Chat/ChatSendButton.test.tsx +1 -4
- package/src/Chat/ChatSendButton.tsx +1 -1
- package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +514 -0
- package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +740 -0
- package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +457 -0
- package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +91 -0
- package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +91 -0
- package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +456 -0
- package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +413 -0
- package/src/Chat/index.ts +1 -0
- package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
- package/src/CheckboxInput/CheckboxInput.tsx +21 -1
- package/src/Citation/Citation.doc.mjs +2 -2
- package/src/Citation/Citation.test.tsx +17 -0
- package/src/Citation/Citation.tsx +4 -2
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
- package/src/ClickableCard/ClickableCard.test.tsx +102 -5
- package/src/CodeBlock/highlightRanges.test.ts +143 -1
- package/src/CodeBlock/highlightRanges.ts +15 -5
- package/src/Collapsible/Collapsible.doc.mjs +11 -0
- package/src/Collapsible/Collapsible.test.tsx +21 -0
- package/src/Collapsible/Collapsible.tsx +5 -0
- package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
- package/src/ComplexSelector/ComplexSelector.tsx +6 -1
- package/src/DateInput/DateInput.tsx +6 -1
- package/src/DateInput/NativeDateField.tsx +24 -8
- package/src/DateInput/TouchDateField.tsx +6 -2
- package/src/DateRangeInput/DateRangeInput.tsx +6 -1
- package/src/DateTimeInput/DateTimeInput.tsx +6 -1
- package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
- package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
- package/src/Dialog/Dialog.doc.mjs +2 -0
- package/src/Dialog/DialogHeader.doc.mjs +22 -0
- package/src/Dialog/DialogHeader.test.tsx +167 -3
- package/src/Dialog/DialogHeader.tsx +37 -6
- package/src/Dialog/modules/DialogHeader.spec.md +101 -42
- package/src/DropdownMenu/DropdownMenu.test.tsx +5 -2
- package/src/Field/InputClearButton.test.tsx +17 -3
- package/src/Field/InputClearButton.tsx +5 -2
- package/src/Field/PanelSearchInput.tsx +5 -2
- package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
- package/src/FileInput/FileInput.tsx +11 -2
- package/src/Icon/Icon.doc.mjs +7 -5
- package/src/Icon/Icon.spec.md +81 -40
- package/src/Icon/Icon.test.tsx +6 -3
- package/src/Icon/Icon.tsx +20 -68
- package/src/Icon/IconDefaultSizeContext.ts +23 -0
- package/src/Icon/IconSize.stylex.ts +70 -0
- package/src/IconButton/IconButton.doc.mjs +3 -3
- package/src/IconButton/IconButton.test.tsx +40 -0
- package/src/Item/Item.doc.mjs +6 -2
- package/src/Item/Item.tsx +9 -3
- package/src/Kbd/Kbd.doc.mjs +3 -3
- package/src/Kbd/Kbd.test.tsx +57 -1
- package/src/Kbd/Kbd.tsx +57 -37
- package/src/Layout/LayoutFooter.doc.mjs +17 -0
- package/src/Link/Link.doc.mjs +17 -4
- package/src/Link/Link.test.tsx +24 -0
- package/src/Link/Link.tsx +5 -0
- package/src/Link/LinkProvider.doc.mjs +2 -2
- package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +261 -0
- package/src/Link/useLinkComponent.test.tsx +333 -0
- package/src/Link/useLinkComponent.ts +29 -57
- package/src/List/List.doc.mjs +6 -0
- package/src/List/List.spec.md +200 -0
- package/src/List/List.test.tsx +117 -1
- package/src/List/List.tsx +22 -2
- package/src/List/ListContext.tsx +3 -1
- package/src/List/ListItem.doc.mjs +2 -2
- package/src/List/ListItem.source-build.test.mjs +41 -0
- package/src/List/ListItem.tsx +26 -2
- package/src/Markdown/Markdown.doc.mjs +300 -2
- package/src/Markdown/Markdown.fr23.bench.ts +174 -0
- package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
- package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
- package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
- package/src/Markdown/Markdown.public.test.ts +130 -3
- package/src/Markdown/Markdown.renderBoundary.test.tsx +72 -0
- package/src/Markdown/Markdown.spec.md +203 -45
- package/src/Markdown/Markdown.test.tsx +63 -0
- package/src/Markdown/Markdown.tsx +414 -135
- package/src/Markdown/ast.test.ts +307 -0
- package/src/Markdown/ast.ts +337 -0
- package/src/Markdown/incremental.test.ts +12 -0
- package/src/Markdown/index.ts +37 -1
- package/src/Markdown/modules/remark.spec.md +269 -0
- package/src/Markdown/modules/softBreaks.spec.md +137 -0
- package/src/Markdown/parser/index.ts +64 -0
- package/src/Markdown/parser.public.test.ts +103 -0
- package/src/Markdown/parser.test.ts +20 -0
- package/src/Markdown/parser.ts +1180 -235
- package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
- package/src/Markdown/plugins/frontmatter.ts +198 -0
- package/src/Markdown/plugins/index.ts +54 -0
- package/src/Markdown/plugins/protocol.test.tsx +1022 -0
- package/src/Markdown/plugins/protocol.ts +1618 -0
- package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
- package/src/Markdown/plugins/semanticFence.ts +424 -0
- package/src/Markdown/plugins/softBreaks.test.tsx +172 -0
- package/src/Markdown/plugins/softBreaks.ts +169 -0
- package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
- package/src/Markdown/plugins/sourceDecoration.ts +539 -0
- package/src/Markdown/plugins/textTransform.test.ts +467 -0
- package/src/Markdown/plugins/textTransform.ts +554 -0
- package/src/Markdown/remark.test.tsx +1877 -0
- package/src/Markdown/remark.ts +1574 -0
- package/src/Markdown/url.ts +36 -0
- package/src/Markdown/utils.ts +13 -1
- package/src/MetadataList/MetadataList.test.tsx +4 -2
- package/src/MetadataList/MetadataList.tsx +3 -3
- package/src/MultiSelector/MultiSelector.test.tsx +1 -35
- package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
- package/src/NumberInput/NumberInput.tsx +6 -1
- package/src/Outline/Outline.doc.mjs +7 -5
- package/src/Outline/Outline.spec.md +1 -1
- package/src/Outline/index.ts +1 -0
- package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
- package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
- package/src/Outline/useOutlineFromMarkdown.ts +15 -3
- package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
- package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +51 -0
- package/src/PowerSearch/PowerSearchValueEditor.tsx +4 -0
- package/src/ProgressBar/ProgressBar.test.tsx +29 -11
- package/src/ProgressBar/ProgressBar.tsx +59 -72
- package/src/RadioList/RadioList.doc.mjs +11 -0
- package/src/RadioList/RadioList.test.tsx +32 -0
- package/src/RadioList/RadioListItem.tsx +25 -1
- package/src/ScrollableArea/ScrollableArea.tsx +1 -0
- package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
- package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
- package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
- package/src/Selector/Selector.doc.mjs +2 -2
- package/src/Selector/Selector.spec.md +51 -49
- package/src/Selector/Selector.test.tsx +61 -55
- package/src/Selector/Selector.tsx +34 -15
- package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
- package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
- package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
- package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
- package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
- package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +45 -0
- package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
- package/src/SideNav/SideNav.doc.mjs +1 -1
- package/src/SideNav/SideNav.test.tsx +10 -0
- package/src/SideNav/SideNav.tsx +14 -2
- package/src/Slider/Slider.doc.mjs +17 -3
- package/src/Slider/Slider.test.tsx +221 -0
- package/src/Slider/Slider.tsx +40 -9
- package/src/Spinner/Spinner.test.tsx +4 -0
- package/src/Spinner/Spinner.tsx +31 -18
- package/src/Switch/Switch.doc.mjs +11 -0
- package/src/Switch/Switch.test.tsx +16 -0
- package/src/Switch/Switch.tsx +28 -0
- package/src/TabList/Tab.tsx +35 -7
- package/src/TabList/TabList.doc.mjs +11 -0
- package/src/TabList/TabList.spec.md +204 -0
- package/src/TabList/TabList.test.tsx +66 -0
- package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
- package/src/Table/Table.doc.mjs +1 -1
- package/src/Table/Table.spec.md +54 -40
- package/src/Table/Table.test.tsx +83 -10
- package/src/Table/Table.tsx +30 -22
- package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
- package/src/TextArea/TextArea.tsx +6 -1
- package/src/TextInput/TextInput.test.tsx +20 -1
- package/src/TextInput/TextInput.tsx +6 -1
- package/src/TimeInput/TimeInput.tsx +6 -1
- package/src/Timer/Timer.doc.mjs +183 -0
- package/src/Timer/Timer.spec.md +215 -0
- package/src/Timer/Timer.test.tsx +302 -0
- package/src/Timer/Timer.tsx +258 -0
- package/src/Timer/index.ts +11 -0
- package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
- package/src/ToggleButton/ToggleButton.test.tsx +299 -4
- package/src/ToggleButton/ToggleButton.tsx +26 -33
- package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
- package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
- package/src/Token/Token.doc.mjs +2 -2
- package/src/Tokenizer/Tokenizer.spec.md +142 -75
- package/src/TopNav/TopNavMenu.doc.mjs +2 -2
- package/src/TopNav/TopNavMenu.test.tsx +30 -0
- package/src/TopNav/TopNavMenu.tsx +7 -2
- package/src/TreeList/TreeList.doc.mjs +3 -3
- package/src/TreeList/TreeList.spec.md +123 -75
- package/src/TreeList/TreeList.test.tsx +29 -0
- package/src/TreeList/TreeList.tsx +3 -0
- package/src/TreeList/TreeListItem.tsx +15 -1
- package/src/TreeList/TreeListTypes.ts +11 -1
- package/src/Typeahead/BaseTypeahead.spec.md +4 -3
- package/src/Typeahead/BaseTypeahead.tsx +21 -7
- package/src/Typeahead/Typeahead.test.tsx +53 -0
- package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
- package/src/__tests__/pressState.ts +93 -0
- package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
- package/src/hooks/scrollKeyboardDelegation.ts +233 -0
- package/src/hooks/useClickableContainer.test.tsx +236 -0
- package/src/hooks/useClickableContainer.ts +20 -4
- package/src/hooks/useScrollableArea.doc.mjs +15 -3
- package/src/hooks/useScrollableArea.test.tsx +59 -1
- package/src/hooks/useScrollableArea.ts +34 -10
- package/src/index.ts +3 -0
- package/src/inputFontFloor.test.ts +106 -0
- package/src/tailwind-theme.css +0 -6
- package/src/theme/Theme.test.tsx +32 -0
- package/src/theme/declarationBoundary.test.ts +126 -0
- package/src/theme/declarationBoundary.ts +347 -0
- package/src/theme/derivedVarRegistry.test.ts +7 -0
- package/src/theme/derivedVarRegistry.ts +1 -0
- package/src/theme/generateThemeRules.test.ts +526 -1
- package/src/theme/generateThemeRules.ts +228 -50
- package/src/theme/tokenValueCompat.test.ts +4 -1
- package/src/utils/interactionOverlay.stylex.ts +20 -0
- package/src/utils/safeUrl.test.ts +88 -0
- package/src/utils/safeUrl.ts +85 -0
package/dist/Markdown/parser.js
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @file parser.ts
|
|
5
|
-
* @input Markdown string
|
|
6
|
-
* @output
|
|
7
|
-
* helpers
|
|
8
|
-
*
|
|
9
|
-
* Outline
|
|
10
|
-
* @position Core parser; consumed by Markdown.tsx and Outline
|
|
5
|
+
* @input Markdown string, released parse options, and optional ordered plugins
|
|
6
|
+
* @output Canonical MDAST-aligned nodes for public/server consumers plus unchanged
|
|
7
|
+
* released parser-node projections; shared heading slug helpers
|
|
8
|
+
* @position Core parser and compatibility boundary; consumed by public parser entry,
|
|
9
|
+
* Markdown, and Outline
|
|
11
10
|
*/
|
|
12
11
|
|
|
12
|
+
import { getMarkdownAstLegacyCodeLanguage, markMarkdownAstLegacyCodeLanguage } from "./ast.js";
|
|
13
|
+
import { applyMarkdownTransforms, freezeMarkdownPluginData, isMarkdownPluginData, prepareMarkdownPlugins, reportMarkdownPluginFailure } from "./plugins/protocol.js";
|
|
14
|
+
import { isSafeMarkdownParserUrl } from "./url.js";
|
|
15
|
+
|
|
13
16
|
// ---------------------------------------------------------------------------
|
|
14
17
|
// Types
|
|
15
18
|
// ---------------------------------------------------------------------------
|
|
@@ -36,6 +39,240 @@
|
|
|
36
39
|
* optional fields without breaking anyone.
|
|
37
40
|
*/
|
|
38
41
|
|
|
42
|
+
function projectRange(position) {
|
|
43
|
+
const start = position?.start.offset;
|
|
44
|
+
const end = position?.end.offset;
|
|
45
|
+
return start == null || end == null ? {} : {
|
|
46
|
+
range: {
|
|
47
|
+
start,
|
|
48
|
+
end
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Canonical nodes always carry Core-authored positions; the released block
|
|
55
|
+
* shape exposes them as `range` only when the caller passed `sourceRanges`,
|
|
56
|
+
* so this projection stays byte-for-byte what it has always returned.
|
|
57
|
+
*
|
|
58
|
+
* An extension node is the one kind the projection passes through instead of
|
|
59
|
+
* rebuilding field by field, so it is the one kind that could carry a
|
|
60
|
+
* canonical `position` out into released output. Strip it unless the caller
|
|
61
|
+
* asked for provenance, in which case the node keeps exactly the `position`
|
|
62
|
+
* it has always exposed.
|
|
63
|
+
*/
|
|
64
|
+
function projectExtensionNode(node, withRanges) {
|
|
65
|
+
if (withRanges || node.position === undefined) {
|
|
66
|
+
return node;
|
|
67
|
+
}
|
|
68
|
+
const {
|
|
69
|
+
position: _canonicalPosition,
|
|
70
|
+
...released
|
|
71
|
+
} = node;
|
|
72
|
+
return released;
|
|
73
|
+
}
|
|
74
|
+
function projectInlineNode(node, cache, withRanges) {
|
|
75
|
+
const cached = cache.get(node);
|
|
76
|
+
if (cached != null) {
|
|
77
|
+
return cached;
|
|
78
|
+
}
|
|
79
|
+
let projected;
|
|
80
|
+
switch (node.type) {
|
|
81
|
+
case 'text':
|
|
82
|
+
projected = {
|
|
83
|
+
type: 'text',
|
|
84
|
+
content: node.value
|
|
85
|
+
};
|
|
86
|
+
break;
|
|
87
|
+
case 'strong':
|
|
88
|
+
projected = {
|
|
89
|
+
type: 'bold',
|
|
90
|
+
children: node.children.map(child => projectInlineNode(child, cache, withRanges))
|
|
91
|
+
};
|
|
92
|
+
break;
|
|
93
|
+
case 'emphasis':
|
|
94
|
+
projected = {
|
|
95
|
+
type: 'italic',
|
|
96
|
+
children: node.children.map(child => projectInlineNode(child, cache, withRanges))
|
|
97
|
+
};
|
|
98
|
+
break;
|
|
99
|
+
case 'delete':
|
|
100
|
+
projected = {
|
|
101
|
+
type: 'strikethrough',
|
|
102
|
+
children: node.children.map(child => projectInlineNode(child, cache, withRanges))
|
|
103
|
+
};
|
|
104
|
+
break;
|
|
105
|
+
case 'inlineCode':
|
|
106
|
+
projected = {
|
|
107
|
+
type: 'code',
|
|
108
|
+
content: node.value
|
|
109
|
+
};
|
|
110
|
+
break;
|
|
111
|
+
case 'inlineMath':
|
|
112
|
+
projected = {
|
|
113
|
+
type: 'math',
|
|
114
|
+
value: node.value
|
|
115
|
+
};
|
|
116
|
+
break;
|
|
117
|
+
case 'link':
|
|
118
|
+
projected = {
|
|
119
|
+
type: 'link',
|
|
120
|
+
href: node.url,
|
|
121
|
+
children: node.children.map(child => projectInlineNode(child, cache, withRanges))
|
|
122
|
+
};
|
|
123
|
+
break;
|
|
124
|
+
case 'image':
|
|
125
|
+
projected = {
|
|
126
|
+
type: 'image',
|
|
127
|
+
src: node.url,
|
|
128
|
+
alt: node.alt
|
|
129
|
+
};
|
|
130
|
+
break;
|
|
131
|
+
case 'citation':
|
|
132
|
+
projected = {
|
|
133
|
+
type: 'citation',
|
|
134
|
+
sourceId: node.sourceId
|
|
135
|
+
};
|
|
136
|
+
break;
|
|
137
|
+
case 'break':
|
|
138
|
+
projected = {
|
|
139
|
+
type: 'break'
|
|
140
|
+
};
|
|
141
|
+
break;
|
|
142
|
+
case 'extension':
|
|
143
|
+
projected = projectExtensionNode(node, withRanges);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
cache.set(node, projected);
|
|
147
|
+
return projected;
|
|
148
|
+
}
|
|
149
|
+
function projectTableCell(node, cache, withRanges) {
|
|
150
|
+
const cached = cache.get(node);
|
|
151
|
+
if (cached != null) {
|
|
152
|
+
return cached;
|
|
153
|
+
}
|
|
154
|
+
const projected = {
|
|
155
|
+
children: node.children.map(child => projectInlineNode(child, cache, withRanges))
|
|
156
|
+
};
|
|
157
|
+
cache.set(node, projected);
|
|
158
|
+
return projected;
|
|
159
|
+
}
|
|
160
|
+
function projectListItem(node, cache, withRanges) {
|
|
161
|
+
const cached = cache.get(node);
|
|
162
|
+
if (cached != null) {
|
|
163
|
+
return cached;
|
|
164
|
+
}
|
|
165
|
+
const projected = {
|
|
166
|
+
checked: node.checked,
|
|
167
|
+
children: node.children.map(child => projectBlockNode(child, cache, withRanges))
|
|
168
|
+
};
|
|
169
|
+
cache.set(node, projected);
|
|
170
|
+
return projected;
|
|
171
|
+
}
|
|
172
|
+
function projectBlockNode(node, cache, withRanges) {
|
|
173
|
+
const cached = cache.get(node);
|
|
174
|
+
if (cached != null) {
|
|
175
|
+
return cached;
|
|
176
|
+
}
|
|
177
|
+
const metadata = withRanges ? projectRange(node.position) : {};
|
|
178
|
+
let projected;
|
|
179
|
+
switch (node.type) {
|
|
180
|
+
case 'heading':
|
|
181
|
+
projected = {
|
|
182
|
+
type: 'heading',
|
|
183
|
+
level: node.depth,
|
|
184
|
+
children: node.children.map(child => projectInlineNode(child, cache, withRanges)),
|
|
185
|
+
...metadata
|
|
186
|
+
};
|
|
187
|
+
break;
|
|
188
|
+
case 'paragraph':
|
|
189
|
+
projected = {
|
|
190
|
+
type: 'paragraph',
|
|
191
|
+
children: node.children.map(child => projectInlineNode(child, cache, withRanges)),
|
|
192
|
+
...metadata
|
|
193
|
+
};
|
|
194
|
+
break;
|
|
195
|
+
case 'code':
|
|
196
|
+
projected = {
|
|
197
|
+
type: 'codeblock',
|
|
198
|
+
language: getMarkdownAstLegacyCodeLanguage(node) ?? 'plaintext',
|
|
199
|
+
content: node.value,
|
|
200
|
+
...metadata
|
|
201
|
+
};
|
|
202
|
+
break;
|
|
203
|
+
case 'math':
|
|
204
|
+
projected = {
|
|
205
|
+
type: 'math',
|
|
206
|
+
value: node.value,
|
|
207
|
+
...metadata
|
|
208
|
+
};
|
|
209
|
+
break;
|
|
210
|
+
case 'blockquote':
|
|
211
|
+
projected = {
|
|
212
|
+
type: 'blockquote',
|
|
213
|
+
children: node.children.map(child => projectBlockNode(child, cache, withRanges)),
|
|
214
|
+
...metadata
|
|
215
|
+
};
|
|
216
|
+
break;
|
|
217
|
+
case 'list':
|
|
218
|
+
projected = {
|
|
219
|
+
type: 'list',
|
|
220
|
+
ordered: node.ordered,
|
|
221
|
+
start: node.start,
|
|
222
|
+
delimiter: node.delimiter,
|
|
223
|
+
loose: node.spread,
|
|
224
|
+
items: node.children.map(item => projectListItem(item, cache, withRanges)),
|
|
225
|
+
...metadata
|
|
226
|
+
};
|
|
227
|
+
break;
|
|
228
|
+
case 'table':
|
|
229
|
+
{
|
|
230
|
+
const [header = {
|
|
231
|
+
type: 'tableRow',
|
|
232
|
+
children: []
|
|
233
|
+
}, ...rows] = node.children;
|
|
234
|
+
projected = {
|
|
235
|
+
type: 'table',
|
|
236
|
+
headers: header.children.map(cell => projectTableCell(cell, cache, withRanges)),
|
|
237
|
+
alignments: [...node.align],
|
|
238
|
+
rows: rows.map(row => row.children.map(cell => projectTableCell(cell, cache, withRanges))),
|
|
239
|
+
...metadata
|
|
240
|
+
};
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
case 'thematicBreak':
|
|
244
|
+
projected = {
|
|
245
|
+
type: 'hr',
|
|
246
|
+
...metadata
|
|
247
|
+
};
|
|
248
|
+
break;
|
|
249
|
+
case 'image':
|
|
250
|
+
projected = {
|
|
251
|
+
type: 'image',
|
|
252
|
+
alt: node.alt,
|
|
253
|
+
src: node.url,
|
|
254
|
+
...metadata
|
|
255
|
+
};
|
|
256
|
+
break;
|
|
257
|
+
case 'extension':
|
|
258
|
+
projected = projectExtensionNode(node, withRanges);
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
cache.set(node, projected);
|
|
262
|
+
return projected;
|
|
263
|
+
}
|
|
264
|
+
function projectInlineNodes(nodes, withRanges, cache = new WeakMap()) {
|
|
265
|
+
return nodes.map(node => projectInlineNode(node, cache, withRanges));
|
|
266
|
+
}
|
|
267
|
+
function projectMarkdownRoot(root, withRanges, cache = new WeakMap()) {
|
|
268
|
+
return root.children.map(node => projectBlockNode(node, cache, withRanges));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Whether a caller asked for the released `range` field on its blocks. */
|
|
272
|
+
function wantsLegacyRanges(arg) {
|
|
273
|
+
return arg != null && typeof arg.has !== 'function' && arg.sourceRanges === true;
|
|
274
|
+
}
|
|
275
|
+
|
|
39
276
|
// ---------------------------------------------------------------------------
|
|
40
277
|
// Parse options
|
|
41
278
|
// ---------------------------------------------------------------------------
|
|
@@ -56,13 +293,37 @@
|
|
|
56
293
|
* from silently widening an exhaustive node switch.
|
|
57
294
|
*/
|
|
58
295
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
296
|
+
/**
|
|
297
|
+
* Every resolved options object is built here, so all of them share one key
|
|
298
|
+
* set in one order — and therefore one hidden class. The parser reads these
|
|
299
|
+
* fields in its hottest loops; letting an omitted-options parse and an
|
|
300
|
+
* options-bag parse produce differently-shaped objects makes those reads
|
|
301
|
+
* polymorphic in any process that does both, which is exactly what a caller
|
|
302
|
+
* comparing an empty pipeline against a configured one does.
|
|
303
|
+
*/
|
|
304
|
+
function makeResolvedOptions(fields) {
|
|
305
|
+
return {
|
|
306
|
+
sourceIds: fields.sourceIds,
|
|
307
|
+
autolink: fields.autolink,
|
|
308
|
+
math: fields.math,
|
|
309
|
+
sourceRanges: fields.sourceRanges,
|
|
310
|
+
astPositions: fields.astPositions ?? true,
|
|
311
|
+
plugins: fields.plugins,
|
|
312
|
+
isFinal: fields.isFinal,
|
|
313
|
+
allowBlockSyntax: fields.allowBlockSyntax ?? true,
|
|
314
|
+
baseOffset: fields.baseOffset,
|
|
315
|
+
linkDefs: fields.linkDefs
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
const EMPTY_OPTS = makeResolvedOptions({
|
|
319
|
+
isFinal: true
|
|
320
|
+
});
|
|
321
|
+
const EMPTY_INCREMENTAL_OPTS = makeResolvedOptions({
|
|
322
|
+
isFinal: false
|
|
323
|
+
});
|
|
324
|
+
function resolveOptions(arg, incremental = false) {
|
|
64
325
|
if (arg == null) {
|
|
65
|
-
return EMPTY_OPTS;
|
|
326
|
+
return incremental ? EMPTY_INCREMENTAL_OPTS : EMPTY_OPTS;
|
|
66
327
|
}
|
|
67
328
|
// Duck-type the legacy `ReadonlySet<string>` form: any object whose
|
|
68
329
|
// `.has` is callable is treated as the legacy sourceIds set. This is
|
|
@@ -70,18 +331,20 @@ function resolveOptions(arg) {
|
|
|
70
331
|
// or polyfilled `ReadonlySet` implementations as a `ParseOptions` bag
|
|
71
332
|
// and silently lose citation resolution.
|
|
72
333
|
if (typeof arg.has === 'function') {
|
|
73
|
-
return {
|
|
334
|
+
return makeResolvedOptions({
|
|
74
335
|
sourceIds: arg,
|
|
75
|
-
|
|
76
|
-
};
|
|
336
|
+
isFinal: !incremental
|
|
337
|
+
});
|
|
77
338
|
}
|
|
78
339
|
const opts = arg;
|
|
79
|
-
return {
|
|
340
|
+
return makeResolvedOptions({
|
|
80
341
|
sourceIds: opts.sourceIds,
|
|
81
342
|
autolink: opts.autolink,
|
|
82
343
|
math: opts.math === true ? true : undefined,
|
|
83
|
-
sourceRanges: opts.sourceRanges
|
|
84
|
-
|
|
344
|
+
sourceRanges: opts.sourceRanges,
|
|
345
|
+
plugins: opts.plugins != null && opts.plugins.length > 0 ? prepareMarkdownPlugins(opts.plugins) : undefined,
|
|
346
|
+
isFinal: incremental ? opts.isFinal === true : true
|
|
347
|
+
});
|
|
85
348
|
}
|
|
86
349
|
|
|
87
350
|
// ---------------------------------------------------------------------------
|
|
@@ -325,6 +588,11 @@ function extractLinkDefinitions(input, math = false) {
|
|
|
325
588
|
};
|
|
326
589
|
}
|
|
327
590
|
|
|
591
|
+
/** Order-independent signature of a citation-source set, for cache checks. */
|
|
592
|
+
function sourceIdsSignature(sourceIds) {
|
|
593
|
+
return sourceIds == null || sourceIds.size === 0 ? '' : [...sourceIds].sort().join('\u0000');
|
|
594
|
+
}
|
|
595
|
+
|
|
328
596
|
/** Order-independent signature of a link-definition set, for cache checks. */
|
|
329
597
|
function linkDefsSignature(defs) {
|
|
330
598
|
if (defs.size === 0) {
|
|
@@ -339,6 +607,12 @@ function linkDefsSignature(defs) {
|
|
|
339
607
|
* Returns the node plus the index just past the reference, or null when it is
|
|
340
608
|
* not a resolvable reference (caller falls through to literal handling).
|
|
341
609
|
*/
|
|
610
|
+
function protectedInlineOptions(opts) {
|
|
611
|
+
return opts.plugins == null ? opts : {
|
|
612
|
+
...opts,
|
|
613
|
+
plugins: undefined
|
|
614
|
+
};
|
|
615
|
+
}
|
|
342
616
|
function matchReferenceLink(text, start, linkDefs, opts) {
|
|
343
617
|
const textClose = text.indexOf(']', start + 1);
|
|
344
618
|
if (textClose === -1) {
|
|
@@ -355,12 +629,12 @@ function matchReferenceLink(text, start, linkDefs, opts) {
|
|
|
355
629
|
// matches nothing.
|
|
356
630
|
const label = rawLabel === '' ? linkText : rawLabel;
|
|
357
631
|
const href = linkDefs.get(normalizeLinkLabel(label));
|
|
358
|
-
if (href != null &&
|
|
632
|
+
if (href != null && isSafeMarkdownParserUrl(href)) {
|
|
359
633
|
return {
|
|
360
634
|
node: {
|
|
361
635
|
type: 'link',
|
|
362
|
-
href,
|
|
363
|
-
children: parseInlineImpl(linkText, opts)
|
|
636
|
+
url: href,
|
|
637
|
+
children: parseInlineImpl(linkText, protectedInlineOptions(opts))
|
|
364
638
|
},
|
|
365
639
|
end: labelClose + 1
|
|
366
640
|
};
|
|
@@ -374,14 +648,14 @@ function matchReferenceLink(text, start, linkDefs, opts) {
|
|
|
374
648
|
return null;
|
|
375
649
|
}
|
|
376
650
|
const href = linkDefs.get(normalizeLinkLabel(linkText));
|
|
377
|
-
if (href == null || !
|
|
651
|
+
if (href == null || !isSafeMarkdownParserUrl(href)) {
|
|
378
652
|
return null;
|
|
379
653
|
}
|
|
380
654
|
return {
|
|
381
655
|
node: {
|
|
382
656
|
type: 'link',
|
|
383
|
-
href,
|
|
384
|
-
children: parseInlineImpl(linkText, opts)
|
|
657
|
+
url: href,
|
|
658
|
+
children: parseInlineImpl(linkText, protectedInlineOptions(opts))
|
|
385
659
|
},
|
|
386
660
|
end: textClose + 1
|
|
387
661
|
};
|
|
@@ -400,11 +674,11 @@ function matchReferenceImage(text, start, linkDefs) {
|
|
|
400
674
|
const rawLabel = text.slice(altClose + 2, labelClose);
|
|
401
675
|
const label = rawLabel === '' ? alt : rawLabel;
|
|
402
676
|
const src = linkDefs.get(normalizeLinkLabel(label));
|
|
403
|
-
if (src != null &&
|
|
677
|
+
if (src != null && isSafeMarkdownParserUrl(src)) {
|
|
404
678
|
return {
|
|
405
679
|
node: {
|
|
406
680
|
type: 'image',
|
|
407
|
-
src,
|
|
681
|
+
url: src,
|
|
408
682
|
alt
|
|
409
683
|
},
|
|
410
684
|
end: labelClose + 1
|
|
@@ -417,13 +691,13 @@ function matchReferenceImage(text, start, linkDefs) {
|
|
|
417
691
|
return null;
|
|
418
692
|
}
|
|
419
693
|
const src = linkDefs.get(normalizeLinkLabel(alt));
|
|
420
|
-
if (src == null || !
|
|
694
|
+
if (src == null || !isSafeMarkdownParserUrl(src)) {
|
|
421
695
|
return null;
|
|
422
696
|
}
|
|
423
697
|
return {
|
|
424
698
|
node: {
|
|
425
699
|
type: 'image',
|
|
426
|
-
src,
|
|
700
|
+
url: src,
|
|
427
701
|
alt
|
|
428
702
|
},
|
|
429
703
|
end: altClose + 1
|
|
@@ -500,26 +774,6 @@ function findInlineMathEnd(text, start) {
|
|
|
500
774
|
}
|
|
501
775
|
|
|
502
776
|
// ---------------------------------------------------------------------------
|
|
503
|
-
// URL scheme sanitization
|
|
504
|
-
// ---------------------------------------------------------------------------
|
|
505
|
-
|
|
506
|
-
/**
|
|
507
|
-
* Reject URLs with dangerous schemes (javascript:, vbscript:, data:) that
|
|
508
|
-
* could execute arbitrary code when rendered as link hrefs or image srcs.
|
|
509
|
-
* Returns true if the URL is safe to use, false otherwise.
|
|
510
|
-
*/
|
|
511
|
-
function isSafeUrl(url) {
|
|
512
|
-
// Trim and collapse whitespace/control chars that browsers tolerate but
|
|
513
|
-
// could bypass a naive prefix check (e.g. "java\nscript:alert(1)").
|
|
514
|
-
// eslint-disable-next-line no-control-regex -- control chars are the bypass
|
|
515
|
-
const normalized = url.replace(/[\x00-\x1f\x7f]/g, '').trim();
|
|
516
|
-
const lower = normalized.toLowerCase();
|
|
517
|
-
if (lower.startsWith('javascript:') || lower.startsWith('vbscript:') || lower.startsWith('data:text/html')) {
|
|
518
|
-
return false;
|
|
519
|
-
}
|
|
520
|
-
return true;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
777
|
// ---------------------------------------------------------------------------
|
|
524
778
|
// Inline parser
|
|
525
779
|
// ---------------------------------------------------------------------------
|
|
@@ -570,8 +824,137 @@ function matchBracketCitation(text, i, opts) {
|
|
|
570
824
|
end: closeIndex + 1
|
|
571
825
|
};
|
|
572
826
|
}
|
|
827
|
+
function currentLineStart(source, offset) {
|
|
828
|
+
return source.lastIndexOf('\n', offset - 1) + 1;
|
|
829
|
+
}
|
|
830
|
+
function matchExtensionSyntax(source, offset, context, opts) {
|
|
831
|
+
const byFirstCharacter = context === 'inline' ? opts.plugins?.inlineByFirstCharacter : opts.allowBlockSyntax === false ? undefined : opts.plugins?.blockByFirstCharacter;
|
|
832
|
+
const candidates = byFirstCharacter?.get(source[offset]);
|
|
833
|
+
if (candidates == null) {
|
|
834
|
+
return {
|
|
835
|
+
status: 'none'
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
const seen = new Set();
|
|
839
|
+
for (const candidate of candidates) {
|
|
840
|
+
if (seen.has(candidate)) {
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
seen.add(candidate);
|
|
844
|
+
let fullPrefix = false;
|
|
845
|
+
for (const prefix of candidate.contribution.startsWith) {
|
|
846
|
+
if (source.startsWith(prefix, offset)) {
|
|
847
|
+
fullPrefix = true;
|
|
848
|
+
break;
|
|
849
|
+
}
|
|
850
|
+
if (!opts.isFinal) {
|
|
851
|
+
const remaining = source.slice(offset);
|
|
852
|
+
if (remaining.length < prefix.length && prefix.startsWith(remaining)) {
|
|
853
|
+
return {
|
|
854
|
+
status: 'defer'
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (!fullPrefix) {
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
const end = Math.min(source.length, offset + candidate.contribution.maxSpan);
|
|
863
|
+
let result;
|
|
864
|
+
try {
|
|
865
|
+
result = candidate.contribution.tokenize({
|
|
866
|
+
source: end === source.length ? source : source.slice(0, end),
|
|
867
|
+
offset,
|
|
868
|
+
end,
|
|
869
|
+
isFinal: opts.isFinal,
|
|
870
|
+
context,
|
|
871
|
+
lineStart: currentLineStart(source, offset),
|
|
872
|
+
column: offset - currentLineStart(source, offset)
|
|
873
|
+
});
|
|
874
|
+
} catch (error) {
|
|
875
|
+
reportMarkdownPluginFailure(candidate.pluginName, 'syntax', error);
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
if (result == null || typeof result !== 'object' || typeof result.then === 'function') {
|
|
879
|
+
reportMarkdownPluginFailure(candidate.pluginName, 'syntax', new TypeError('Tokenizer returned an invalid result'));
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
882
|
+
if (result.status === 'no-match') {
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
if (result.status === 'defer') {
|
|
886
|
+
return !opts.isFinal && end === source.length && source.length - offset < candidate.contribution.maxSpan ? {
|
|
887
|
+
status: 'defer'
|
|
888
|
+
} : {
|
|
889
|
+
status: 'none'
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
if (result.status !== 'match' || !Number.isInteger(result.end) || result.end <= offset || result.end > end || result.node.type !== 'extension' || result.node.plugin !== candidate.pluginName || result.node.display !== context || result.node.name.trim() === '' || !isMarkdownPluginData(result.node.data) || !opts.plugins?.renderers.has(`${candidate.pluginName}\0${result.node.name}`)) {
|
|
893
|
+
reportMarkdownPluginFailure(candidate.pluginName, 'syntax', new TypeError('Tokenizer returned an invalid extension node'));
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
const rawNode = result.node;
|
|
897
|
+
const {
|
|
898
|
+
source: _ignoredSource,
|
|
899
|
+
position: _ignoredPosition,
|
|
900
|
+
...safeNode
|
|
901
|
+
} = rawNode;
|
|
902
|
+
const absoluteStart = (opts.baseOffset ?? 0) + offset;
|
|
903
|
+
const absoluteEnd = (opts.baseOffset ?? 0) + result.end;
|
|
904
|
+
return {
|
|
905
|
+
status: 'match',
|
|
906
|
+
end: result.end,
|
|
907
|
+
node: Object.freeze({
|
|
908
|
+
...safeNode,
|
|
909
|
+
data: freezeMarkdownPluginData(result.node.data),
|
|
910
|
+
source: source.slice(offset, result.end),
|
|
911
|
+
...(opts.sourceRanges && context === 'block' ? {
|
|
912
|
+
position: Object.freeze({
|
|
913
|
+
start: Object.freeze({
|
|
914
|
+
offset: absoluteStart
|
|
915
|
+
}),
|
|
916
|
+
end: Object.freeze({
|
|
917
|
+
offset: absoluteEnd
|
|
918
|
+
})
|
|
919
|
+
})
|
|
920
|
+
} : null)
|
|
921
|
+
})
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
return {
|
|
925
|
+
status: 'none'
|
|
926
|
+
};
|
|
927
|
+
}
|
|
573
928
|
export function parseInline(text, arg) {
|
|
574
|
-
return
|
|
929
|
+
return projectInlineNodes(parseInlineAstRuntime(text, arg), wantsLegacyRanges(arg));
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Parse inline Markdown into the canonical immutable Astryx AST.
|
|
934
|
+
*
|
|
935
|
+
* Unlike `parseInline`, this returns MDAST-aligned node names and fields. Math
|
|
936
|
+
* nodes are present only when `math: true`, and plugin extension nodes are
|
|
937
|
+
* inferred from the ordered `plugins` tuple.
|
|
938
|
+
*/
|
|
939
|
+
|
|
940
|
+
export function parseInlineAst(text, arg) {
|
|
941
|
+
return parseInlineAstRuntime(text, arg);
|
|
942
|
+
}
|
|
943
|
+
function parseInlineAstRuntime(text, arg) {
|
|
944
|
+
const opts = resolveOptions(arg);
|
|
945
|
+
const nodes = parseInlineEntry(text, opts);
|
|
946
|
+
if ((opts.plugins?.transforms.length ?? 0) === 0) {
|
|
947
|
+
return nodes;
|
|
948
|
+
}
|
|
949
|
+
const transformed = applyMarkdownTransforms({
|
|
950
|
+
type: 'root',
|
|
951
|
+
children: [{
|
|
952
|
+
type: 'paragraph',
|
|
953
|
+
children: nodes
|
|
954
|
+
}]
|
|
955
|
+
}, opts.plugins, text, opts.isFinal, 'inline');
|
|
956
|
+
const paragraph = transformed.children[0];
|
|
957
|
+
return paragraph?.type === 'paragraph' ? [...paragraph.children] : nodes;
|
|
575
958
|
}
|
|
576
959
|
|
|
577
960
|
/**
|
|
@@ -589,13 +972,18 @@ function parseInlineEntry(text, opts) {
|
|
|
589
972
|
}
|
|
590
973
|
function parseInlineImpl(text, opts) {
|
|
591
974
|
const nodes = [];
|
|
975
|
+
// Only a plugin that actually contributes INLINE syntax may cost anything
|
|
976
|
+
// per source position. A transform-only list contributes none, so it takes
|
|
977
|
+
// the same path as an omitted or empty one: no candidate probe per
|
|
978
|
+
// position, and no map lookup per character in the plain-text scan below.
|
|
979
|
+
const inlineExtensionStarts = opts.plugins != null && opts.plugins.inlineByFirstCharacter.size > 0 ? opts.plugins.inlineByFirstCharacter : undefined;
|
|
592
980
|
let i = 0;
|
|
593
981
|
while (i < text.length) {
|
|
594
982
|
// --- Escape ---
|
|
595
983
|
if (text[i] === '\\' && i + 1 < text.length) {
|
|
596
984
|
nodes.push({
|
|
597
985
|
type: 'text',
|
|
598
|
-
|
|
986
|
+
value: text[i + 1]
|
|
599
987
|
});
|
|
600
988
|
i += 2;
|
|
601
989
|
continue;
|
|
@@ -608,8 +996,8 @@ function parseInlineImpl(text, opts) {
|
|
|
608
996
|
const closeIndex = text.indexOf('`'.repeat(tickCount), openIndex);
|
|
609
997
|
if (closeIndex !== -1) {
|
|
610
998
|
nodes.push({
|
|
611
|
-
type: '
|
|
612
|
-
|
|
999
|
+
type: 'inlineCode',
|
|
1000
|
+
value: text.slice(openIndex, closeIndex)
|
|
613
1001
|
});
|
|
614
1002
|
i = closeIndex + tickCount;
|
|
615
1003
|
continue;
|
|
@@ -621,7 +1009,7 @@ function parseInlineImpl(text, opts) {
|
|
|
621
1009
|
const closeIndex = findInlineMathEnd(text, i);
|
|
622
1010
|
if (closeIndex !== -1) {
|
|
623
1011
|
nodes.push({
|
|
624
|
-
type: '
|
|
1012
|
+
type: 'inlineMath',
|
|
625
1013
|
value: text.slice(i + 1, closeIndex)
|
|
626
1014
|
});
|
|
627
1015
|
i = closeIndex + 1;
|
|
@@ -649,16 +1037,16 @@ function parseInlineImpl(text, opts) {
|
|
|
649
1037
|
const srcClose = findClosingParen(text, altClose + 2);
|
|
650
1038
|
if (srcClose !== -1) {
|
|
651
1039
|
const src = text.slice(altClose + 2, srcClose);
|
|
652
|
-
if (!
|
|
1040
|
+
if (!isSafeMarkdownParserUrl(src)) {
|
|
653
1041
|
// Dangerous scheme — emit as plain text.
|
|
654
1042
|
nodes.push({
|
|
655
1043
|
type: 'text',
|
|
656
|
-
|
|
1044
|
+
value: text.slice(i, srcClose + 1)
|
|
657
1045
|
});
|
|
658
1046
|
} else {
|
|
659
1047
|
nodes.push({
|
|
660
1048
|
type: 'image',
|
|
661
|
-
src,
|
|
1049
|
+
url: src,
|
|
662
1050
|
alt: text.slice(i + 2, altClose)
|
|
663
1051
|
});
|
|
664
1052
|
}
|
|
@@ -698,17 +1086,17 @@ function parseInlineImpl(text, opts) {
|
|
|
698
1086
|
const urlClose = findClosingParen(text, textClose + 2);
|
|
699
1087
|
if (urlClose !== -1) {
|
|
700
1088
|
const href = text.slice(textClose + 2, urlClose);
|
|
701
|
-
if (!
|
|
1089
|
+
if (!isSafeMarkdownParserUrl(href)) {
|
|
702
1090
|
// Dangerous scheme — emit as plain text instead of a link.
|
|
703
1091
|
nodes.push({
|
|
704
1092
|
type: 'text',
|
|
705
|
-
|
|
1093
|
+
value: text.slice(i, urlClose + 1)
|
|
706
1094
|
});
|
|
707
1095
|
} else {
|
|
708
1096
|
nodes.push({
|
|
709
1097
|
type: 'link',
|
|
710
|
-
href,
|
|
711
|
-
children: parseInlineImpl(text.slice(i + 1, textClose), opts)
|
|
1098
|
+
url: href,
|
|
1099
|
+
children: parseInlineImpl(text.slice(i + 1, textClose), protectedInlineOptions(opts))
|
|
712
1100
|
});
|
|
713
1101
|
}
|
|
714
1102
|
i = urlClose + 1;
|
|
@@ -737,9 +1125,9 @@ function parseInlineImpl(text, opts) {
|
|
|
737
1125
|
const closeIndex = text.indexOf(marker, i + 3);
|
|
738
1126
|
if (closeIndex !== -1 && (!isUnderscore || !isWordChar(text[closeIndex + 3]))) {
|
|
739
1127
|
nodes.push({
|
|
740
|
-
type: '
|
|
1128
|
+
type: 'strong',
|
|
741
1129
|
children: [{
|
|
742
|
-
type: '
|
|
1130
|
+
type: 'emphasis',
|
|
743
1131
|
children: parseInlineImpl(text.slice(i + 3, closeIndex), opts)
|
|
744
1132
|
}]
|
|
745
1133
|
});
|
|
@@ -759,7 +1147,7 @@ function parseInlineImpl(text, opts) {
|
|
|
759
1147
|
const closeIndex = text.indexOf(marker, i + 2);
|
|
760
1148
|
if (closeIndex !== -1 && (!isUnderscore || !isWordChar(text[closeIndex + 2]))) {
|
|
761
1149
|
nodes.push({
|
|
762
|
-
type: '
|
|
1150
|
+
type: 'strong',
|
|
763
1151
|
children: parseInlineImpl(text.slice(i + 2, closeIndex), opts)
|
|
764
1152
|
});
|
|
765
1153
|
i = closeIndex + 2;
|
|
@@ -773,7 +1161,7 @@ function parseInlineImpl(text, opts) {
|
|
|
773
1161
|
const closeIndex = text.indexOf('~~', i + 2);
|
|
774
1162
|
if (closeIndex !== -1) {
|
|
775
1163
|
nodes.push({
|
|
776
|
-
type: '
|
|
1164
|
+
type: 'delete',
|
|
777
1165
|
children: parseInlineImpl(text.slice(i + 2, closeIndex), opts)
|
|
778
1166
|
});
|
|
779
1167
|
i = closeIndex + 2;
|
|
@@ -790,7 +1178,7 @@ function parseInlineImpl(text, opts) {
|
|
|
790
1178
|
const closeIndex = text.indexOf(text[i], i + 1);
|
|
791
1179
|
if (closeIndex !== -1 && closeIndex > i + 1 && (!isUnderscore || !isWordChar(text[closeIndex + 1]))) {
|
|
792
1180
|
nodes.push({
|
|
793
|
-
type: '
|
|
1181
|
+
type: 'emphasis',
|
|
794
1182
|
children: parseInlineImpl(text.slice(i + 1, closeIndex), opts)
|
|
795
1183
|
});
|
|
796
1184
|
i = closeIndex + 1;
|
|
@@ -799,9 +1187,22 @@ function parseInlineImpl(text, opts) {
|
|
|
799
1187
|
}
|
|
800
1188
|
}
|
|
801
1189
|
|
|
1190
|
+
// --- Extension syntax (built-ins and protected contexts win) ---
|
|
1191
|
+
if (inlineExtensionStarts !== undefined) {
|
|
1192
|
+
const extension = matchExtensionSyntax(text, i, 'inline', opts);
|
|
1193
|
+
if (extension.status === 'match') {
|
|
1194
|
+
nodes.push(extension.node);
|
|
1195
|
+
i = extension.end;
|
|
1196
|
+
continue;
|
|
1197
|
+
}
|
|
1198
|
+
if (extension.status === 'defer') {
|
|
1199
|
+
break;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
|
|
802
1203
|
// --- Plain text (with line-break detection) ---
|
|
803
1204
|
let end = i + 1;
|
|
804
|
-
while (end < text.length && !'*_~`[!\\\n\u3010'.includes(text[end]) && !(opts.math && text[end] === '$')) {
|
|
1205
|
+
while (end < text.length && !'*_~`[!\\\n\u3010'.includes(text[end]) && !(opts.math && text[end] === '$') && (inlineExtensionStarts === undefined || !inlineExtensionStarts.has(text[end]))) {
|
|
805
1206
|
end++;
|
|
806
1207
|
}
|
|
807
1208
|
const content = text.slice(i, end);
|
|
@@ -813,11 +1214,14 @@ function parseInlineImpl(text, opts) {
|
|
|
813
1214
|
if (trimmed.length > 0) {
|
|
814
1215
|
const last = nodes[nodes.length - 1];
|
|
815
1216
|
if (last?.type === 'text') {
|
|
816
|
-
|
|
1217
|
+
nodes[nodes.length - 1] = {
|
|
1218
|
+
...last,
|
|
1219
|
+
value: last.value + trimmed
|
|
1220
|
+
};
|
|
817
1221
|
} else {
|
|
818
1222
|
nodes.push({
|
|
819
1223
|
type: 'text',
|
|
820
|
-
|
|
1224
|
+
value: trimmed
|
|
821
1225
|
});
|
|
822
1226
|
}
|
|
823
1227
|
}
|
|
@@ -830,11 +1234,14 @@ function parseInlineImpl(text, opts) {
|
|
|
830
1234
|
}
|
|
831
1235
|
const last = nodes[nodes.length - 1];
|
|
832
1236
|
if (last?.type === 'text') {
|
|
833
|
-
|
|
1237
|
+
nodes[nodes.length - 1] = {
|
|
1238
|
+
...last,
|
|
1239
|
+
value: last.value + content
|
|
1240
|
+
};
|
|
834
1241
|
} else {
|
|
835
1242
|
nodes.push({
|
|
836
1243
|
type: 'text',
|
|
837
|
-
content
|
|
1244
|
+
value: content
|
|
838
1245
|
});
|
|
839
1246
|
}
|
|
840
1247
|
i = end;
|
|
@@ -938,7 +1345,7 @@ function scanAutolinksInText(text) {
|
|
|
938
1345
|
while ((m = re.exec(text)) !== null) {
|
|
939
1346
|
const url = m[1];
|
|
940
1347
|
// Skip dangerous URL schemes (javascript:, vbscript:, data:text/html)
|
|
941
|
-
if (!
|
|
1348
|
+
if (!isSafeMarkdownParserUrl(url)) {
|
|
942
1349
|
continue;
|
|
943
1350
|
}
|
|
944
1351
|
matches.push({
|
|
@@ -1063,7 +1470,7 @@ function splitTextOnAutolinks(content) {
|
|
|
1063
1470
|
if (matches.length === 0) {
|
|
1064
1471
|
return [{
|
|
1065
1472
|
type: 'text',
|
|
1066
|
-
content
|
|
1473
|
+
value: content
|
|
1067
1474
|
}];
|
|
1068
1475
|
}
|
|
1069
1476
|
const out = [];
|
|
@@ -1072,15 +1479,15 @@ function splitTextOnAutolinks(content) {
|
|
|
1072
1479
|
if (m.start > cursor) {
|
|
1073
1480
|
out.push({
|
|
1074
1481
|
type: 'text',
|
|
1075
|
-
|
|
1482
|
+
value: content.slice(cursor, m.start)
|
|
1076
1483
|
});
|
|
1077
1484
|
}
|
|
1078
1485
|
out.push({
|
|
1079
1486
|
type: 'link',
|
|
1080
|
-
|
|
1487
|
+
url: m.href,
|
|
1081
1488
|
children: [{
|
|
1082
1489
|
type: 'text',
|
|
1083
|
-
|
|
1490
|
+
value: m.display
|
|
1084
1491
|
}]
|
|
1085
1492
|
});
|
|
1086
1493
|
cursor = m.end;
|
|
@@ -1088,7 +1495,7 @@ function splitTextOnAutolinks(content) {
|
|
|
1088
1495
|
if (cursor < content.length) {
|
|
1089
1496
|
out.push({
|
|
1090
1497
|
type: 'text',
|
|
1091
|
-
|
|
1498
|
+
value: content.slice(cursor)
|
|
1092
1499
|
});
|
|
1093
1500
|
}
|
|
1094
1501
|
return out;
|
|
@@ -1106,16 +1513,19 @@ function transformAutolinks(nodes) {
|
|
|
1106
1513
|
const out = [];
|
|
1107
1514
|
for (const node of nodes) {
|
|
1108
1515
|
if (node.type === 'text') {
|
|
1109
|
-
const split = splitTextOnAutolinks(node.
|
|
1516
|
+
const split = splitTextOnAutolinks(node.value);
|
|
1110
1517
|
for (const seg of split) {
|
|
1111
1518
|
const last = out[out.length - 1];
|
|
1112
1519
|
if (seg.type === 'text' && last?.type === 'text') {
|
|
1113
|
-
|
|
1520
|
+
out[out.length - 1] = {
|
|
1521
|
+
...last,
|
|
1522
|
+
value: last.value + seg.value
|
|
1523
|
+
};
|
|
1114
1524
|
} else {
|
|
1115
1525
|
out.push(seg);
|
|
1116
1526
|
}
|
|
1117
1527
|
}
|
|
1118
|
-
} else if (node.type === '
|
|
1528
|
+
} else if (node.type === 'strong' || node.type === 'emphasis' || node.type === 'delete') {
|
|
1119
1529
|
out.push({
|
|
1120
1530
|
...node,
|
|
1121
1531
|
children: transformAutolinks(node.children)
|
|
@@ -1200,10 +1610,19 @@ function isTableSeparator(line) {
|
|
|
1200
1610
|
* offset into it would not address the document.
|
|
1201
1611
|
*/
|
|
1202
1612
|
function nested(opts) {
|
|
1203
|
-
|
|
1613
|
+
const nestedOptions = opts.allowBlockSyntax === false ? opts : {
|
|
1204
1614
|
...opts,
|
|
1205
|
-
|
|
1206
|
-
}
|
|
1615
|
+
allowBlockSyntax: false
|
|
1616
|
+
};
|
|
1617
|
+
return nestedOptions.sourceRanges || nestedOptions.astPositions ? {
|
|
1618
|
+
...nestedOptions,
|
|
1619
|
+
sourceRanges: false,
|
|
1620
|
+
astPositions: false
|
|
1621
|
+
} : nestedOptions;
|
|
1622
|
+
}
|
|
1623
|
+
function blockExtensionColumn(line) {
|
|
1624
|
+
const indentation = line.length - line.trimStart().length;
|
|
1625
|
+
return indentation <= 3 ? indentation : null;
|
|
1207
1626
|
}
|
|
1208
1627
|
|
|
1209
1628
|
/**
|
|
@@ -1271,6 +1690,7 @@ function splitTableRow(line) {
|
|
|
1271
1690
|
}
|
|
1272
1691
|
function parseTable(lines, lineIndex, opts) {
|
|
1273
1692
|
const headers = splitTableRow(lines[lineIndex]).map(cell => ({
|
|
1693
|
+
type: 'tableCell',
|
|
1274
1694
|
children: parseInlineEntry(cell, opts)
|
|
1275
1695
|
}));
|
|
1276
1696
|
const alignments = splitTableRow(lines[lineIndex + 1]).map(cell => {
|
|
@@ -1282,17 +1702,24 @@ function parseTable(lines, lineIndex, opts) {
|
|
|
1282
1702
|
const rows = [];
|
|
1283
1703
|
let rowIndex = lineIndex + 2;
|
|
1284
1704
|
while (rowIndex < lines.length && lines[rowIndex].includes('|') && lines[rowIndex].trim() !== '') {
|
|
1285
|
-
rows.push(
|
|
1286
|
-
|
|
1287
|
-
|
|
1705
|
+
rows.push({
|
|
1706
|
+
type: 'tableRow',
|
|
1707
|
+
children: splitTableRow(lines[rowIndex]).map(cell => ({
|
|
1708
|
+
type: 'tableCell',
|
|
1709
|
+
children: parseInlineEntry(cell, opts)
|
|
1710
|
+
}))
|
|
1711
|
+
});
|
|
1288
1712
|
rowIndex++;
|
|
1289
1713
|
}
|
|
1714
|
+
const header = {
|
|
1715
|
+
type: 'tableRow',
|
|
1716
|
+
children: headers
|
|
1717
|
+
};
|
|
1290
1718
|
return {
|
|
1291
1719
|
node: {
|
|
1292
1720
|
type: 'table',
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
rows
|
|
1721
|
+
align: alignments,
|
|
1722
|
+
children: [header, ...rows]
|
|
1296
1723
|
},
|
|
1297
1724
|
nextIndex: rowIndex
|
|
1298
1725
|
};
|
|
@@ -1335,6 +1762,7 @@ function parseList(lines, startIndex, ordered, opts) {
|
|
|
1335
1762
|
itemText += '\n' + deindented.join('\n');
|
|
1336
1763
|
}
|
|
1337
1764
|
items.push({
|
|
1765
|
+
type: 'listItem',
|
|
1338
1766
|
checked,
|
|
1339
1767
|
children: parseMarkdownImpl(itemText, nested(opts))
|
|
1340
1768
|
});
|
|
@@ -1351,15 +1779,16 @@ function parseList(lines, startIndex, ordered, opts) {
|
|
|
1351
1779
|
index = lookahead;
|
|
1352
1780
|
}
|
|
1353
1781
|
}
|
|
1782
|
+
const node = {
|
|
1783
|
+
type: 'list',
|
|
1784
|
+
ordered,
|
|
1785
|
+
start,
|
|
1786
|
+
delimiter: ordered ? delim : undefined,
|
|
1787
|
+
spread: loose || undefined,
|
|
1788
|
+
children: items
|
|
1789
|
+
};
|
|
1354
1790
|
return {
|
|
1355
|
-
node
|
|
1356
|
-
type: 'list',
|
|
1357
|
-
ordered,
|
|
1358
|
-
start,
|
|
1359
|
-
delimiter: ordered ? delim : undefined,
|
|
1360
|
-
loose: loose || undefined,
|
|
1361
|
-
items
|
|
1362
|
-
},
|
|
1791
|
+
node,
|
|
1363
1792
|
nextIndex: index
|
|
1364
1793
|
};
|
|
1365
1794
|
}
|
|
@@ -1369,7 +1798,33 @@ function parseList(lines, startIndex, ordered, opts) {
|
|
|
1369
1798
|
// ---------------------------------------------------------------------------
|
|
1370
1799
|
|
|
1371
1800
|
export function parseMarkdown(input, arg) {
|
|
1372
|
-
return
|
|
1801
|
+
return projectMarkdownRoot(parseMarkdownAstInternal(input, arg, true), wantsLegacyRanges(arg));
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
/**
|
|
1805
|
+
* Parse block Markdown into the canonical immutable Astryx AST.
|
|
1806
|
+
*
|
|
1807
|
+
* Unlike `parseMarkdown`, this returns the MDAST-aligned root used by Markdown,
|
|
1808
|
+
* transforms, and Outline. Math nodes are present only when `math: true`, and
|
|
1809
|
+
* plugin extension nodes are inferred from the ordered `plugins` tuple.
|
|
1810
|
+
*/
|
|
1811
|
+
|
|
1812
|
+
export function parseMarkdownAst(input, arg) {
|
|
1813
|
+
return parseMarkdownAstInternal(input, arg, true);
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
/** @internal Full-parse entry point with streaming finality for Outline. */
|
|
1817
|
+
export function parseMarkdownAstInternal(input, arg, isFinal) {
|
|
1818
|
+
const resolved = resolveOptions(arg);
|
|
1819
|
+
const opts = isFinal ? resolved : {
|
|
1820
|
+
...resolved,
|
|
1821
|
+
isFinal: false
|
|
1822
|
+
};
|
|
1823
|
+
const root = {
|
|
1824
|
+
type: 'root',
|
|
1825
|
+
children: parseMarkdownImpl(input, opts)
|
|
1826
|
+
};
|
|
1827
|
+
return applyMarkdownTransforms(root, opts.plugins, input, opts.isFinal, 'block');
|
|
1373
1828
|
}
|
|
1374
1829
|
function parseMarkdownImpl(input, baseOpts) {
|
|
1375
1830
|
// Collect this input's link reference definitions and strip their lines,
|
|
@@ -1398,14 +1853,26 @@ function parseMarkdownImpl(input, baseOpts) {
|
|
|
1398
1853
|
linkDefs
|
|
1399
1854
|
} : baseOpts;
|
|
1400
1855
|
const lines = cleaned.split('\n');
|
|
1856
|
+
const hasBlockExtensionSyntax = opts.allowBlockSyntax !== false && (opts.plugins?.blockByFirstCharacter.size ?? 0) > 0;
|
|
1857
|
+
// Derived from the already-split lines rather than a second character
|
|
1858
|
+
// scan: every line contributes its own length plus the newline it ended on.
|
|
1859
|
+
const lineOffsets = [0];
|
|
1860
|
+
if (opts.astPositions === true || hasBlockExtensionSyntax) {
|
|
1861
|
+
let offset = 0;
|
|
1862
|
+
for (let index = 0; index < lines.length; index++) {
|
|
1863
|
+
offset += lines[index].length + 1;
|
|
1864
|
+
lineOffsets.push(offset);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
const blockExtensionMatches = new Map();
|
|
1401
1868
|
const blocks = [];
|
|
1402
1869
|
// The line each block started on, parallel to `blocks`. Only collected when
|
|
1403
1870
|
// ranges were asked for; a block's end is resolved after the loop, since the
|
|
1404
1871
|
// branch that produced it has already moved `index` past whatever it read.
|
|
1405
|
-
const blockStartLines = opts.
|
|
1872
|
+
const blockStartLines = opts.astPositions === true ? [] : null;
|
|
1406
1873
|
// Set only by a block that consumes blank lines as content, where the
|
|
1407
1874
|
// positional end derivation would trim them away.
|
|
1408
|
-
const blockEndLines = opts.
|
|
1875
|
+
const blockEndLines = opts.astPositions === true ? [] : null;
|
|
1409
1876
|
let blockStartLine = 0;
|
|
1410
1877
|
const pushBlock = (node, endLine) => {
|
|
1411
1878
|
blocks.push(node);
|
|
@@ -1422,10 +1889,13 @@ function parseMarkdownImpl(input, baseOpts) {
|
|
|
1422
1889
|
}
|
|
1423
1890
|
|
|
1424
1891
|
// --- Fenced code block ---
|
|
1425
|
-
const fenceMatch = line.match(/^(`{3,}|~{3,})
|
|
1892
|
+
const fenceMatch = line.match(/^(`{3,}|~{3,})/);
|
|
1426
1893
|
if (fenceMatch) {
|
|
1427
1894
|
const fence = fenceMatch[1];
|
|
1428
|
-
const
|
|
1895
|
+
const info = line.slice(fence.length);
|
|
1896
|
+
const language = info.match(/^(\S+)/)?.[1] ?? null;
|
|
1897
|
+
const legacyLanguage = info.match(/^(\w*)/)?.[1] || null;
|
|
1898
|
+
const meta = language == null ? undefined : info.slice(language.length).trim() || undefined;
|
|
1429
1899
|
const codeLines = [];
|
|
1430
1900
|
index++;
|
|
1431
1901
|
while (index < lines.length && !lines[index].startsWith(fence)) {
|
|
@@ -1436,11 +1906,14 @@ function parseMarkdownImpl(input, baseOpts) {
|
|
|
1436
1906
|
// A fence owns its blank lines, and an unterminated one (mid-stream)
|
|
1437
1907
|
// can end on them, so it states its own end rather than letting the
|
|
1438
1908
|
// positional derivation trim them off.
|
|
1439
|
-
pushBlock({
|
|
1440
|
-
type: '
|
|
1441
|
-
language,
|
|
1442
|
-
|
|
1443
|
-
|
|
1909
|
+
pushBlock(markMarkdownAstLegacyCodeLanguage({
|
|
1910
|
+
type: 'code',
|
|
1911
|
+
lang: language,
|
|
1912
|
+
...(meta == null ? {} : {
|
|
1913
|
+
meta
|
|
1914
|
+
}),
|
|
1915
|
+
value: codeLines.join('\n')
|
|
1916
|
+
}, legacyLanguage), Math.min(index, lines.length) - 1);
|
|
1444
1917
|
continue;
|
|
1445
1918
|
}
|
|
1446
1919
|
|
|
@@ -1462,7 +1935,7 @@ function parseMarkdownImpl(input, baseOpts) {
|
|
|
1462
1935
|
if (headingMatch) {
|
|
1463
1936
|
pushBlock({
|
|
1464
1937
|
type: 'heading',
|
|
1465
|
-
|
|
1938
|
+
depth: headingMatch[1].length,
|
|
1466
1939
|
children: parseInlineEntry(headingMatch[2], opts)
|
|
1467
1940
|
});
|
|
1468
1941
|
index++;
|
|
@@ -1472,7 +1945,7 @@ function parseMarkdownImpl(input, baseOpts) {
|
|
|
1472
1945
|
// --- HR (must precede list check to handle `- - -`, `* * *`, `_ _ _`) ---
|
|
1473
1946
|
if (isHorizontalRule(line)) {
|
|
1474
1947
|
pushBlock({
|
|
1475
|
-
type: '
|
|
1948
|
+
type: 'thematicBreak'
|
|
1476
1949
|
});
|
|
1477
1950
|
index++;
|
|
1478
1951
|
continue;
|
|
@@ -1482,11 +1955,11 @@ function parseMarkdownImpl(input, baseOpts) {
|
|
|
1482
1955
|
// An unsafe src falls through to the paragraph path and renders as
|
|
1483
1956
|
// literal text, the same rule the inline image path applies.
|
|
1484
1957
|
const imageMatch = line.match(/^!\[([^\]]*)\]\(([^)]+)\)/);
|
|
1485
|
-
if (imageMatch && line.trim() === imageMatch[0] &&
|
|
1958
|
+
if (imageMatch && line.trim() === imageMatch[0] && isSafeMarkdownParserUrl(imageMatch[2])) {
|
|
1486
1959
|
pushBlock({
|
|
1487
1960
|
type: 'image',
|
|
1488
1961
|
alt: imageMatch[1],
|
|
1489
|
-
|
|
1962
|
+
url: imageMatch[2]
|
|
1490
1963
|
});
|
|
1491
1964
|
index++;
|
|
1492
1965
|
continue;
|
|
@@ -1530,11 +2003,52 @@ function parseMarkdownImpl(input, baseOpts) {
|
|
|
1530
2003
|
continue;
|
|
1531
2004
|
}
|
|
1532
2005
|
|
|
2006
|
+
// --- Extension block syntax (built-in blocks take precedence) ---
|
|
2007
|
+
if (hasBlockExtensionSyntax) {
|
|
2008
|
+
const extensionColumn = blockExtensionColumn(line);
|
|
2009
|
+
const extensionOffset = extensionColumn == null ? lineOffsets[index] : lineOffsets[index] + extensionColumn;
|
|
2010
|
+
const extension = blockExtensionMatches.get(extensionOffset) ?? (extensionColumn == null ? {
|
|
2011
|
+
status: 'none'
|
|
2012
|
+
} : matchExtensionSyntax(cleaned, extensionOffset, 'block', opts));
|
|
2013
|
+
blockExtensionMatches.delete(extensionOffset);
|
|
2014
|
+
if (extension.status === 'match') {
|
|
2015
|
+
const consumedEnd = extension.end;
|
|
2016
|
+
const consumed = cleaned.slice(lineOffsets[index], consumedEnd);
|
|
2017
|
+
if (consumedEnd < cleaned.length && cleaned[consumedEnd] !== '\n' && cleaned[consumedEnd - 1] !== '\n') {
|
|
2018
|
+
reportMarkdownPluginFailure(extension.node.plugin, 'syntax', new TypeError('Block syntax must consume complete lines'));
|
|
2019
|
+
} else {
|
|
2020
|
+
const newlineCount = consumed.split('\n').length - 1;
|
|
2021
|
+
const consumedLines = Math.max(1, newlineCount + (consumed.endsWith('\n') ? 0 : 1));
|
|
2022
|
+
pushBlock(extension.node, index + consumedLines - 1);
|
|
2023
|
+
index += consumedLines;
|
|
2024
|
+
continue;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
if (extension.status === 'defer') {
|
|
2028
|
+
break;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
|
|
1533
2032
|
// --- Paragraph ---
|
|
1534
2033
|
const paraLines = [line];
|
|
1535
2034
|
index++;
|
|
1536
|
-
while (index < lines.length
|
|
1537
|
-
|
|
2035
|
+
while (index < lines.length) {
|
|
2036
|
+
const nextLine = lines[index];
|
|
2037
|
+
if (isBlockStart(nextLine) || opts.math && matchDisplayMathBlock(lines, index) != null || nextLine.trim() === '') {
|
|
2038
|
+
break;
|
|
2039
|
+
}
|
|
2040
|
+
if (hasBlockExtensionSyntax) {
|
|
2041
|
+
const extensionColumn = blockExtensionColumn(nextLine);
|
|
2042
|
+
if (extensionColumn != null) {
|
|
2043
|
+
const extensionOffset = lineOffsets[index] + extensionColumn;
|
|
2044
|
+
const extension = matchExtensionSyntax(cleaned, extensionOffset, 'block', opts);
|
|
2045
|
+
if (extension.status !== 'none') {
|
|
2046
|
+
blockExtensionMatches.set(extensionOffset, extension);
|
|
2047
|
+
break;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
paraLines.push(nextLine);
|
|
1538
2052
|
index++;
|
|
1539
2053
|
}
|
|
1540
2054
|
pushBlock({
|
|
@@ -1586,9 +2100,13 @@ function stampSourceRanges(blocks, blockStartLines, blockEndLines, lines, lineMa
|
|
|
1586
2100
|
const end = lineStart(endLine) + lines[endLine].length;
|
|
1587
2101
|
blocks[i] = {
|
|
1588
2102
|
...blocks[i],
|
|
1589
|
-
|
|
1590
|
-
start:
|
|
1591
|
-
|
|
2103
|
+
position: {
|
|
2104
|
+
start: {
|
|
2105
|
+
offset: lineStart(startLine)
|
|
2106
|
+
},
|
|
2107
|
+
end: {
|
|
2108
|
+
offset: end
|
|
2109
|
+
}
|
|
1592
2110
|
}
|
|
1593
2111
|
};
|
|
1594
2112
|
}
|
|
@@ -1609,6 +2127,11 @@ function makeIncrementalCache(state) {
|
|
|
1609
2127
|
tailLinkDefs: new Map(),
|
|
1610
2128
|
linkDefs: defs,
|
|
1611
2129
|
linkDefsKey: linkDefsSignature(defs),
|
|
2130
|
+
settledAstBlocks: [],
|
|
2131
|
+
settledRevision: 0,
|
|
2132
|
+
projectedRevision: -1,
|
|
2133
|
+
projectedSettledBlocks: [],
|
|
2134
|
+
projectionCache: new WeakMap(),
|
|
1612
2135
|
work: {
|
|
1613
2136
|
splitCharacters: 0,
|
|
1614
2137
|
boundaryLines: 0,
|
|
@@ -2041,7 +2564,7 @@ function trimUnsettledStructural(text) {
|
|
|
2041
2564
|
* rather than into the slice.
|
|
2042
2565
|
*/
|
|
2043
2566
|
function atOffset(opts, offset) {
|
|
2044
|
-
return opts.
|
|
2567
|
+
return opts.astPositions === true ? {
|
|
2045
2568
|
...opts,
|
|
2046
2569
|
baseOffset: offset
|
|
2047
2570
|
} : opts;
|
|
@@ -2066,14 +2589,13 @@ function mergeSettledBlocks(prev, delta) {
|
|
|
2066
2589
|
ordered: prevLast.ordered,
|
|
2067
2590
|
start: prevLast.start,
|
|
2068
2591
|
delimiter: prevLast.delimiter,
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
// One list now, so one
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
end: deltaFirst.range.end
|
|
2592
|
+
spread: true,
|
|
2593
|
+
children: [...prevLast.children, ...deltaFirst.children],
|
|
2594
|
+
// One list now, so one position spans both halves.
|
|
2595
|
+
...(prevLast.position != null && deltaFirst.position != null ? {
|
|
2596
|
+
position: {
|
|
2597
|
+
start: prevLast.position.start,
|
|
2598
|
+
end: deltaFirst.position.end
|
|
2077
2599
|
}
|
|
2078
2600
|
} : null)
|
|
2079
2601
|
};
|
|
@@ -2085,11 +2607,11 @@ function mergeSettledBlocks(prev, delta) {
|
|
|
2085
2607
|
/** Append a newly-settled slice without copying the already-settled prefix. */
|
|
2086
2608
|
function appendSettledBlocks(prev, delta) {
|
|
2087
2609
|
if (delta.length === 0) {
|
|
2088
|
-
return;
|
|
2610
|
+
return false;
|
|
2089
2611
|
}
|
|
2090
2612
|
if (prev.length === 0) {
|
|
2091
2613
|
prev.push(...delta);
|
|
2092
|
-
return;
|
|
2614
|
+
return false;
|
|
2093
2615
|
}
|
|
2094
2616
|
const prevLast = prev[prev.length - 1];
|
|
2095
2617
|
const deltaFirst = delta[0];
|
|
@@ -2099,19 +2621,20 @@ function appendSettledBlocks(prev, delta) {
|
|
|
2099
2621
|
ordered: prevLast.ordered,
|
|
2100
2622
|
start: prevLast.start,
|
|
2101
2623
|
delimiter: prevLast.delimiter,
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
...(prevLast.
|
|
2105
|
-
|
|
2106
|
-
start: prevLast.
|
|
2107
|
-
end: deltaFirst.
|
|
2624
|
+
spread: true,
|
|
2625
|
+
children: [...prevLast.children, ...deltaFirst.children],
|
|
2626
|
+
...(prevLast.position != null && deltaFirst.position != null ? {
|
|
2627
|
+
position: {
|
|
2628
|
+
start: prevLast.position.start,
|
|
2629
|
+
end: deltaFirst.position.end
|
|
2108
2630
|
}
|
|
2109
2631
|
} : null)
|
|
2110
2632
|
};
|
|
2111
2633
|
prev.push(...delta.slice(1));
|
|
2112
|
-
return;
|
|
2634
|
+
return true;
|
|
2113
2635
|
}
|
|
2114
2636
|
prev.push(...delta);
|
|
2637
|
+
return false;
|
|
2115
2638
|
}
|
|
2116
2639
|
function sameUnsettledDefinitions(previous, next, settled) {
|
|
2117
2640
|
for (const [label, destination] of previous) {
|
|
@@ -2132,12 +2655,19 @@ function resetIncrementalCache(state, cache) {
|
|
|
2132
2655
|
state.settledBlocks = [];
|
|
2133
2656
|
state.settledUpTo = 0;
|
|
2134
2657
|
state.linkDefsKey = undefined;
|
|
2658
|
+
state.sourceIdsKey = undefined;
|
|
2659
|
+
state.pluginSyntaxIdentity = undefined;
|
|
2135
2660
|
state.math = undefined;
|
|
2136
2661
|
cache.settledEnd = 0;
|
|
2137
2662
|
cache.settledLinkDefs.clear();
|
|
2138
2663
|
cache.tailLinkDefs = new Map();
|
|
2139
2664
|
cache.linkDefs = new Map();
|
|
2140
2665
|
cache.linkDefsKey = '';
|
|
2666
|
+
cache.settledAstBlocks = [];
|
|
2667
|
+
cache.settledRevision++;
|
|
2668
|
+
cache.projectedRevision = -1;
|
|
2669
|
+
cache.projectedSettledBlocks = [];
|
|
2670
|
+
cache.projectionCache = new WeakMap();
|
|
2141
2671
|
cache.work = {
|
|
2142
2672
|
splitCharacters: 0,
|
|
2143
2673
|
boundaryLines: 0,
|
|
@@ -2159,24 +2689,47 @@ function resetIncrementalCache(state, cache) {
|
|
|
2159
2689
|
*/
|
|
2160
2690
|
|
|
2161
2691
|
export function parseMarkdownIncremental(input, state, arg) {
|
|
2162
|
-
const
|
|
2692
|
+
const withRanges = wantsLegacyRanges(arg);
|
|
2693
|
+
const root = parseMarkdownAstIncremental(input, state, arg);
|
|
2163
2694
|
const cache = incrementalCaches.get(state) ?? makeIncrementalCache(state);
|
|
2164
|
-
|
|
2695
|
+
const projected = projectMarkdownRoot(root, withRanges, cache.projectionCache);
|
|
2696
|
+
if (cache.projectedRevision !== cache.settledRevision) {
|
|
2697
|
+
cache.projectedSettledBlocks = cache.settledAstBlocks.map(block => projectBlockNode(block, cache.projectionCache, withRanges));
|
|
2698
|
+
cache.projectedRevision = cache.settledRevision;
|
|
2699
|
+
}
|
|
2700
|
+
state.settledBlocks = cache.projectedSettledBlocks;
|
|
2701
|
+
return projected;
|
|
2702
|
+
}
|
|
2165
2703
|
|
|
2704
|
+
/** @internal Canonical incremental parse used by Markdown rendering. */
|
|
2705
|
+
export function parseMarkdownAstIncremental(input, state, arg) {
|
|
2706
|
+
const opts = resolveOptions(arg, true);
|
|
2707
|
+
const root = {
|
|
2708
|
+
type: 'root',
|
|
2709
|
+
children: parseMarkdownIncrementalAstBlocks(input, state, opts)
|
|
2710
|
+
};
|
|
2711
|
+
return applyMarkdownTransforms(root, opts.plugins, input, opts.isFinal, 'block');
|
|
2712
|
+
}
|
|
2713
|
+
function parseMarkdownIncrementalAstBlocks(input, state, opts) {
|
|
2714
|
+
const cache = incrementalCaches.get(state) ?? makeIncrementalCache(state);
|
|
2715
|
+
let reparseSettled = false;
|
|
2716
|
+
const nextSourceIdsKey = sourceIdsSignature(opts.sourceIds);
|
|
2717
|
+
const nextPluginSyntaxIdentity = opts.plugins?.syntaxIdentity ?? '';
|
|
2166
2718
|
// Invalidate cache when an option that changes parsed nodes flips — cached
|
|
2167
2719
|
// settled blocks were parsed with the previous setting and would otherwise
|
|
2168
2720
|
// be reused unchanged.
|
|
2169
|
-
if (state.autolink !== opts.autolink || state.math !== opts.math || Boolean(state.sourceRanges) !== Boolean(opts.sourceRanges)) {
|
|
2721
|
+
if (state.autolink !== opts.autolink || state.math !== opts.math || Boolean(state.sourceRanges) !== Boolean(opts.sourceRanges) || state.sourceIdsKey !== nextSourceIdsKey || state.pluginSyntaxIdentity !== nextPluginSyntaxIdentity) {
|
|
2170
2722
|
reparseSettled = true;
|
|
2171
2723
|
state.autolink = opts.autolink;
|
|
2172
2724
|
state.math = opts.math;
|
|
2173
2725
|
state.sourceRanges = opts.sourceRanges;
|
|
2726
|
+
state.sourceIdsKey = nextSourceIdsKey;
|
|
2727
|
+
state.pluginSyntaxIdentity = nextPluginSyntaxIdentity;
|
|
2174
2728
|
}
|
|
2175
2729
|
if (input === '') {
|
|
2176
2730
|
resetIncrementalCache(state, cache);
|
|
2177
2731
|
return [];
|
|
2178
2732
|
}
|
|
2179
|
-
|
|
2180
2733
|
// The settled prefix is only reusable while the input still contains it
|
|
2181
2734
|
// verbatim. Lengths alone cannot tell: a same-length or longer replacement
|
|
2182
2735
|
// (new args after reusing a state) disagrees with the prefix without ever
|
|
@@ -2190,6 +2743,8 @@ export function parseMarkdownIncremental(input, state, arg) {
|
|
|
2190
2743
|
state.autolink = opts.autolink;
|
|
2191
2744
|
state.math = opts.math;
|
|
2192
2745
|
state.sourceRanges = opts.sourceRanges;
|
|
2746
|
+
state.sourceIdsKey = nextSourceIdsKey;
|
|
2747
|
+
state.pluginSyntaxIdentity = nextPluginSyntaxIdentity;
|
|
2193
2748
|
}
|
|
2194
2749
|
|
|
2195
2750
|
// The recurring parse costs are confined to the mutable suffix: splitting,
|
|
@@ -2260,22 +2815,38 @@ export function parseMarkdownIncremental(input, state, arg) {
|
|
|
2260
2815
|
// table, which inside a fence is ordinary code: a TypeScript union or a `- `
|
|
2261
2816
|
// would disappear from the code block as it streams.
|
|
2262
2817
|
const unsettledText = openFence ? unsettledRaw : openMath ? trimOpenDisplayMath(unsettledRaw) : trimUnsettledStructural(unsettledRaw);
|
|
2818
|
+
const legacyRanges = opts.sourceRanges === true;
|
|
2263
2819
|
let parsedSettledBlocks = 0;
|
|
2264
2820
|
if (reparseSettled) {
|
|
2265
|
-
|
|
2266
|
-
parsedSettledBlocks =
|
|
2821
|
+
cache.settledAstBlocks = state.settledText ? parseMarkdownImpl(state.settledText, parseOpts) : [];
|
|
2822
|
+
parsedSettledBlocks = cache.settledAstBlocks.length;
|
|
2823
|
+
cache.settledRevision++;
|
|
2824
|
+
cache.projectedSettledBlocks = cache.settledAstBlocks.map(block => projectBlockNode(block, cache.projectionCache, legacyRanges));
|
|
2825
|
+
cache.projectedRevision = cache.settledRevision;
|
|
2267
2826
|
} else if (settledDelta !== '') {
|
|
2268
2827
|
const deltaBlocks = parseMarkdownImpl(settledDelta, atOffset(parseOpts, oldSettledEnd));
|
|
2269
|
-
|
|
2828
|
+
const mergeIndex = cache.settledAstBlocks.length - 1;
|
|
2829
|
+
const mergedList = appendSettledBlocks(cache.settledAstBlocks, deltaBlocks);
|
|
2270
2830
|
parsedSettledBlocks = deltaBlocks.length;
|
|
2831
|
+
cache.settledRevision++;
|
|
2832
|
+
const projectedDelta = deltaBlocks.map(block => projectBlockNode(block, cache.projectionCache, legacyRanges));
|
|
2833
|
+
if (mergedList) {
|
|
2834
|
+
const canonicalMerged = cache.settledAstBlocks[mergeIndex];
|
|
2835
|
+
const projectedMerged = projectBlockNode(canonicalMerged, cache.projectionCache, legacyRanges);
|
|
2836
|
+
cache.projectedSettledBlocks[mergeIndex] = projectedMerged;
|
|
2837
|
+
cache.projectedSettledBlocks.push(...projectedDelta.slice(1));
|
|
2838
|
+
} else {
|
|
2839
|
+
cache.projectedSettledBlocks.push(...projectedDelta);
|
|
2840
|
+
}
|
|
2841
|
+
cache.projectedRevision = cache.settledRevision;
|
|
2271
2842
|
}
|
|
2272
2843
|
|
|
2273
2844
|
// The unsettled tail is trimmed before parsing, so its offset in the
|
|
2274
2845
|
// document is where that trimmed text actually starts — not the boundary,
|
|
2275
|
-
// which is a line index. If it somehow
|
|
2276
|
-
//
|
|
2277
|
-
//
|
|
2278
|
-
const unsettledStart = unsettledText && opts.
|
|
2846
|
+
// which is a line index. If it somehow cannot be located, parse it without
|
|
2847
|
+
// positions rather than report wrong ones. The search starts at the
|
|
2848
|
+
// settled end, so it scans the tail and never the prefix.
|
|
2849
|
+
const unsettledStart = unsettledText && opts.astPositions === true ? input.indexOf(unsettledText, cache.settledEnd) : -1;
|
|
2279
2850
|
const unsettledBlocks = unsettledText ? parseMarkdownImpl(unsettledText, unsettledStart >= 0 ? atOffset(parseOpts, unsettledStart) : nested(parseOpts)) : [];
|
|
2280
2851
|
state.prevInput = input;
|
|
2281
2852
|
|
|
@@ -2290,7 +2861,7 @@ export function parseMarkdownIncremental(input, state, arg) {
|
|
|
2290
2861
|
definitionCharacters: settledDelta.length + unsettledInput.length,
|
|
2291
2862
|
renderedBlocks: parsedSettledBlocks + unsettledBlocks.length
|
|
2292
2863
|
};
|
|
2293
|
-
return mergeSettledBlocks(
|
|
2864
|
+
return mergeSettledBlocks(cache.settledAstBlocks, unsettledBlocks);
|
|
2294
2865
|
}
|
|
2295
2866
|
|
|
2296
2867
|
// ---------------------------------------------------------------------------
|
|
@@ -2301,28 +2872,6 @@ export function parseMarkdownIncremental(input, state, arg) {
|
|
|
2301
2872
|
// derives its item ids from the same functions, so outline hash links always
|
|
2302
2873
|
// resolve to a rendered heading by construction.
|
|
2303
2874
|
|
|
2304
|
-
/** Flatten inline nodes into their plain text content. */
|
|
2305
|
-
export function inlineText(nodes) {
|
|
2306
|
-
return nodes.map(node => {
|
|
2307
|
-
switch (node.type) {
|
|
2308
|
-
case 'text':
|
|
2309
|
-
case 'code':
|
|
2310
|
-
case 'math':
|
|
2311
|
-
return node.type === 'math' ? node.value : node.content;
|
|
2312
|
-
case 'bold':
|
|
2313
|
-
case 'italic':
|
|
2314
|
-
case 'strikethrough':
|
|
2315
|
-
case 'link':
|
|
2316
|
-
return inlineText(node.children);
|
|
2317
|
-
case 'image':
|
|
2318
|
-
return node.alt;
|
|
2319
|
-
case 'citation':
|
|
2320
|
-
case 'break':
|
|
2321
|
-
return '';
|
|
2322
|
-
}
|
|
2323
|
-
}).join('');
|
|
2324
|
-
}
|
|
2325
|
-
|
|
2326
2875
|
/** Turn heading text into a URL-safe slug (lowercase, hyphen-separated). */
|
|
2327
2876
|
export function slugify(value) {
|
|
2328
2877
|
return value.trim().toLowerCase().replace(/['"]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|