@terra-symposium/docs 0.1.17 → 0.1.71
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/README.md +3 -3
- package/lib-dist/assets/fonts/AUTHENTICSans-130.woff +0 -0
- package/lib-dist/assets/fonts/AUTHENTICSans-130.woff2 +0 -0
- package/lib-dist/assets/fonts/AUTHENTICSans-150.woff +0 -0
- package/lib-dist/assets/fonts/AUTHENTICSans-150.woff2 +0 -0
- package/lib-dist/assets/fonts/AUTHENTICSans-90.woff +0 -0
- package/lib-dist/assets/fonts/AUTHENTICSans-90.woff2 +0 -0
- package/lib-dist/assets/fonts/Avara-Bold.woff +0 -0
- package/lib-dist/assets/fonts/Avara-BoldItalic.woff +0 -0
- package/lib-dist/assets/fonts/InterVariable-Italic-latin-20260728.woff2 +0 -0
- package/lib-dist/assets/fonts/InterVariable-latin-20260728.woff2 +0 -0
- package/lib-dist/assets/fonts/README.md +7 -0
- package/lib-dist/assets/fonts/licenses/Inter-OFL-1.1.txt +92 -0
- package/lib-dist/assets/fonts/licenses/OFL-1.1.txt +93 -0
- package/lib-dist/{Docs.d.ts → components/Docs.d.ts} +1 -1
- package/lib-dist/components/Docs.d.ts.map +1 -0
- package/lib-dist/components/Docs.js +9 -0
- package/lib-dist/components/Docs.js.map +1 -0
- package/lib-dist/{LocalDocsWorkspace.d.ts → components/LocalDocsWorkspace.d.ts} +9 -2
- package/lib-dist/components/LocalDocsWorkspace.d.ts.map +1 -0
- package/lib-dist/{LocalDocsWorkspace.js → components/LocalDocsWorkspace.js} +83 -24
- package/lib-dist/components/LocalDocsWorkspace.js.map +1 -0
- package/lib-dist/components/NotFound.d.ts +8 -0
- package/lib-dist/components/NotFound.d.ts.map +1 -0
- package/lib-dist/components/NotFound.js +6 -0
- package/lib-dist/components/NotFound.js.map +1 -0
- package/lib-dist/components/SiteLayout.d.ts +25 -0
- package/lib-dist/components/SiteLayout.d.ts.map +1 -0
- package/lib-dist/components/SiteLayout.js +12 -0
- package/lib-dist/components/SiteLayout.js.map +1 -0
- package/lib-dist/{StaticWorkspace.d.ts → components/StaticWorkspace.d.ts} +7 -3
- package/lib-dist/components/StaticWorkspace.d.ts.map +1 -0
- package/lib-dist/{StaticWorkspace.js → components/StaticWorkspace.js} +100 -34
- package/lib-dist/components/StaticWorkspace.js.map +1 -0
- package/lib-dist/components/StrictLocalWorkspaceHarness.d.ts +10 -0
- package/lib-dist/components/StrictLocalWorkspaceHarness.d.ts.map +1 -0
- package/lib-dist/components/StrictLocalWorkspaceHarness.js +12 -0
- package/lib-dist/components/StrictLocalWorkspaceHarness.js.map +1 -0
- package/lib-dist/components/blocks.d.ts.map +1 -0
- package/lib-dist/{blocks.js → components/blocks.js} +88 -13
- package/lib-dist/components/blocks.js.map +1 -0
- package/lib-dist/{navigation.d.ts → components/navigation.d.ts} +2 -1
- package/lib-dist/components/navigation.d.ts.map +1 -0
- package/lib-dist/components/navigation.js.map +1 -0
- package/lib-dist/{terra → components/terra}/Workspace.d.ts +1 -1
- package/lib-dist/components/terra/Workspace.d.ts.map +1 -0
- package/lib-dist/components/terra/Workspace.js +190 -0
- package/lib-dist/components/terra/Workspace.js.map +1 -0
- package/lib-dist/components/terra/editor/TerraContentEditor.d.ts +15 -0
- package/lib-dist/components/terra/editor/TerraContentEditor.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/TerraContentEditor.js +358 -0
- package/lib-dist/components/terra/editor/TerraContentEditor.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/_blocks.d.ts +3 -4
- package/lib-dist/components/terra/editor/_blocks.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/_blocks.js +120 -0
- package/lib-dist/components/terra/editor/_blocks.js.map +1 -0
- package/lib-dist/components/terra/editor/docs/BlockContext.d.ts +7 -0
- package/lib-dist/components/terra/editor/docs/BlockContext.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/docs/BlockContext.js +60 -0
- package/lib-dist/components/terra/editor/docs/BlockContext.js.map +1 -0
- package/lib-dist/components/terra/editor/docs/DocsAttachmentPicker.d.ts +12 -0
- package/lib-dist/components/terra/editor/docs/DocsAttachmentPicker.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/docs/DocsAttachmentPicker.js +66 -0
- package/lib-dist/components/terra/editor/docs/DocsAttachmentPicker.js.map +1 -0
- package/lib-dist/components/terra/editor/docs/TerraToolbar.d.ts +12 -0
- package/lib-dist/components/terra/editor/docs/TerraToolbar.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/docs/TerraToolbar.js +169 -0
- package/lib-dist/components/terra/editor/docs/TerraToolbar.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Callout.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_Callout.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Callout.js +10 -6
- package/lib-dist/components/terra/editor/docs/_Callout.js.map +1 -0
- package/lib-dist/components/terra/editor/docs/_CodeBlock.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_CodeBlock.js +110 -44
- package/lib-dist/components/terra/editor/docs/_CodeBlock.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_DocsCode.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_DocsCode.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_DocsCode.js +44 -11
- package/lib-dist/components/terra/editor/docs/_DocsCode.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_DocsImage.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_DocsImage.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/docs/_DocsImage.js +62 -0
- package/lib-dist/components/terra/editor/docs/_DocsImage.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Embed.d.ts +3 -1
- package/lib-dist/components/terra/editor/docs/_Embed.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/docs/_Embed.js +73 -0
- package/lib-dist/components/terra/editor/docs/_Embed.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Math.d.ts +2 -2
- package/lib-dist/components/terra/editor/docs/_Math.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Math.js +26 -14
- package/lib-dist/components/terra/editor/docs/_Math.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Nodes.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_Nodes.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/docs/_Nodes.js +62 -0
- package/lib-dist/components/terra/editor/docs/_Nodes.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Raw.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_Raw.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Raw.js +8 -3
- package/lib-dist/components/terra/editor/docs/_Raw.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Table.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_Table.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/docs/_Table.js +99 -0
- package/lib-dist/components/terra/editor/docs/_Table.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Tabs.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_Tabs.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_Tabs.js +35 -14
- package/lib-dist/components/terra/editor/docs/_Tabs.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_TsDocs.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_TsDocs.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_TsDocs.js +15 -13
- package/lib-dist/components/terra/editor/docs/_TsDocs.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_math_inline.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/_math_inline.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/_math_inline.js +2 -2
- package/lib-dist/components/terra/editor/docs/_math_inline.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/heading.d.ts +1 -1
- package/lib-dist/components/terra/editor/docs/heading.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/docs/heading.js +8 -5
- package/lib-dist/components/terra/editor/docs/heading.js.map +1 -0
- package/lib-dist/components/terra/editor/docs/index.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/docs/index.js.map +1 -0
- package/lib-dist/components/terra/editor/terra-content.styles.d.ts +3 -0
- package/lib-dist/components/terra/editor/terra-content.styles.d.ts.map +1 -0
- package/lib-dist/components/terra/editor/terra-content.styles.js +3 -0
- package/lib-dist/components/terra/editor/terra-content.styles.js.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/types.d.ts +2 -2
- package/lib-dist/components/terra/editor/types.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/editor/types.js +1 -1
- package/lib-dist/components/terra/editor/types.js.map +1 -0
- package/lib-dist/{terra → components/terra}/flow/Nodes.d.ts +3 -3
- package/lib-dist/components/terra/flow/Nodes.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/flow/Nodes.js +211 -104
- package/lib-dist/components/terra/flow/Nodes.js.map +1 -0
- package/lib-dist/{terra → components/terra}/flow/_chrome.d.ts +9 -9
- package/lib-dist/components/terra/flow/_chrome.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/flow/_chrome.js +325 -114
- package/lib-dist/components/terra/flow/_chrome.js.map +1 -0
- package/lib-dist/components/terra/flow/menuContext.d.ts.map +1 -0
- package/lib-dist/components/terra/flow/menuContext.js.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_attachments.d.ts +1 -1
- package/lib-dist/components/terra/pages/docs/_attachments.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_attachments.js +371 -127
- package/lib-dist/components/terra/pages/docs/_attachments.js.map +1 -0
- package/lib-dist/components/terra/pages/docs/_blocks.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_blocks.js +39 -28
- package/lib-dist/components/terra/pages/docs/_blocks.js.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_editable.d.ts +3 -3
- package/lib-dist/components/terra/pages/docs/_editable.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_editable.js +81 -43
- package/lib-dist/components/terra/pages/docs/_editable.js.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_export-dialog.d.ts +1 -1
- package/lib-dist/components/terra/pages/docs/_export-dialog.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_export-dialog.js +13 -13
- package/lib-dist/components/terra/pages/docs/_export-dialog.js.map +1 -0
- package/lib-dist/components/terra/pages/docs/_icons.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/_icons.js.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_main.d.ts +10 -7
- package/lib-dist/components/terra/pages/docs/_main.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/_main.js +710 -0
- package/lib-dist/components/terra/pages/docs/_main.js.map +1 -0
- package/lib-dist/components/terra/pages/docs/_manage-attachments-dialog.d.ts +10 -0
- package/lib-dist/components/terra/pages/docs/_manage-attachments-dialog.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/_manage-attachments-dialog.js +597 -0
- package/lib-dist/components/terra/pages/docs/_manage-attachments-dialog.js.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_sidebar.d.ts +3 -12
- package/lib-dist/components/terra/pages/docs/_sidebar.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/_sidebar.js +1437 -0
- package/lib-dist/components/terra/pages/docs/_sidebar.js.map +1 -0
- package/lib-dist/components/terra/pages/docs/_toc.d.ts +4 -0
- package/lib-dist/components/terra/pages/docs/_toc.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/_toc.js +212 -0
- package/lib-dist/components/terra/pages/docs/_toc.js.map +1 -0
- package/lib-dist/components/terra/pages/docs/_toolbar-find-replace.d.ts +15 -0
- package/lib-dist/components/terra/pages/docs/_toolbar-find-replace.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/_toolbar-find-replace.js +207 -0
- package/lib-dist/components/terra/pages/docs/_toolbar-find-replace.js.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_toolbar.d.ts +4 -5
- package/lib-dist/components/terra/pages/docs/_toolbar.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_toolbar.js +312 -343
- package/lib-dist/components/terra/pages/docs/_toolbar.js.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_tree.d.ts +4 -4
- package/lib-dist/components/terra/pages/docs/_tree.d.ts.map +1 -0
- package/lib-dist/{terra → components/terra}/pages/docs/_tree.js +219 -264
- package/lib-dist/components/terra/pages/docs/_tree.js.map +1 -0
- package/lib-dist/components/terra/pages/docs/use-block-nav.d.ts +5 -0
- package/lib-dist/components/terra/pages/docs/use-block-nav.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/use-block-nav.js +1306 -0
- package/lib-dist/components/terra/pages/docs/use-block-nav.js.map +1 -0
- package/lib-dist/components/terra/pages/docs/use-media-paste.d.ts +5 -0
- package/lib-dist/components/terra/pages/docs/use-media-paste.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/use-media-paste.js +391 -0
- package/lib-dist/components/terra/pages/docs/use-media-paste.js.map +1 -0
- package/lib-dist/components/terra/pages/docs/use-render-tripwire.d.ts +2 -0
- package/lib-dist/components/terra/pages/docs/use-render-tripwire.d.ts.map +1 -0
- package/lib-dist/components/terra/pages/docs/use-render-tripwire.js +25 -0
- package/lib-dist/components/terra/pages/docs/use-render-tripwire.js.map +1 -0
- package/lib-dist/{terra/runtime → components/terra}/ui.d.ts +2 -5
- package/lib-dist/components/terra/ui.d.ts.map +1 -0
- package/lib-dist/components/terra/ui.js +20 -0
- package/lib-dist/components/terra/ui.js.map +1 -0
- package/lib-dist/components/workspace-demo-fixture.d.ts +35 -0
- package/lib-dist/components/workspace-demo-fixture.d.ts.map +1 -0
- package/lib-dist/components/workspace-demo-fixture.js +820 -0
- package/lib-dist/components/workspace-demo-fixture.js.map +1 -0
- package/lib-dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_AMS-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- package/lib-dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- package/lib-dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Main-Bold.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Main-Bold.woff +0 -0
- package/lib-dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- package/lib-dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Main-Italic.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Main-Italic.woff +0 -0
- package/lib-dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Main-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Main-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- package/lib-dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Math-Italic.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Math-Italic.woff +0 -0
- package/lib-dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Script-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Script-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Size1-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Size2-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Size3-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Size4-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/lib-dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- package/lib-dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- package/lib-dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/lib-dist/lib/astro.d.ts +8 -0
- package/lib-dist/lib/astro.d.ts.map +1 -0
- package/lib-dist/lib/astro.js +27 -0
- package/lib-dist/lib/astro.js.map +1 -0
- package/lib-dist/{docs-catalog.d.ts → lib/docs-catalog.d.ts} +1 -1
- package/lib-dist/lib/docs-catalog.d.ts.map +1 -0
- package/lib-dist/lib/docs-catalog.js +75 -0
- package/lib-dist/lib/docs-catalog.js.map +1 -0
- package/lib-dist/lib/docs-theme.d.ts +7 -0
- package/lib-dist/lib/docs-theme.d.ts.map +1 -0
- package/lib-dist/lib/docs-theme.js +51 -0
- package/lib-dist/lib/docs-theme.js.map +1 -0
- package/lib-dist/lib/host-runtime.d.ts.map +1 -0
- package/lib-dist/{host-runtime.js → lib/host-runtime.js} +4 -2
- package/lib-dist/lib/host-runtime.js.map +1 -0
- package/lib-dist/{host.d.ts → lib/host.d.ts} +20 -0
- package/lib-dist/lib/host.d.ts.map +1 -0
- package/lib-dist/lib/host.js.map +1 -0
- package/lib-dist/lib/index.d.ts +34 -0
- package/lib-dist/lib/index.d.ts.map +1 -0
- package/lib-dist/lib/index.js +27 -0
- package/lib-dist/lib/index.js.map +1 -0
- package/lib-dist/{markdown-model.d.ts → lib/markdown-model.d.ts} +3 -3
- package/lib-dist/lib/markdown-model.d.ts.map +1 -0
- package/lib-dist/lib/markdown-model.js +2031 -0
- package/lib-dist/lib/markdown-model.js.map +1 -0
- package/lib-dist/lib/markdown.d.ts +3 -0
- package/lib-dist/lib/markdown.d.ts.map +1 -0
- package/lib-dist/lib/markdown.js +222 -0
- package/lib-dist/lib/markdown.js.map +1 -0
- package/lib-dist/{schema.d.ts → lib/schema.d.ts} +55 -23
- package/lib-dist/lib/schema.d.ts.map +1 -0
- package/lib-dist/{schema.js → lib/schema.js} +26 -18
- package/lib-dist/lib/schema.js.map +1 -0
- package/lib-dist/{terra/pages/docs/_custom.d.ts → lib/terra/custom-components.d.ts} +2 -2
- package/lib-dist/lib/terra/custom-components.d.ts.map +1 -0
- package/lib-dist/{terra/pages/docs/_custom.js → lib/terra/custom-components.js} +1 -1
- package/lib-dist/lib/terra/custom-components.js.map +1 -0
- package/lib-dist/lib/terra/docs/archive.d.ts +3 -0
- package/lib-dist/lib/terra/docs/archive.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/archive.js +654 -0
- package/lib-dist/lib/terra/docs/archive.js.map +1 -0
- package/lib-dist/lib/terra/docs/assets.d.ts +26 -0
- package/lib-dist/lib/terra/docs/assets.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/assets.js +74 -0
- package/lib-dist/lib/terra/docs/assets.js.map +1 -0
- package/lib-dist/lib/terra/docs/attachments.d.ts +4 -0
- package/lib-dist/lib/terra/docs/attachments.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/attachments.js +5 -0
- package/lib-dist/lib/terra/docs/attachments.js.map +1 -0
- package/lib-dist/lib/terra/docs/editor-dom.d.ts +50 -0
- package/lib-dist/lib/terra/docs/editor-dom.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/editor-dom.js +236 -0
- package/lib-dist/lib/terra/docs/editor-dom.js.map +1 -0
- package/lib-dist/lib/terra/docs/mutations.d.ts +10 -0
- package/lib-dist/lib/terra/docs/mutations.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/mutations.js +105 -0
- package/lib-dist/lib/terra/docs/mutations.js.map +1 -0
- package/lib-dist/lib/terra/docs/navigation.d.ts +6 -0
- package/lib-dist/lib/terra/docs/navigation.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/navigation.js +21 -0
- package/lib-dist/lib/terra/docs/navigation.js.map +1 -0
- package/lib-dist/lib/terra/docs/state.d.ts +186 -0
- package/lib-dist/lib/terra/docs/state.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/state.js +255 -0
- package/lib-dist/lib/terra/docs/state.js.map +1 -0
- package/lib-dist/lib/terra/docs/toolbar.d.ts +11 -0
- package/lib-dist/lib/terra/docs/toolbar.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/toolbar.js +41 -0
- package/lib-dist/lib/terra/docs/toolbar.js.map +1 -0
- package/lib-dist/lib/terra/docs/tree.d.ts +15 -0
- package/lib-dist/lib/terra/docs/tree.d.ts.map +1 -0
- package/lib-dist/lib/terra/docs/tree.js +61 -0
- package/lib-dist/lib/terra/docs/tree.js.map +1 -0
- package/lib-dist/{terra/pages/docs/_helpers.d.ts → lib/terra/docs/workspace.d.ts} +7 -6
- package/lib-dist/lib/terra/docs/workspace.d.ts.map +1 -0
- package/lib-dist/{terra/pages/docs/_helpers.js → lib/terra/docs/workspace.js} +39 -27
- package/lib-dist/lib/terra/docs/workspace.js.map +1 -0
- package/lib-dist/lib/terra/flow/_layout.d.ts.map +1 -0
- package/lib-dist/{terra → lib/terra}/flow/_layout.js +16 -6
- package/lib-dist/lib/terra/flow/_layout.js.map +1 -0
- package/lib-dist/lib/terra/flow/powerSource.d.ts.map +1 -0
- package/lib-dist/{terra → lib/terra}/flow/powerSource.js +10 -4
- package/lib-dist/lib/terra/flow/powerSource.js.map +1 -0
- package/lib-dist/{terra → lib/terra}/regex.mjs +11 -6
- package/lib-dist/lib/terra/runtime/action-proxy.d.ts +45 -0
- package/lib-dist/lib/terra/runtime/action-proxy.d.ts.map +1 -0
- package/lib-dist/{terra → lib/terra}/runtime/action-proxy.js +1 -1
- package/lib-dist/lib/terra/runtime/action-proxy.js.map +1 -0
- package/lib-dist/lib/terra/runtime/content/block-jsx.d.ts +23 -0
- package/lib-dist/lib/terra/runtime/content/block-jsx.d.ts.map +1 -0
- package/lib-dist/lib/terra/runtime/content/block-jsx.js +225 -0
- package/lib-dist/lib/terra/runtime/content/block-jsx.js.map +1 -0
- package/lib-dist/lib/terra/runtime/content/document-markdown.d.ts +41 -0
- package/lib-dist/lib/terra/runtime/content/document-markdown.d.ts.map +1 -0
- package/lib-dist/lib/terra/runtime/content/document-markdown.js +536 -0
- package/lib-dist/lib/terra/runtime/content/document-markdown.js.map +1 -0
- package/lib-dist/lib/terra/runtime/content/markdown.d.ts +109 -0
- package/lib-dist/lib/terra/runtime/content/markdown.d.ts.map +1 -0
- package/lib-dist/lib/terra/runtime/content/markdown.js +428 -0
- package/lib-dist/lib/terra/runtime/content/markdown.js.map +1 -0
- package/lib-dist/lib/terra/runtime/content.d.ts.map +1 -0
- package/lib-dist/{terra → lib/terra}/runtime/content.js +147 -62
- package/lib-dist/lib/terra/runtime/content.js.map +1 -0
- package/lib-dist/lib/terra/runtime/leaf.d.ts.map +1 -0
- package/lib-dist/{terra → lib/terra}/runtime/leaf.js +1 -1
- package/lib-dist/lib/terra/runtime/leaf.js.map +1 -0
- package/lib-dist/lib/terra/runtime/nodes.d.ts.map +1 -0
- package/lib-dist/{terra → lib/terra}/runtime/nodes.js +103 -31
- package/lib-dist/lib/terra/runtime/nodes.js.map +1 -0
- package/lib-dist/{terra → lib/terra}/runtime/runtime.d.ts +8 -2
- package/lib-dist/lib/terra/runtime/runtime.d.ts.map +1 -0
- package/lib-dist/lib/terra/runtime/runtime.js +86 -0
- package/lib-dist/lib/terra/runtime/runtime.js.map +1 -0
- package/lib-dist/lib/terra/runtime/shared.d.ts.map +1 -0
- package/lib-dist/{terra → lib/terra}/runtime/shared.js +56 -11
- package/lib-dist/lib/terra/runtime/shared.js.map +1 -0
- package/lib-dist/lib/terra/runtime/types.d.ts +529 -0
- package/lib-dist/lib/terra/runtime/types.d.ts.map +1 -0
- package/lib-dist/{terra → lib/terra}/runtime/types.js +28 -2
- package/lib-dist/lib/terra/runtime/types.js.map +1 -0
- package/lib-dist/lib/workspace-types.d.ts +29 -0
- package/lib-dist/lib/workspace-types.d.ts.map +1 -0
- package/lib-dist/lib/workspace-types.js +2 -0
- package/lib-dist/lib/workspace-types.js.map +1 -0
- package/lib-dist/style.css +237 -1
- package/package.json +34 -16
- package/src/components/NotFound.astro +6 -0
- package/src/components/NotFound.tsx +48 -0
- package/src/{SiteLayout.astro → components/SiteLayout.astro} +8 -4
- package/src/{navigation.tsx → components/navigation.tsx} +2 -1
- package/lib-dist/Docs.d.ts.map +0 -1
- package/lib-dist/Docs.js +0 -60
- package/lib-dist/Docs.js.map +0 -1
- package/lib-dist/LocalDocsWorkspace.d.ts.map +0 -1
- package/lib-dist/LocalDocsWorkspace.js.map +0 -1
- package/lib-dist/SiteLayout.d.ts +0 -30
- package/lib-dist/SiteLayout.d.ts.map +0 -1
- package/lib-dist/SiteLayout.js +0 -34
- package/lib-dist/SiteLayout.js.map +0 -1
- package/lib-dist/StaticWorkspace.d.ts.map +0 -1
- package/lib-dist/StaticWorkspace.js.map +0 -1
- package/lib-dist/_Toolbar.d.ts +0 -7
- package/lib-dist/_Toolbar.d.ts.map +0 -1
- package/lib-dist/_Toolbar.js +0 -85
- package/lib-dist/_Toolbar.js.map +0 -1
- package/lib-dist/blocks.d.ts.map +0 -1
- package/lib-dist/blocks.js.map +0 -1
- package/lib-dist/docs-catalog.d.ts.map +0 -1
- package/lib-dist/docs-catalog.js +0 -38
- package/lib-dist/docs-catalog.js.map +0 -1
- package/lib-dist/docs-style.css +0 -31
- package/lib-dist/fonts/README.md +0 -5
- package/lib-dist/host-runtime.d.ts.map +0 -1
- package/lib-dist/host-runtime.js.map +0 -1
- package/lib-dist/host.d.ts.map +0 -1
- package/lib-dist/host.js.map +0 -1
- package/lib-dist/index.d.ts +0 -35
- package/lib-dist/index.d.ts.map +0 -1
- package/lib-dist/index.js +0 -28
- package/lib-dist/index.js.map +0 -1
- package/lib-dist/markdown-model.d.ts.map +0 -1
- package/lib-dist/markdown-model.js +0 -181
- package/lib-dist/markdown-model.js.map +0 -1
- package/lib-dist/markdown.d.ts +0 -3
- package/lib-dist/markdown.d.ts.map +0 -1
- package/lib-dist/markdown.js +0 -83
- package/lib-dist/markdown.js.map +0 -1
- package/lib-dist/navigation.d.ts.map +0 -1
- package/lib-dist/navigation.js.map +0 -1
- package/lib-dist/schema.d.ts.map +0 -1
- package/lib-dist/schema.js.map +0 -1
- package/lib-dist/terra/Workspace.d.ts.map +0 -1
- package/lib-dist/terra/Workspace.js +0 -9
- package/lib-dist/terra/Workspace.js.map +0 -1
- package/lib-dist/terra/editor/TerraContentEditor.d.ts +0 -10
- package/lib-dist/terra/editor/TerraContentEditor.d.ts.map +0 -1
- package/lib-dist/terra/editor/TerraContentEditor.js +0 -47
- package/lib-dist/terra/editor/TerraContentEditor.js.map +0 -1
- package/lib-dist/terra/editor/_blocks.d.ts.map +0 -1
- package/lib-dist/terra/editor/_blocks.js +0 -110
- package/lib-dist/terra/editor/_blocks.js.map +0 -1
- package/lib-dist/terra/editor/docs/_Callout.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_Callout.js.map +0 -1
- package/lib-dist/terra/editor/docs/_CodeBlock.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_CodeBlock.js.map +0 -1
- package/lib-dist/terra/editor/docs/_DocsCode.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_DocsCode.js.map +0 -1
- package/lib-dist/terra/editor/docs/_DocsImage.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_DocsImage.js +0 -62
- package/lib-dist/terra/editor/docs/_DocsImage.js.map +0 -1
- package/lib-dist/terra/editor/docs/_Embed.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_Embed.js +0 -27
- package/lib-dist/terra/editor/docs/_Embed.js.map +0 -1
- package/lib-dist/terra/editor/docs/_Math.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_Math.js.map +0 -1
- package/lib-dist/terra/editor/docs/_Nodes.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_Nodes.js +0 -52
- package/lib-dist/terra/editor/docs/_Nodes.js.map +0 -1
- package/lib-dist/terra/editor/docs/_Raw.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_Raw.js.map +0 -1
- package/lib-dist/terra/editor/docs/_Table.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_Table.js +0 -71
- package/lib-dist/terra/editor/docs/_Table.js.map +0 -1
- package/lib-dist/terra/editor/docs/_Tabs.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_Tabs.js.map +0 -1
- package/lib-dist/terra/editor/docs/_TsDocs.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_TsDocs.js.map +0 -1
- package/lib-dist/terra/editor/docs/_math_inline.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/_math_inline.js.map +0 -1
- package/lib-dist/terra/editor/docs/heading.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/heading.js.map +0 -1
- package/lib-dist/terra/editor/docs/index.d.ts.map +0 -1
- package/lib-dist/terra/editor/docs/index.js.map +0 -1
- package/lib-dist/terra/editor/types.d.ts.map +0 -1
- package/lib-dist/terra/editor/types.js.map +0 -1
- package/lib-dist/terra/flow/Nodes.d.ts.map +0 -1
- package/lib-dist/terra/flow/Nodes.js.map +0 -1
- package/lib-dist/terra/flow/_chrome.d.ts.map +0 -1
- package/lib-dist/terra/flow/_chrome.js.map +0 -1
- package/lib-dist/terra/flow/_layout.d.ts.map +0 -1
- package/lib-dist/terra/flow/_layout.js.map +0 -1
- package/lib-dist/terra/flow/menuContext.d.ts.map +0 -1
- package/lib-dist/terra/flow/menuContext.js.map +0 -1
- package/lib-dist/terra/flow/powerSource.d.ts.map +0 -1
- package/lib-dist/terra/flow/powerSource.js.map +0 -1
- package/lib-dist/terra/pages/docs/_attachments.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_attachments.js.map +0 -1
- package/lib-dist/terra/pages/docs/_blocks.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_blocks.js.map +0 -1
- package/lib-dist/terra/pages/docs/_custom.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_custom.js.map +0 -1
- package/lib-dist/terra/pages/docs/_editable.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_editable.js.map +0 -1
- package/lib-dist/terra/pages/docs/_export-dialog.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_export-dialog.js.map +0 -1
- package/lib-dist/terra/pages/docs/_helpers.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_helpers.js.map +0 -1
- package/lib-dist/terra/pages/docs/_icons.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_icons.js.map +0 -1
- package/lib-dist/terra/pages/docs/_main.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_main.js +0 -1959
- package/lib-dist/terra/pages/docs/_main.js.map +0 -1
- package/lib-dist/terra/pages/docs/_sidebar.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_sidebar.js +0 -2450
- package/lib-dist/terra/pages/docs/_sidebar.js.map +0 -1
- package/lib-dist/terra/pages/docs/_toolbar.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_toolbar.js.map +0 -1
- package/lib-dist/terra/pages/docs/_tree.d.ts.map +0 -1
- package/lib-dist/terra/pages/docs/_tree.js.map +0 -1
- package/lib-dist/terra/runtime/action-proxy.d.ts +0 -5
- package/lib-dist/terra/runtime/action-proxy.d.ts.map +0 -1
- package/lib-dist/terra/runtime/action-proxy.js.map +0 -1
- package/lib-dist/terra/runtime/content.d.ts.map +0 -1
- package/lib-dist/terra/runtime/content.js.map +0 -1
- package/lib-dist/terra/runtime/leaf.d.ts.map +0 -1
- package/lib-dist/terra/runtime/leaf.js.map +0 -1
- package/lib-dist/terra/runtime/nodes.d.ts.map +0 -1
- package/lib-dist/terra/runtime/nodes.js.map +0 -1
- package/lib-dist/terra/runtime/runtime.d.ts.map +0 -1
- package/lib-dist/terra/runtime/runtime.js +0 -50
- package/lib-dist/terra/runtime/runtime.js.map +0 -1
- package/lib-dist/terra/runtime/shared.d.ts.map +0 -1
- package/lib-dist/terra/runtime/shared.js.map +0 -1
- package/lib-dist/terra/runtime/types.d.ts +0 -266
- package/lib-dist/terra/runtime/types.d.ts.map +0 -1
- package/lib-dist/terra/runtime/types.js.map +0 -1
- package/lib-dist/terra/runtime/ui.d.ts.map +0 -1
- package/lib-dist/terra/runtime/ui.js +0 -16
- package/lib-dist/terra/runtime/ui.js.map +0 -1
- package/lib-dist/workspace.d.ts +0 -78
- package/lib-dist/workspace.d.ts.map +0 -1
- package/lib-dist/workspace.js +0 -151
- package/lib-dist/workspace.js.map +0 -1
- package/src/style.css +0 -733
- /package/lib-dist/{fonts → assets/fonts}/Avara-Bold.woff2 +0 -0
- /package/lib-dist/{fonts → assets/fonts}/Avara-BoldItalic.woff2 +0 -0
- /package/lib-dist/{fonts → assets/fonts}/OFL-1.1.txt +0 -0
- /package/lib-dist/{blocks.d.ts → components/blocks.d.ts} +0 -0
- /package/lib-dist/{navigation.js → components/navigation.js} +0 -0
- /package/lib-dist/{terra → components/terra}/editor/docs/_CodeBlock.d.ts +0 -0
- /package/lib-dist/{terra → components/terra}/editor/docs/index.d.ts +0 -0
- /package/lib-dist/{terra → components/terra}/editor/docs/index.js +0 -0
- /package/lib-dist/{terra → components/terra}/flow/menuContext.d.ts +0 -0
- /package/lib-dist/{terra → components/terra}/flow/menuContext.js +0 -0
- /package/lib-dist/{terra → components/terra}/pages/docs/_blocks.d.ts +0 -0
- /package/lib-dist/{terra → components/terra}/pages/docs/_icons.d.ts +0 -0
- /package/lib-dist/{terra → components/terra}/pages/docs/_icons.js +0 -0
- /package/lib-dist/{host-runtime.d.ts → lib/host-runtime.d.ts} +0 -0
- /package/lib-dist/{host.js → lib/host.js} +0 -0
- /package/lib-dist/{terra → lib/terra}/flow/_layout.d.ts +0 -0
- /package/lib-dist/{terra → lib/terra}/flow/powerSource.d.ts +0 -0
- /package/lib-dist/{terra → lib/terra}/runtime/content.d.ts +0 -0
- /package/lib-dist/{terra → lib/terra}/runtime/leaf.d.ts +0 -0
- /package/lib-dist/{terra → lib/terra}/runtime/nodes.d.ts +0 -0
- /package/lib-dist/{terra → lib/terra}/runtime/shared.d.ts +0 -0
|
@@ -0,0 +1,2031 @@
|
|
|
1
|
+
import { marked } from 'marked';
|
|
2
|
+
import { enabledDocsBlocks } from '../components/blocks.js';
|
|
3
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
4
|
+
const key = () => crypto.randomUUID();
|
|
5
|
+
function encodeInlineMathPlaceholder(code) {
|
|
6
|
+
const hex = Array.from(code, (character) => (character.codePointAt(0) ?? 0).toString(16).padStart(6, '0')).join('');
|
|
7
|
+
return `TERRADOCSMATH${hex}END`;
|
|
8
|
+
}
|
|
9
|
+
function decodeInlineMathPlaceholder(value) {
|
|
10
|
+
const match = value.match(/^TERRADOCSMATH([0-9a-f]+)END$/i);
|
|
11
|
+
if (!match || match[1].length % 6 !== 0)
|
|
12
|
+
return undefined;
|
|
13
|
+
const codepoints = [];
|
|
14
|
+
for (let offset = 0; offset < match[1].length; offset += 6) {
|
|
15
|
+
const codepoint = Number.parseInt(match[1].slice(offset, offset + 6), 16);
|
|
16
|
+
if (codepoint > 0x10ffff || (codepoint >= 0xd800 && codepoint <= 0xdfff))
|
|
17
|
+
return undefined;
|
|
18
|
+
codepoints.push(codepoint);
|
|
19
|
+
}
|
|
20
|
+
return String.fromCodePoint(...codepoints);
|
|
21
|
+
}
|
|
22
|
+
function restoreInlineMathPlaceholders(value) {
|
|
23
|
+
return value.replace(/TERRADOCSMATH[0-9a-f]+END/gi, (placeholder) => {
|
|
24
|
+
const code = decodeInlineMathPlaceholder(placeholder);
|
|
25
|
+
return code === undefined ? placeholder : `$${code}$`;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function withGeneratedInlineMathTokens(tokens) {
|
|
29
|
+
const result = [];
|
|
30
|
+
for (const token of tokens ?? []) {
|
|
31
|
+
if (!['text', 'escape'].includes(token.type)) {
|
|
32
|
+
result.push(token);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const matches = [...token.raw.matchAll(/TERRADOCSMATH[0-9a-f]+END/gi)];
|
|
36
|
+
if (!matches.length) {
|
|
37
|
+
result.push(token);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let cursor = 0;
|
|
41
|
+
for (const match of matches) {
|
|
42
|
+
const start = match.index ?? 0;
|
|
43
|
+
if (start > cursor) {
|
|
44
|
+
const raw = token.raw.slice(cursor, start);
|
|
45
|
+
const text = token.text ?? token.raw;
|
|
46
|
+
result.push({
|
|
47
|
+
...token,
|
|
48
|
+
raw,
|
|
49
|
+
text: text.length === token.raw.length ? text.slice(cursor, start) : raw,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const code = decodeInlineMathPlaceholder(match[0]);
|
|
53
|
+
result.push(code === undefined
|
|
54
|
+
? { ...token, raw: match[0], text: match[0] }
|
|
55
|
+
: { type: 'docsMath', raw: match[0], text: code });
|
|
56
|
+
cursor = start + match[0].length;
|
|
57
|
+
}
|
|
58
|
+
if (cursor < token.raw.length) {
|
|
59
|
+
const raw = token.raw.slice(cursor);
|
|
60
|
+
const text = token.text ?? token.raw;
|
|
61
|
+
result.push({
|
|
62
|
+
...token,
|
|
63
|
+
raw,
|
|
64
|
+
text: text.length === token.raw.length ? text.slice(cursor) : raw,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
function span(text, marks = []) {
|
|
71
|
+
return { _type: 'span', _key: key(), text, marks };
|
|
72
|
+
}
|
|
73
|
+
function withInlineMathTokens(tokens, inlineMath) {
|
|
74
|
+
if (!tokens || !inlineMath)
|
|
75
|
+
return tokens ?? [];
|
|
76
|
+
const result = [];
|
|
77
|
+
for (let index = 0; index < tokens.length;) {
|
|
78
|
+
if (!['text', 'escape'].includes(tokens[index].type)) {
|
|
79
|
+
result.push(tokens[index]);
|
|
80
|
+
index += 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const run = [];
|
|
84
|
+
while (index < tokens.length && ['text', 'escape'].includes(tokens[index].type)) {
|
|
85
|
+
run.push(tokens[index]);
|
|
86
|
+
index += 1;
|
|
87
|
+
}
|
|
88
|
+
const source = run.map((token) => token.raw).join('');
|
|
89
|
+
const matches = [...source.matchAll(/(?<!\\)\$([^$\n]+)\$/g)];
|
|
90
|
+
if (!matches.length) {
|
|
91
|
+
result.push(...run);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const appendSourceRange = (start, end) => {
|
|
95
|
+
let offset = 0;
|
|
96
|
+
for (const token of run) {
|
|
97
|
+
const tokenStart = offset;
|
|
98
|
+
const tokenEnd = tokenStart + token.raw.length;
|
|
99
|
+
offset = tokenEnd;
|
|
100
|
+
const from = Math.max(start, tokenStart);
|
|
101
|
+
const to = Math.min(end, tokenEnd);
|
|
102
|
+
if (from >= to)
|
|
103
|
+
continue;
|
|
104
|
+
if (from === tokenStart && to === tokenEnd) {
|
|
105
|
+
result.push(token);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const localStart = from - tokenStart;
|
|
109
|
+
const localEnd = to - tokenStart;
|
|
110
|
+
const raw = token.raw.slice(localStart, localEnd);
|
|
111
|
+
const text = token.text ?? token.raw;
|
|
112
|
+
result.push({
|
|
113
|
+
...token,
|
|
114
|
+
raw,
|
|
115
|
+
text: text.length === token.raw.length
|
|
116
|
+
? text.slice(localStart, localEnd)
|
|
117
|
+
: raw,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
let cursor = 0;
|
|
122
|
+
for (const match of matches) {
|
|
123
|
+
const start = match.index ?? 0;
|
|
124
|
+
const raw = match[0];
|
|
125
|
+
appendSourceRange(cursor, start);
|
|
126
|
+
result.push({ type: 'docsMath', raw, text: match[1] ?? '' });
|
|
127
|
+
cursor = start + raw.length;
|
|
128
|
+
}
|
|
129
|
+
appendSourceRange(cursor, source.length);
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
function inline(tokens, markDefs, inlineMath = true, inheritedMarks = []) {
|
|
134
|
+
if (!tokens)
|
|
135
|
+
return [];
|
|
136
|
+
let activeMarks = [...inheritedMarks];
|
|
137
|
+
const result = [];
|
|
138
|
+
const addMark = (items, mark) => items.map((item) => (item._type === 'span' ? { ...item, marks: [...item.marks, mark] } : item));
|
|
139
|
+
for (const token of withInlineMathTokens(inlineMath ? withGeneratedInlineMathTokens(tokens) : tokens, inlineMath)) {
|
|
140
|
+
if (token.type === 'docsMath') {
|
|
141
|
+
result.push({ _type: 'math', _key: key(), code: token.text ?? '', inline: true });
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (token.type === 'html') {
|
|
145
|
+
const tag = token.raw.match(/^<(\/)?(u|ins|s|del|strike|em|i|strong|b|code)\s*>$/i);
|
|
146
|
+
if (tag) {
|
|
147
|
+
const mark = /^code$/i.test(tag[2])
|
|
148
|
+
? 'code'
|
|
149
|
+
: /^(?:u|ins)$/i.test(tag[2])
|
|
150
|
+
? 'underline'
|
|
151
|
+
: /^(?:em|i)$/i.test(tag[2])
|
|
152
|
+
? 'em'
|
|
153
|
+
: /^(?:strong|b)$/i.test(tag[2])
|
|
154
|
+
? 'strong'
|
|
155
|
+
: 'strike-through';
|
|
156
|
+
if (tag[1])
|
|
157
|
+
activeMarks = activeMarks.filter((item) => item !== mark);
|
|
158
|
+
else
|
|
159
|
+
activeMarks = [...activeMarks, mark];
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (/^<br\s*\/?>$/i.test(token.raw)) {
|
|
163
|
+
result.push(span('\n', activeMarks));
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
result.push(span(token.raw, activeMarks));
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (token.type === 'strong') {
|
|
170
|
+
result.push(...addMark(inline(token.tokens, markDefs, inlineMath, activeMarks), 'strong'));
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (token.type === 'em') {
|
|
174
|
+
result.push(...addMark(inline(token.tokens, markDefs, inlineMath, activeMarks), 'em'));
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (token.type === 'del') {
|
|
178
|
+
result.push(...addMark(inline(token.tokens, markDefs, inlineMath, activeMarks), 'strike-through'));
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (token.type === 'link') {
|
|
182
|
+
const href = typeof token.href === 'string' ? token.href : '';
|
|
183
|
+
if (!href || !/^(?:https?:\/\/|mailto:|tel:|\/|\.\.?\/|#)/i.test(href)) {
|
|
184
|
+
result.push(span(token.raw, activeMarks));
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const mark = key();
|
|
188
|
+
markDefs.push({ _type: 'link', _key: mark, href });
|
|
189
|
+
const linked = addMark(inline(token.tokens, markDefs, inlineMath, activeMarks), mark);
|
|
190
|
+
const joined = [];
|
|
191
|
+
for (const item of linked) {
|
|
192
|
+
const previous = joined.at(-1);
|
|
193
|
+
if (item._type === 'span' &&
|
|
194
|
+
previous?._type === 'span' &&
|
|
195
|
+
JSON.stringify(item.marks) === JSON.stringify(previous.marks))
|
|
196
|
+
previous.text += item.text;
|
|
197
|
+
else
|
|
198
|
+
joined.push(item);
|
|
199
|
+
}
|
|
200
|
+
result.push(...joined);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (token.type === 'text' || token.type === 'escape') {
|
|
204
|
+
const tokenText = token.text ?? token.raw;
|
|
205
|
+
if (activeMarks.includes('code')) {
|
|
206
|
+
result.push(span(decodeHtml(tokenText), activeMarks));
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const pieces = tokenText.split(/(\$[^$\n]+\$)/g).filter(Boolean);
|
|
210
|
+
result.push(...pieces.map((piece) => inlineMath && /^\$[^$\n]+\$$/.test(piece)
|
|
211
|
+
? {
|
|
212
|
+
_type: 'math',
|
|
213
|
+
_key: key(),
|
|
214
|
+
code: piece.slice(1, -1),
|
|
215
|
+
inline: true,
|
|
216
|
+
}
|
|
217
|
+
: span(piece, activeMarks)));
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (token.type === 'codespan') {
|
|
221
|
+
result.push(span(token.text ?? token.raw, [...activeMarks, 'code']));
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (token.type === 'br') {
|
|
225
|
+
result.push(span('\n', activeMarks));
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
// Images in the middle of prose have no Portable Text inline equivalent. Keep their source.
|
|
229
|
+
result.push(span(token.raw, activeMarks));
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
function textBlock(style, tokens, fallback, inlineMath = true) {
|
|
234
|
+
const markDefs = [];
|
|
235
|
+
const children = inline(tokens, markDefs, inlineMath);
|
|
236
|
+
return {
|
|
237
|
+
_type: 'block',
|
|
238
|
+
_key: key(),
|
|
239
|
+
style,
|
|
240
|
+
markDefs,
|
|
241
|
+
children: children.length ? children : [span(fallback)],
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function paragraphTokens(tokens) {
|
|
245
|
+
if (!tokens)
|
|
246
|
+
return [];
|
|
247
|
+
return tokens.flatMap((token) => (token.type === 'paragraph' || token.type === 'heading') && token.tokens
|
|
248
|
+
? paragraphTokens(token.tokens)
|
|
249
|
+
: [token]);
|
|
250
|
+
}
|
|
251
|
+
function containsUnsupportedInlineHtml(tokens) {
|
|
252
|
+
return Boolean(tokens?.some((token) => {
|
|
253
|
+
if (token.type === 'html') {
|
|
254
|
+
return (!/^<\/?(?:u|ins|s|del|strike|em|i|strong|b|code)\s*>$/i.test(token.raw) &&
|
|
255
|
+
!/^<br\s*\/?>$/i.test(token.raw));
|
|
256
|
+
}
|
|
257
|
+
return containsUnsupportedInlineHtml(token.tokens);
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
function enabled(options, type) {
|
|
261
|
+
// Imported Terra Portable Text paragraphs are part of the document model itself,
|
|
262
|
+
// not optional rich blocks. Canonical JSON directives let local hosts retain
|
|
263
|
+
// their marks and inline objects without a lossy Markdown round trip.
|
|
264
|
+
if (type === 'block' || type === 'terraBlock')
|
|
265
|
+
return true;
|
|
266
|
+
return enabledDocsBlocks(options).includes(type);
|
|
267
|
+
}
|
|
268
|
+
function richPlaceholder(blocks, block) {
|
|
269
|
+
const placeholder = `TERRADOCSBLOCK${blocks.length}PLACEHOLDER`;
|
|
270
|
+
blocks.push({ ...block, _key: block._key ?? key() });
|
|
271
|
+
return `\n\n${placeholder}\n\n`;
|
|
272
|
+
}
|
|
273
|
+
function rawPlaceholder(blocks, markdown) {
|
|
274
|
+
return richPlaceholder(blocks, { _type: 'raw', markdown });
|
|
275
|
+
}
|
|
276
|
+
function codeFenceRanges(source) {
|
|
277
|
+
const ranges = [];
|
|
278
|
+
let open;
|
|
279
|
+
let index = 0;
|
|
280
|
+
while (index < source.length) {
|
|
281
|
+
const lineStart = index === 0 || source[index - 1] === '\n';
|
|
282
|
+
if (lineStart && !open) {
|
|
283
|
+
const newline = source.indexOf('\n', index);
|
|
284
|
+
const end = newline === -1 ? source.length : newline + 1;
|
|
285
|
+
const line = source.slice(index, end).replace(/\r?\n$/, '');
|
|
286
|
+
const marker = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
287
|
+
if (marker) {
|
|
288
|
+
const fence = marker[1];
|
|
289
|
+
open = { start: index, char: fence[0], length: fence.length };
|
|
290
|
+
index = end;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
else if (lineStart && open) {
|
|
295
|
+
const newline = source.indexOf('\n', index);
|
|
296
|
+
const end = newline === -1 ? source.length : newline + 1;
|
|
297
|
+
const line = source.slice(index, end).replace(/\r?\n$/, '');
|
|
298
|
+
const marker = line.match(/^ {0,3}(`{3,}|~{3,})\s*$/);
|
|
299
|
+
if (marker && marker[1][0] === open.char && marker[1].length >= open.length) {
|
|
300
|
+
ranges.push({ start: open.start, end });
|
|
301
|
+
open = undefined;
|
|
302
|
+
}
|
|
303
|
+
index = end;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
// The original Docs serializer embeds code in a template literal. Fences inside that literal
|
|
307
|
+
// are code content, so treat the whole component as opaque while locating Markdown fences.
|
|
308
|
+
if (!open && source[index] === '<') {
|
|
309
|
+
const opening = readJsxOpeningTag(source, index);
|
|
310
|
+
if (opening?.name === 'Code') {
|
|
311
|
+
index = jsxComponentEnd(source, opening);
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Ignore component-looking text inside inline Markdown code spans.
|
|
316
|
+
if (!open && source[index] === '`' && source[index - 1] !== '\\') {
|
|
317
|
+
const marker = source.slice(index).match(/^`+/)?.[0];
|
|
318
|
+
if (marker) {
|
|
319
|
+
const close = source.indexOf(marker, index + marker.length);
|
|
320
|
+
if (close !== -1) {
|
|
321
|
+
index = close + marker.length;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
index += 1;
|
|
327
|
+
}
|
|
328
|
+
if (open)
|
|
329
|
+
ranges.push({ start: open.start, end: source.length });
|
|
330
|
+
return ranges;
|
|
331
|
+
}
|
|
332
|
+
function protectMarkdownInlineMath(source, inlineMath) {
|
|
333
|
+
if (!inlineMath)
|
|
334
|
+
return source;
|
|
335
|
+
const fences = codeFenceRanges(source);
|
|
336
|
+
let fenceIndex = 0;
|
|
337
|
+
let output = '';
|
|
338
|
+
let cursor = 0;
|
|
339
|
+
let index = 0;
|
|
340
|
+
while (index < source.length) {
|
|
341
|
+
while (fenceIndex < fences.length && index >= fences[fenceIndex].end)
|
|
342
|
+
fenceIndex += 1;
|
|
343
|
+
const fence = fences[fenceIndex];
|
|
344
|
+
if (fence && index >= fence.start && index < fence.end) {
|
|
345
|
+
index = fence.end;
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (source[index] === '`' && source[index - 1] !== '\\') {
|
|
349
|
+
const marker = source.slice(index).match(/^`+/)?.[0];
|
|
350
|
+
const end = marker ? source.indexOf(marker, index + marker.length) : -1;
|
|
351
|
+
if (marker && end !== -1) {
|
|
352
|
+
index = end + marker.length;
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (source[index] !== '$' || source[index - 1] === '\\') {
|
|
357
|
+
index += 1;
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (source[index + 1] === '$') {
|
|
361
|
+
const end = source.indexOf('$$', index + 2);
|
|
362
|
+
if (end !== -1) {
|
|
363
|
+
index = end + 2;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
index += 2;
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
let end = index + 1;
|
|
370
|
+
while (end < source.length && source[end] !== '\n') {
|
|
371
|
+
if (source[end] === '$' && source[end - 1] !== '\\' && source[end + 1] !== '$')
|
|
372
|
+
break;
|
|
373
|
+
end += 1;
|
|
374
|
+
}
|
|
375
|
+
if (end >= source.length || source[end] !== '$' || end === index + 1) {
|
|
376
|
+
index += 1;
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
output += source.slice(cursor, index) + encodeInlineMathPlaceholder(source.slice(index + 1, end));
|
|
380
|
+
index = end + 1;
|
|
381
|
+
cursor = index;
|
|
382
|
+
}
|
|
383
|
+
return output + source.slice(cursor);
|
|
384
|
+
}
|
|
385
|
+
function structuredBlockRanges(source) {
|
|
386
|
+
const ranges = [
|
|
387
|
+
...source.matchAll(/^(:{3,})terra-docs [A-Za-z]+(?:\[[^\]\n]*\])?\s*\r?\n[\s\S]*?^\1\s*$/gm),
|
|
388
|
+
...source.matchAll(/^(:{4,})terra-docs (?:accordion|tabs)\s*\r?\n[\s\S]*?^\1\s*$/gm),
|
|
389
|
+
];
|
|
390
|
+
return ranges
|
|
391
|
+
.map((match) => ({ start: match.index ?? 0, end: (match.index ?? 0) + match[0].length }))
|
|
392
|
+
.sort((a, b) => a.start - b.start);
|
|
393
|
+
}
|
|
394
|
+
function readBracedExpression(source, start) {
|
|
395
|
+
if (source[start] !== '{')
|
|
396
|
+
return undefined;
|
|
397
|
+
let depth = 1;
|
|
398
|
+
let quote;
|
|
399
|
+
for (let index = start + 1; index < source.length; index += 1) {
|
|
400
|
+
const char = source[index];
|
|
401
|
+
if (quote) {
|
|
402
|
+
if (char === '\\') {
|
|
403
|
+
index += 1;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (char === quote)
|
|
407
|
+
quote = undefined;
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
411
|
+
quote = char;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (char === '{')
|
|
415
|
+
depth += 1;
|
|
416
|
+
else if (char === '}') {
|
|
417
|
+
depth -= 1;
|
|
418
|
+
if (depth === 0)
|
|
419
|
+
return { value: source.slice(start + 1, index), end: index + 1 };
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return undefined;
|
|
423
|
+
}
|
|
424
|
+
function readJsxTagEnd(source, start) {
|
|
425
|
+
let quote;
|
|
426
|
+
let expressionDepth = 0;
|
|
427
|
+
for (let index = start + 1; index < source.length; index += 1) {
|
|
428
|
+
const char = source[index];
|
|
429
|
+
if (quote) {
|
|
430
|
+
if (char === '\\') {
|
|
431
|
+
index += 1;
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
if (char === quote)
|
|
435
|
+
quote = undefined;
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
439
|
+
quote = char;
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
if (char === '{')
|
|
443
|
+
expressionDepth += 1;
|
|
444
|
+
else if (char === '}' && expressionDepth > 0)
|
|
445
|
+
expressionDepth -= 1;
|
|
446
|
+
else if (char === '>' && expressionDepth === 0)
|
|
447
|
+
return index + 1;
|
|
448
|
+
}
|
|
449
|
+
return undefined;
|
|
450
|
+
}
|
|
451
|
+
function decodeTemplateLiteral(source) {
|
|
452
|
+
return source.replace(/\\([\\`$])/g, '$1');
|
|
453
|
+
}
|
|
454
|
+
function parseJsxLiteral(source) {
|
|
455
|
+
const value = source.trim();
|
|
456
|
+
if (!value)
|
|
457
|
+
return '';
|
|
458
|
+
if (value.startsWith('`') && value.endsWith('`'))
|
|
459
|
+
return decodeTemplateLiteral(value.slice(1, -1));
|
|
460
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
461
|
+
try {
|
|
462
|
+
return decodeHtml(JSON.parse(value));
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
return decodeHtml(value.slice(1, -1));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (value.startsWith("'") && value.endsWith("'"))
|
|
469
|
+
return decodeHtml(value.slice(1, -1).replace(/\\([\\'"`])/g, '$1'));
|
|
470
|
+
if (/^(?:true|false|null)$/.test(value))
|
|
471
|
+
return JSON.parse(value);
|
|
472
|
+
if (/^-?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i.test(value))
|
|
473
|
+
return Number(value);
|
|
474
|
+
try {
|
|
475
|
+
return JSON.parse(value);
|
|
476
|
+
}
|
|
477
|
+
catch {
|
|
478
|
+
return undefined;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function parseJsxAttributes(source) {
|
|
482
|
+
const attributes = {};
|
|
483
|
+
let index = 0;
|
|
484
|
+
while (index < source.length) {
|
|
485
|
+
while (/\s/.test(source[index] ?? ''))
|
|
486
|
+
index += 1;
|
|
487
|
+
const name = source.slice(index).match(/^[A-Za-z_$][\w$:-]*/)?.[0];
|
|
488
|
+
if (!name) {
|
|
489
|
+
index += 1;
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
index += name.length;
|
|
493
|
+
while (/\s/.test(source[index] ?? ''))
|
|
494
|
+
index += 1;
|
|
495
|
+
if (source[index] !== '=') {
|
|
496
|
+
attributes[name] = true;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
index += 1;
|
|
500
|
+
while (/\s/.test(source[index] ?? ''))
|
|
501
|
+
index += 1;
|
|
502
|
+
const quote = source[index];
|
|
503
|
+
if (quote === '"' || quote === "'") {
|
|
504
|
+
const start = index;
|
|
505
|
+
index += 1;
|
|
506
|
+
while (index < source.length) {
|
|
507
|
+
if (source[index] === '\\') {
|
|
508
|
+
index += 2;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
if (source[index] === quote) {
|
|
512
|
+
index += 1;
|
|
513
|
+
break;
|
|
514
|
+
}
|
|
515
|
+
index += 1;
|
|
516
|
+
}
|
|
517
|
+
attributes[name] = parseJsxLiteral(source.slice(start, index));
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (source[index] === '{') {
|
|
521
|
+
const expression = readBracedExpression(source, index);
|
|
522
|
+
if (!expression)
|
|
523
|
+
break;
|
|
524
|
+
attributes[name] = parseJsxLiteral(expression.value);
|
|
525
|
+
index = expression.end;
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
const bare = source.slice(index).match(/^[^\s/>]+/)?.[0];
|
|
529
|
+
if (!bare) {
|
|
530
|
+
index += 1;
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
attributes[name] = parseJsxLiteral(bare);
|
|
534
|
+
index += bare.length;
|
|
535
|
+
}
|
|
536
|
+
return attributes;
|
|
537
|
+
}
|
|
538
|
+
function readJsxOpeningTag(source, start) {
|
|
539
|
+
if (source[start] !== '<')
|
|
540
|
+
return undefined;
|
|
541
|
+
const name = source.slice(start + 1).match(/^([A-Z][A-Za-z0-9_]*)\b/)?.[1];
|
|
542
|
+
if (!name)
|
|
543
|
+
return undefined;
|
|
544
|
+
const nameEnd = start + name.length + 1;
|
|
545
|
+
const end = readJsxTagEnd(source, start);
|
|
546
|
+
if (!end)
|
|
547
|
+
return undefined;
|
|
548
|
+
const shell = source.slice(nameEnd, end - 1);
|
|
549
|
+
const selfClosing = /\/\s*$/.test(shell);
|
|
550
|
+
return {
|
|
551
|
+
name,
|
|
552
|
+
attributes: parseJsxAttributes(shell.replace(/\/\s*$/, '')),
|
|
553
|
+
end,
|
|
554
|
+
selfClosing,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function codeBodyExpression(source, start) {
|
|
558
|
+
const first = source.slice(start).match(/^\s*\{/);
|
|
559
|
+
if (!first)
|
|
560
|
+
return undefined;
|
|
561
|
+
const expressionStart = start + first[0].length - 1;
|
|
562
|
+
const body = source.slice(expressionStart + 1).match(/^\s*`/);
|
|
563
|
+
return body ? readBracedExpression(source, expressionStart) : undefined;
|
|
564
|
+
}
|
|
565
|
+
function jsxComponentEnd(source, opening) {
|
|
566
|
+
return jsxComponentRange(source, opening)?.end ?? source.length;
|
|
567
|
+
}
|
|
568
|
+
function jsxComponentRange(source, opening) {
|
|
569
|
+
if (opening.selfClosing)
|
|
570
|
+
return { bodyEnd: opening.end, end: opening.end };
|
|
571
|
+
const expression = opening.name === 'Code' ? codeBodyExpression(source, opening.end) : undefined;
|
|
572
|
+
const closePattern = new RegExp(`<\\/${opening.name}\\s*>`, 'g');
|
|
573
|
+
closePattern.lastIndex = expression?.end ?? opening.end;
|
|
574
|
+
const close = closePattern.exec(source);
|
|
575
|
+
if (opening.name === 'Code') {
|
|
576
|
+
// Older exported leaves can omit an end tag before the next Code block. Treat that next
|
|
577
|
+
// opening tag as the boundary instead of swallowing every following code sample.
|
|
578
|
+
const nextOpening = source.indexOf('<Code', expression?.end ?? opening.end);
|
|
579
|
+
if (nextOpening !== -1 && (!close || nextOpening < close.index))
|
|
580
|
+
return { bodyEnd: nextOpening, end: nextOpening };
|
|
581
|
+
}
|
|
582
|
+
return close ? { bodyEnd: close.index, end: close.index + close[0].length } : undefined;
|
|
583
|
+
}
|
|
584
|
+
function parseArrayAttribute(value) {
|
|
585
|
+
if (Array.isArray(value))
|
|
586
|
+
return value;
|
|
587
|
+
if (typeof value !== 'string')
|
|
588
|
+
return undefined;
|
|
589
|
+
try {
|
|
590
|
+
const parsed = JSON.parse(value);
|
|
591
|
+
return Array.isArray(parsed) ? parsed : undefined;
|
|
592
|
+
}
|
|
593
|
+
catch {
|
|
594
|
+
return undefined;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
function componentBlock(name, attributes, body) {
|
|
598
|
+
const expression = codeBodyExpression(body, 0);
|
|
599
|
+
const bodyValue = expression ? parseJsxLiteral(expression.value) : decodeHtml(body.trim());
|
|
600
|
+
if (name === 'Nodes') {
|
|
601
|
+
const nodes = parseArrayAttribute(attributes.nodes);
|
|
602
|
+
const edges = parseArrayAttribute(attributes.edges);
|
|
603
|
+
if (('nodes' in attributes && !nodes) || ('edges' in attributes && !edges))
|
|
604
|
+
return undefined;
|
|
605
|
+
return {
|
|
606
|
+
_type: 'nodes',
|
|
607
|
+
_key: key(),
|
|
608
|
+
...attributes,
|
|
609
|
+
nodes: Array.isArray(nodes) ? nodes : [],
|
|
610
|
+
edges: Array.isArray(edges) ? edges : [],
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
if (name === 'Code') {
|
|
614
|
+
const language = typeof attributes.language === 'string' ? attributes.language : '';
|
|
615
|
+
const source = typeof attributes.source === 'string' ? attributes.source : undefined;
|
|
616
|
+
const codeAttribute = typeof attributes.code === 'string' ? attributes.code : undefined;
|
|
617
|
+
const value = typeof bodyValue === 'string'
|
|
618
|
+
? bodyValue.replace(/^\r?\n/, '').replace(/\r?\n$/, '')
|
|
619
|
+
: (codeAttribute ?? '');
|
|
620
|
+
return {
|
|
621
|
+
_type: 'code',
|
|
622
|
+
_key: key(),
|
|
623
|
+
language,
|
|
624
|
+
...(source ? { source } : {}),
|
|
625
|
+
value: value || codeAttribute || '',
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
if (name === 'Embed')
|
|
629
|
+
return {
|
|
630
|
+
_type: 'embed',
|
|
631
|
+
_key: key(),
|
|
632
|
+
...attributes,
|
|
633
|
+
src: typeof attributes.src === 'string' ? attributes.src : '',
|
|
634
|
+
title: typeof attributes.title === 'string' ? attributes.title : '',
|
|
635
|
+
};
|
|
636
|
+
if (name === 'TsDocs')
|
|
637
|
+
return {
|
|
638
|
+
_type: 'tsDocs',
|
|
639
|
+
_key: key(),
|
|
640
|
+
...attributes,
|
|
641
|
+
scope: typeof attributes.scope === 'string' ? attributes.scope : '',
|
|
642
|
+
};
|
|
643
|
+
return undefined;
|
|
644
|
+
}
|
|
645
|
+
function inHtmlTable(source, index) {
|
|
646
|
+
const before = source.slice(0, index).toLowerCase();
|
|
647
|
+
return before.lastIndexOf('<table') > before.lastIndexOf('</table');
|
|
648
|
+
}
|
|
649
|
+
function transformCanonicalComponents(source, options, blocks) {
|
|
650
|
+
const recognized = new Set(['Nodes', 'Code', 'Embed', 'TsDocs']);
|
|
651
|
+
const fences = codeFenceRanges(source);
|
|
652
|
+
const structured = structuredBlockRanges(source);
|
|
653
|
+
let fenceIndex = 0;
|
|
654
|
+
let structuredIndex = 0;
|
|
655
|
+
let output = '';
|
|
656
|
+
let copiedUntil = 0;
|
|
657
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
658
|
+
while (fenceIndex < fences.length && index >= fences[fenceIndex].end)
|
|
659
|
+
fenceIndex += 1;
|
|
660
|
+
const fence = fences[fenceIndex];
|
|
661
|
+
if (fence && index >= fence.start && index < fence.end) {
|
|
662
|
+
index = fence.end - 1;
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
while (structuredIndex < structured.length && index >= structured[structuredIndex].end)
|
|
666
|
+
structuredIndex += 1;
|
|
667
|
+
const block = structured[structuredIndex];
|
|
668
|
+
if (block && index >= block.start && index < block.end) {
|
|
669
|
+
index = block.end - 1;
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
if (source[index] === '`' && source[index - 1] !== '\\') {
|
|
673
|
+
const marker = source.slice(index).match(/^`+/)?.[0];
|
|
674
|
+
if (marker) {
|
|
675
|
+
const close = source.indexOf(marker, index + marker.length);
|
|
676
|
+
if (close !== -1) {
|
|
677
|
+
index = close + marker.length - 1;
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (source[index] !== '<')
|
|
683
|
+
continue;
|
|
684
|
+
const opening = readJsxOpeningTag(source, index);
|
|
685
|
+
if (!opening || !recognized.has(opening.name))
|
|
686
|
+
continue;
|
|
687
|
+
const component = jsxComponentRange(source, opening);
|
|
688
|
+
if (!component)
|
|
689
|
+
continue;
|
|
690
|
+
const { end, bodyEnd } = component;
|
|
691
|
+
const body = opening.selfClosing ? '' : source.slice(opening.end, bodyEnd);
|
|
692
|
+
const isTableCode = opening.name === 'Code' && inHtmlTable(source, index);
|
|
693
|
+
const type = opening.name === 'Nodes'
|
|
694
|
+
? 'nodes'
|
|
695
|
+
: opening.name === 'Code'
|
|
696
|
+
? 'code'
|
|
697
|
+
: opening.name === 'Embed'
|
|
698
|
+
? 'embed'
|
|
699
|
+
: 'tsDocs';
|
|
700
|
+
const parsed = componentBlock(opening.name, opening.attributes, body);
|
|
701
|
+
if (!parsed) {
|
|
702
|
+
output += source.slice(copiedUntil, index) + rawPlaceholder(blocks, source.slice(index, end));
|
|
703
|
+
copiedUntil = end;
|
|
704
|
+
index = end - 1;
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
if (isTableCode) {
|
|
708
|
+
const value = String(parsed.value ?? parsed.source ?? '');
|
|
709
|
+
output +=
|
|
710
|
+
source.slice(copiedUntil, index) +
|
|
711
|
+
`<code>${value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')}</code>`;
|
|
712
|
+
}
|
|
713
|
+
else {
|
|
714
|
+
const replacement = enabled(options, type)
|
|
715
|
+
? richPlaceholder(blocks, parsed)
|
|
716
|
+
: rawPlaceholder(blocks, source.slice(index, end));
|
|
717
|
+
output += source.slice(copiedUntil, index) + replacement;
|
|
718
|
+
}
|
|
719
|
+
copiedUntil = end;
|
|
720
|
+
index = end - 1;
|
|
721
|
+
}
|
|
722
|
+
return output ? output + source.slice(copiedUntil) : source;
|
|
723
|
+
}
|
|
724
|
+
function transformCallouts(source, options, blocks, parse) {
|
|
725
|
+
const stack = [];
|
|
726
|
+
const ranges = [];
|
|
727
|
+
const fences = codeFenceRanges(source);
|
|
728
|
+
let fenceIndex = 0;
|
|
729
|
+
let offset = 0;
|
|
730
|
+
while (offset < source.length) {
|
|
731
|
+
const newline = source.indexOf('\n', offset);
|
|
732
|
+
const end = newline === -1 ? source.length : newline + 1;
|
|
733
|
+
const line = source.slice(offset, end).replace(/\r?\n$/, '');
|
|
734
|
+
while (fenceIndex < fences.length && offset >= fences[fenceIndex].end)
|
|
735
|
+
fenceIndex += 1;
|
|
736
|
+
const fence = fences[fenceIndex];
|
|
737
|
+
if (fence && offset >= fence.start && offset < fence.end) {
|
|
738
|
+
offset = end;
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
const open = line.match(/^\s*(:{3,})(?!terra-docs(?:\s|$))([A-Za-z][\w-]*)(?:\[([^\]\n]*)\])?\s*$/);
|
|
742
|
+
if (open) {
|
|
743
|
+
stack.push({
|
|
744
|
+
start: offset,
|
|
745
|
+
bodyStart: end,
|
|
746
|
+
fenceLength: open[1].length,
|
|
747
|
+
kind: open[2],
|
|
748
|
+
...(open[3] ? { title: open[3].trim() } : {}),
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
const closing = line.match(/^\s*(:{3,})\s*$/);
|
|
753
|
+
const current = stack.at(-1);
|
|
754
|
+
if (closing && current?.fenceLength === closing[1].length) {
|
|
755
|
+
const closed = stack.pop();
|
|
756
|
+
if (closed && stack.length === 0)
|
|
757
|
+
ranges.push({ ...closed, closeStart: offset, end });
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
offset = end;
|
|
761
|
+
}
|
|
762
|
+
for (const range of ranges.reverse()) {
|
|
763
|
+
const raw = source.slice(range.start, range.end);
|
|
764
|
+
const body = range.closeStart === undefined
|
|
765
|
+
? ''
|
|
766
|
+
: source.slice(range.bodyStart, range.closeStart).trimEnd();
|
|
767
|
+
const content = parse(body);
|
|
768
|
+
const replacement = enabled(options, 'callout')
|
|
769
|
+
? richPlaceholder(blocks, {
|
|
770
|
+
_type: 'callout',
|
|
771
|
+
kind: range.kind,
|
|
772
|
+
title: range.title || range.kind,
|
|
773
|
+
content,
|
|
774
|
+
...(/TERRADOCSBLOCK\d+PLACEHOLDER/.test(body) ? {} : { markdown: body }),
|
|
775
|
+
})
|
|
776
|
+
: rawPlaceholder(blocks, raw);
|
|
777
|
+
source = source.slice(0, range.start) + replacement + source.slice(range.end);
|
|
778
|
+
}
|
|
779
|
+
return source;
|
|
780
|
+
}
|
|
781
|
+
function decodeHtml(value) {
|
|
782
|
+
return value
|
|
783
|
+
.replace(/&#(\d+);?/g, (match, code) => {
|
|
784
|
+
const point = Number(code);
|
|
785
|
+
return Number.isInteger(point) && point >= 0 && point <= 0x10ffff
|
|
786
|
+
? String.fromCodePoint(point)
|
|
787
|
+
: match;
|
|
788
|
+
})
|
|
789
|
+
.replace(/&#x([0-9a-f]+);?/gi, (match, code) => {
|
|
790
|
+
const point = Number.parseInt(code, 16);
|
|
791
|
+
return Number.isInteger(point) && point >= 0 && point <= 0x10ffff
|
|
792
|
+
? String.fromCodePoint(point)
|
|
793
|
+
: match;
|
|
794
|
+
})
|
|
795
|
+
.replace(/&(nbsp|amp|lt|gt|quot|apos|#39);/gi, (_match, entity) => {
|
|
796
|
+
const entities = {
|
|
797
|
+
nbsp: ' ',
|
|
798
|
+
amp: '&',
|
|
799
|
+
lt: '<',
|
|
800
|
+
gt: '>',
|
|
801
|
+
quot: '"',
|
|
802
|
+
apos: "'",
|
|
803
|
+
'#39': "'",
|
|
804
|
+
};
|
|
805
|
+
return entities[entity.toLowerCase()] ?? _match;
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
function decodeHtmlRepeated(value) {
|
|
809
|
+
let current = value;
|
|
810
|
+
for (let pass = 0; pass < 8; pass += 1) {
|
|
811
|
+
const decoded = decodeHtml(current);
|
|
812
|
+
if (decoded === current)
|
|
813
|
+
break;
|
|
814
|
+
current = decoded;
|
|
815
|
+
}
|
|
816
|
+
return current;
|
|
817
|
+
}
|
|
818
|
+
function htmlAttribute(attributes, name) {
|
|
819
|
+
const match = attributes.match(new RegExp(`\\b${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, 'i'));
|
|
820
|
+
const value = match?.[1] ?? match?.[2] ?? match?.[3];
|
|
821
|
+
return value === undefined ? undefined : decodeHtml(value);
|
|
822
|
+
}
|
|
823
|
+
function escapeMarkdownText(value) {
|
|
824
|
+
return decodeHtmlRepeated(value).replace(/(\$[^$\n]+\$)|([\\`*_{}\x5B\x5D#<>!$])/g, (_match, math, character) => math ?? `\\${character}`);
|
|
825
|
+
}
|
|
826
|
+
function markdownCodeSpan(value) {
|
|
827
|
+
const longest = Math.max(0, ...[...value.matchAll(/`+/g)].map(([ticks]) => ticks.length));
|
|
828
|
+
const fence = '`'.repeat(longest + 1);
|
|
829
|
+
const padding = value.startsWith('`') || value.endsWith('`') ? ' ' : '';
|
|
830
|
+
return `${fence}${padding}${value}${padding}${fence}`;
|
|
831
|
+
}
|
|
832
|
+
function htmlCodeText(value) {
|
|
833
|
+
const entities = {
|
|
834
|
+
'&': '&',
|
|
835
|
+
'<': '<',
|
|
836
|
+
'>': '>',
|
|
837
|
+
'`': '`',
|
|
838
|
+
'*': '*',
|
|
839
|
+
_: '_',
|
|
840
|
+
'[': '[',
|
|
841
|
+
']': ']',
|
|
842
|
+
'\\': '\',
|
|
843
|
+
'!': '!',
|
|
844
|
+
$: '$',
|
|
845
|
+
'|': '|',
|
|
846
|
+
'~': '~',
|
|
847
|
+
'\r': ' ',
|
|
848
|
+
'\n': ' ',
|
|
849
|
+
};
|
|
850
|
+
return value.replace(/[&<>`*_\x5B\x5D\\!$|~\r\n]/g, (character) => entities[character]);
|
|
851
|
+
}
|
|
852
|
+
function markdownDestination(value) {
|
|
853
|
+
const destination = decodeHtmlRepeated(value).replace(/[>\s]/g, (character) => character === '>' ? '%3E' : '%20');
|
|
854
|
+
return /[()[\]<>]/.test(destination) ? '<' + destination + '>' : destination;
|
|
855
|
+
}
|
|
856
|
+
/** Convert HTML table cells without letting ordinary underscores become Markdown emphasis. */
|
|
857
|
+
function escapeHtmlTableText(value, inlineMath) {
|
|
858
|
+
const decoded = decodeHtmlRepeated(value);
|
|
859
|
+
if (!inlineMath)
|
|
860
|
+
return escapeMarkdownText(decoded);
|
|
861
|
+
const matches = [...decoded.matchAll(/(?<!\\)\$([^$\n]+)\$/g)];
|
|
862
|
+
if (!matches.length)
|
|
863
|
+
return escapeMarkdownText(decoded);
|
|
864
|
+
let output = '';
|
|
865
|
+
let cursor = 0;
|
|
866
|
+
for (const match of matches) {
|
|
867
|
+
const start = match.index ?? 0;
|
|
868
|
+
const code = match[1] ?? '';
|
|
869
|
+
output +=
|
|
870
|
+
escapeMarkdownText(decoded.slice(cursor, start)) +
|
|
871
|
+
encodeInlineMathPlaceholder(code);
|
|
872
|
+
cursor = start + match[0].length;
|
|
873
|
+
}
|
|
874
|
+
return output + escapeMarkdownText(decoded.slice(cursor));
|
|
875
|
+
}
|
|
876
|
+
function htmlToMarkdown(source, inlineMath) {
|
|
877
|
+
const stack = [];
|
|
878
|
+
const tagPattern = /<!--[\s\S]*?-->|<\/?([A-Za-z][A-Za-z0-9:-]*)\b([^>]*?)>/g;
|
|
879
|
+
let output = '';
|
|
880
|
+
let copiedUntil = 0;
|
|
881
|
+
let match;
|
|
882
|
+
while ((match = tagPattern.exec(source))) {
|
|
883
|
+
const index = match.index ?? 0;
|
|
884
|
+
const raw = match[0];
|
|
885
|
+
const name = match[1]?.toLowerCase();
|
|
886
|
+
if (!name) {
|
|
887
|
+
output += escapeHtmlTableText(source.slice(copiedUntil, index), inlineMath);
|
|
888
|
+
copiedUntil = index + raw.length;
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
const closing = /^<\//.test(raw);
|
|
892
|
+
const selfClosing = /\/\s*>$/.test(raw);
|
|
893
|
+
const attributes = match[2] ?? '';
|
|
894
|
+
output += escapeHtmlTableText(source.slice(copiedUntil, index), inlineMath);
|
|
895
|
+
copiedUntil = tagPattern.lastIndex;
|
|
896
|
+
if (closing) {
|
|
897
|
+
const openIndex = stack.map((tag) => tag.name).lastIndexOf(name);
|
|
898
|
+
if (openIndex >= 0) {
|
|
899
|
+
for (let position = stack.length - 1; position >= openIndex; position -= 1)
|
|
900
|
+
output += stack.pop().close;
|
|
901
|
+
}
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
if (name === 'br') {
|
|
905
|
+
output += '\n';
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
if (name === 'img') {
|
|
909
|
+
const alt = htmlAttribute(attributes, 'alt') ?? 'image';
|
|
910
|
+
const src = htmlAttribute(attributes, 'src') ?? '';
|
|
911
|
+
const title = htmlAttribute(attributes, 'title');
|
|
912
|
+
const escapedTitle = title?.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
913
|
+
output += src
|
|
914
|
+
? `}${escapedTitle ? ` "${escapedTitle}"` : ''})`
|
|
915
|
+
: escapeMarkdownText(alt);
|
|
916
|
+
continue;
|
|
917
|
+
}
|
|
918
|
+
if (name === 'code') {
|
|
919
|
+
// Code content is opaque; preserve punctuation and decode the deeply escaped export text.
|
|
920
|
+
const closeTag = /<\/code\s*>/gi;
|
|
921
|
+
closeTag.lastIndex = copiedUntil;
|
|
922
|
+
const close = closeTag.exec(source);
|
|
923
|
+
if (close) {
|
|
924
|
+
output += markdownCodeSpan(decodeHtmlRepeated(source.slice(copiedUntil, close.index)));
|
|
925
|
+
copiedUntil = closeTag.lastIndex;
|
|
926
|
+
tagPattern.lastIndex = copiedUntil;
|
|
927
|
+
}
|
|
928
|
+
else
|
|
929
|
+
output += escapeMarkdownText(raw);
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
let open = '';
|
|
933
|
+
let close = '';
|
|
934
|
+
if (name === 'a') {
|
|
935
|
+
const href = htmlAttribute(attributes, 'href');
|
|
936
|
+
if (href)
|
|
937
|
+
[open, close] = ['[', `](${markdownDestination(href)})`];
|
|
938
|
+
}
|
|
939
|
+
else if (name === 'strong' || name === 'b')
|
|
940
|
+
[open, close] = ['**', '**'];
|
|
941
|
+
else if (name === 'em' || name === 'i')
|
|
942
|
+
[open, close] = ['*', '*'];
|
|
943
|
+
else if (name === 's' || name === 'del' || name === 'strike')
|
|
944
|
+
[open, close] = ['~~', '~~'];
|
|
945
|
+
else if (name === 'p' || name === 'div')
|
|
946
|
+
[open, close] = ['\n\n', '\n\n'];
|
|
947
|
+
else if (name === 'li')
|
|
948
|
+
[open, close] = ['\n- ', '\n'];
|
|
949
|
+
else if (name === 'pre')
|
|
950
|
+
[open, close] = ['\n\n```\n', '\n```\n\n'];
|
|
951
|
+
output += open;
|
|
952
|
+
if (open && !selfClosing)
|
|
953
|
+
stack.push({ name, close });
|
|
954
|
+
else if ((name === 'p' || name === 'div' || name === 'li' || name === 'pre') && !selfClosing)
|
|
955
|
+
stack.push({ name, close });
|
|
956
|
+
}
|
|
957
|
+
output += escapeHtmlTableText(source.slice(copiedUntil), inlineMath);
|
|
958
|
+
while (stack.length)
|
|
959
|
+
output += stack.pop().close;
|
|
960
|
+
return output.replace(/\n{3,}/g, '\n\n').trim();
|
|
961
|
+
}
|
|
962
|
+
function tableCell(tokens, fallback, options) {
|
|
963
|
+
const contentTokens = [[]];
|
|
964
|
+
for (const token of tokens) {
|
|
965
|
+
if (token.type === 'html' && /^<br\s+data-docs-paragraph-break\s*\/?>$/i.test(token.raw)) {
|
|
966
|
+
contentTokens.push([]);
|
|
967
|
+
}
|
|
968
|
+
else {
|
|
969
|
+
contentTokens.at(-1).push(token);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
const inlineMath = options.inlineMath !== false && options.math !== false;
|
|
973
|
+
const content = contentTokens.flatMap((part) => {
|
|
974
|
+
const result = [];
|
|
975
|
+
let pending = [];
|
|
976
|
+
const flush = () => {
|
|
977
|
+
if (!pending.length)
|
|
978
|
+
return;
|
|
979
|
+
const text = pending.map((token) => token.text ?? token.raw).join('');
|
|
980
|
+
result.push(textBlock('normal', pending, text, inlineMath));
|
|
981
|
+
pending = [];
|
|
982
|
+
};
|
|
983
|
+
for (const token of part) {
|
|
984
|
+
if (token.type === 'image' && enabled(options, 'docImage')) {
|
|
985
|
+
flush();
|
|
986
|
+
result.push({
|
|
987
|
+
_type: 'docImage',
|
|
988
|
+
_key: key(),
|
|
989
|
+
alt: token.text ?? '',
|
|
990
|
+
url: token.href ?? '',
|
|
991
|
+
...(token.title ? { title: token.title } : {}),
|
|
992
|
+
markdown: token.raw,
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
else {
|
|
996
|
+
// Keep an opted-out image as literal Markdown instead of dropping it.
|
|
997
|
+
pending.push(token);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
flush();
|
|
1001
|
+
if (!result.length) {
|
|
1002
|
+
const text = part.map((token) => token.text ?? token.raw).join('') || fallback;
|
|
1003
|
+
result.push(textBlock('normal', part, text, inlineMath));
|
|
1004
|
+
}
|
|
1005
|
+
return result;
|
|
1006
|
+
});
|
|
1007
|
+
return { _type: 'cell', _key: key(), content };
|
|
1008
|
+
}
|
|
1009
|
+
function tableBlock(rows, markdown, options, header = 'Table') {
|
|
1010
|
+
if (!rows.length)
|
|
1011
|
+
return undefined;
|
|
1012
|
+
return {
|
|
1013
|
+
_type: 'table',
|
|
1014
|
+
_key: key(),
|
|
1015
|
+
header,
|
|
1016
|
+
markdown: restoreInlineMathPlaceholders(markdown),
|
|
1017
|
+
rows: rows.map((cells) => ({
|
|
1018
|
+
_type: 'row',
|
|
1019
|
+
_key: key(),
|
|
1020
|
+
cells: cells.map((cell) => tableCell(Array.isArray(cell.tokens) ? cell.tokens : [], cell.text ?? cell.raw, options)),
|
|
1021
|
+
})),
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
function markdownImagesAsBlocks(source, options, blocks) {
|
|
1025
|
+
if (!enabled(options, 'docImage'))
|
|
1026
|
+
return source;
|
|
1027
|
+
const images = [];
|
|
1028
|
+
const visit = (tokens, insideLink = false) => {
|
|
1029
|
+
for (const token of tokens ?? []) {
|
|
1030
|
+
if (token.type === 'image' && !insideLink)
|
|
1031
|
+
images.push(token);
|
|
1032
|
+
else if (token.tokens)
|
|
1033
|
+
visit(token.tokens, insideLink || token.type === 'link');
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
visit(marked.lexer(source, { gfm: true }));
|
|
1037
|
+
let result = source;
|
|
1038
|
+
let cursor = 0;
|
|
1039
|
+
for (const image of images) {
|
|
1040
|
+
const raw = image.raw;
|
|
1041
|
+
const index = result.indexOf(raw, cursor);
|
|
1042
|
+
if (index < 0 || typeof image.href !== 'string')
|
|
1043
|
+
continue;
|
|
1044
|
+
const block = {
|
|
1045
|
+
_type: 'docImage',
|
|
1046
|
+
_key: key(),
|
|
1047
|
+
alt: image.text ?? '',
|
|
1048
|
+
url: image.href,
|
|
1049
|
+
...(image.title ? { title: image.title } : {}),
|
|
1050
|
+
markdown: raw,
|
|
1051
|
+
};
|
|
1052
|
+
const placeholder = richPlaceholder(blocks, block);
|
|
1053
|
+
result = result.slice(0, index) + placeholder + result.slice(index + raw.length);
|
|
1054
|
+
cursor = index + placeholder.length;
|
|
1055
|
+
}
|
|
1056
|
+
return result;
|
|
1057
|
+
}
|
|
1058
|
+
function htmlTableBlock(source, options, blocks) {
|
|
1059
|
+
const table = source.match(/<table\b[^>]*>[\s\S]*?<\/table\s*>/i)?.[0];
|
|
1060
|
+
if (!table)
|
|
1061
|
+
return undefined;
|
|
1062
|
+
const rows = [...table.matchAll(/<tr\b[^>]*>([\s\S]*?)<\/tr\s*>/gi)].map((row) => {
|
|
1063
|
+
const cells = [...(row[1] ?? '').matchAll(/<(?:th|td)\b[^>]*>([\s\S]*?)<\/(?:th|td)\s*>/gi)];
|
|
1064
|
+
return cells.map((cell) => {
|
|
1065
|
+
const markdown = htmlToMarkdown(cell[1] ?? '', options.inlineMath !== false && options.math !== false);
|
|
1066
|
+
const cellBlocks = [];
|
|
1067
|
+
const cellMarkdownWithBlocks = markdown.replace(/TERRADOCSBLOCK(\d+)PLACEHOLDER/g, (placeholder, indexText) => {
|
|
1068
|
+
const original = blocks[Number(indexText)];
|
|
1069
|
+
return original ? richPlaceholder(cellBlocks, original) : placeholder;
|
|
1070
|
+
});
|
|
1071
|
+
const cellMarkdown = markdownImagesAsBlocks(cellMarkdownWithBlocks, options, cellBlocks);
|
|
1072
|
+
return {
|
|
1073
|
+
_type: 'cell',
|
|
1074
|
+
_key: key(),
|
|
1075
|
+
content: parseMarkdown(cellMarkdown, options, cellBlocks),
|
|
1076
|
+
};
|
|
1077
|
+
});
|
|
1078
|
+
});
|
|
1079
|
+
const parsedRows = rows.map((cells) => ({
|
|
1080
|
+
_type: 'row',
|
|
1081
|
+
_key: key(),
|
|
1082
|
+
cells,
|
|
1083
|
+
}));
|
|
1084
|
+
// Use one isolated placeholder registry per cell; parsing every paragraph and rich inline
|
|
1085
|
+
// component is necessary to keep the table's complete source visible in the nested renderer.
|
|
1086
|
+
return {
|
|
1087
|
+
_type: 'table',
|
|
1088
|
+
_key: key(),
|
|
1089
|
+
header: 'Table',
|
|
1090
|
+
markdown: restoreInlineMathPlaceholders(table),
|
|
1091
|
+
rows: parsedRows,
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
function markdownList(token, options, level = 1) {
|
|
1095
|
+
const items = Array.isArray(token.items) ? token.items : [];
|
|
1096
|
+
const result = [];
|
|
1097
|
+
for (const item of items) {
|
|
1098
|
+
const itemTokens = Array.isArray(item.tokens) ? item.tokens : [];
|
|
1099
|
+
const bodyTokens = [];
|
|
1100
|
+
const nestedLists = [];
|
|
1101
|
+
for (const child of itemTokens) {
|
|
1102
|
+
if (child.type === 'list') {
|
|
1103
|
+
nestedLists.push(child);
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
const childTokens = (child.type === 'text' || child.type === 'paragraph') && Array.isArray(child.tokens)
|
|
1107
|
+
? child.tokens
|
|
1108
|
+
: [child];
|
|
1109
|
+
if (bodyTokens.length)
|
|
1110
|
+
bodyTokens.push({ type: 'text', raw: '\n', text: '\n' });
|
|
1111
|
+
bodyTokens.push(...childTokens);
|
|
1112
|
+
}
|
|
1113
|
+
const markDefs = [];
|
|
1114
|
+
let children = inline(bodyTokens, markDefs, options.inlineMath !== false && options.math !== false);
|
|
1115
|
+
if (item.task)
|
|
1116
|
+
children = [span(item.checked ? '[x] ' : '[ ] '), ...children];
|
|
1117
|
+
if (children.length) {
|
|
1118
|
+
result.push({
|
|
1119
|
+
_type: 'block',
|
|
1120
|
+
_key: key(),
|
|
1121
|
+
style: 'normal',
|
|
1122
|
+
listItem: token.ordered ? 'number' : 'bullet',
|
|
1123
|
+
level,
|
|
1124
|
+
markDefs,
|
|
1125
|
+
children,
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
else {
|
|
1129
|
+
result.push({ _type: 'raw', _key: key(), markdown: item.raw });
|
|
1130
|
+
}
|
|
1131
|
+
for (const nested of nestedLists)
|
|
1132
|
+
result.push(...markdownList(nested, options, level + 1));
|
|
1133
|
+
}
|
|
1134
|
+
return result;
|
|
1135
|
+
}
|
|
1136
|
+
/** Decode Markdown without dropping unsupported syntax; opaque tokens become raw blocks. */
|
|
1137
|
+
export function markdownToDocsValue(markdown, options = {}) {
|
|
1138
|
+
return parseMarkdown(markdown, options, []);
|
|
1139
|
+
}
|
|
1140
|
+
function parseGroupedItems(source, options, blocks) {
|
|
1141
|
+
const markers = [...source.matchAll(/^:::terra-item ("(?:\\.|[^"\\])*")[ \t]*\r?$/gm)];
|
|
1142
|
+
if (!markers.length || source.slice(0, markers[0].index).trim())
|
|
1143
|
+
return undefined;
|
|
1144
|
+
const items = [];
|
|
1145
|
+
let consumedUntil = 0;
|
|
1146
|
+
for (let index = 0; index < markers.length; index += 1) {
|
|
1147
|
+
const marker = markers[index];
|
|
1148
|
+
const bodyStart = (marker.index ?? 0) + marker[0].length;
|
|
1149
|
+
const nextStart = markers[index + 1]?.index ?? source.length;
|
|
1150
|
+
const closing = /^:::terra-item-end[ \t]*\r?$/gm;
|
|
1151
|
+
closing.lastIndex = bodyStart;
|
|
1152
|
+
const end = closing.exec(source);
|
|
1153
|
+
if (!end || end.index >= nextStart || source.slice(end.index + end[0].length, nextStart).trim())
|
|
1154
|
+
return undefined;
|
|
1155
|
+
let title;
|
|
1156
|
+
try {
|
|
1157
|
+
title = JSON.parse(marker[1]);
|
|
1158
|
+
}
|
|
1159
|
+
catch {
|
|
1160
|
+
return undefined;
|
|
1161
|
+
}
|
|
1162
|
+
const body = source
|
|
1163
|
+
.slice(bodyStart, end.index)
|
|
1164
|
+
.replace(/^\r?\n/, '')
|
|
1165
|
+
.replace(/\r?\n$/, '');
|
|
1166
|
+
const content = parseMarkdown(body, options, blocks);
|
|
1167
|
+
items.push({
|
|
1168
|
+
_type: 'item',
|
|
1169
|
+
_key: key(),
|
|
1170
|
+
title,
|
|
1171
|
+
...(/TERRADOCSBLOCK\d+PLACEHOLDER/.test(body) ? {} : { markdown: body }),
|
|
1172
|
+
content,
|
|
1173
|
+
});
|
|
1174
|
+
consumedUntil = end.index + end[0].length;
|
|
1175
|
+
}
|
|
1176
|
+
return source.slice(consumedUntil).trim() ? undefined : items;
|
|
1177
|
+
}
|
|
1178
|
+
function parseMarkdownTableCells(block, options, blocks) {
|
|
1179
|
+
const source = block;
|
|
1180
|
+
if (source._docsCellFormat !== 'markdown-v1' || !Array.isArray(source.rows))
|
|
1181
|
+
return block;
|
|
1182
|
+
const { rows: sourceRows, ...table } = source;
|
|
1183
|
+
delete table._docsCellFormat;
|
|
1184
|
+
const rows = sourceRows.map((row) => {
|
|
1185
|
+
if (!row || typeof row !== 'object')
|
|
1186
|
+
return row;
|
|
1187
|
+
const rowSource = row;
|
|
1188
|
+
const { cells: sourceCells, ...rowFields } = rowSource;
|
|
1189
|
+
const cells = Array.isArray(sourceCells)
|
|
1190
|
+
? sourceCells.map((cell) => {
|
|
1191
|
+
if (!cell || typeof cell !== 'object')
|
|
1192
|
+
return cell;
|
|
1193
|
+
const cellSource = cell;
|
|
1194
|
+
const { markdown, ...cellFields } = cellSource;
|
|
1195
|
+
if (typeof markdown !== 'string')
|
|
1196
|
+
return {
|
|
1197
|
+
...cellFields,
|
|
1198
|
+
_type: typeof cellFields._type === 'string' ? cellFields._type : 'cell',
|
|
1199
|
+
content: Array.isArray(cellFields.content) ? cellFields.content : [],
|
|
1200
|
+
};
|
|
1201
|
+
return {
|
|
1202
|
+
...cellFields,
|
|
1203
|
+
_type: typeof cellFields._type === 'string' ? cellFields._type : 'cell',
|
|
1204
|
+
content: parseMarkdown(markdown, options, blocks),
|
|
1205
|
+
};
|
|
1206
|
+
})
|
|
1207
|
+
: sourceCells;
|
|
1208
|
+
return {
|
|
1209
|
+
...rowFields,
|
|
1210
|
+
_type: typeof rowFields._type === 'string' ? rowFields._type : 'row',
|
|
1211
|
+
cells,
|
|
1212
|
+
};
|
|
1213
|
+
});
|
|
1214
|
+
return { ...table, _type: 'table', rows };
|
|
1215
|
+
}
|
|
1216
|
+
function parseMarkdown(markdown, options, blocks) {
|
|
1217
|
+
const inlineMath = options.inlineMath !== false && options.math !== false;
|
|
1218
|
+
const jsxSource = transformCanonicalComponents(markdown, options, blocks);
|
|
1219
|
+
const richSource = jsxSource.replace(/^(:{3,})terra-docs ([A-Za-z]+)\s*\n([\s\S]*?)^\1\s*$/gm, (source, fence, type, payload) => {
|
|
1220
|
+
// Four-colon accordion/tab blocks use grouped Markdown items. Sending
|
|
1221
|
+
// their prose through YAML first misreads list lines such as
|
|
1222
|
+
// `- **Research**: ...` as aliases and can emit noisy parser warnings.
|
|
1223
|
+
// Leave this form for the grouped-block parser below.
|
|
1224
|
+
if (fence.length >= 4 &&
|
|
1225
|
+
(type === 'accordion' || type === 'tabs') &&
|
|
1226
|
+
/^:::terra-item "/m.test(payload))
|
|
1227
|
+
return source;
|
|
1228
|
+
try {
|
|
1229
|
+
const data = parseYaml(payload);
|
|
1230
|
+
if (data && data._type === type) {
|
|
1231
|
+
const normalized = type === 'table' ? parseMarkdownTableCells(data, options, blocks) : data;
|
|
1232
|
+
return enabled(options, type)
|
|
1233
|
+
? richPlaceholder(blocks, normalized)
|
|
1234
|
+
: rawPlaceholder(blocks, source);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
catch {
|
|
1238
|
+
// Four-colon accordion and tab blocks use nested Markdown rather than a typed payload.
|
|
1239
|
+
if (fence.length >= 4 && (type === 'accordion' || type === 'tabs'))
|
|
1240
|
+
return source;
|
|
1241
|
+
}
|
|
1242
|
+
if (fence.length >= 4 && (type === 'accordion' || type === 'tabs'))
|
|
1243
|
+
return source;
|
|
1244
|
+
return rawPlaceholder(blocks, source);
|
|
1245
|
+
});
|
|
1246
|
+
const withCaptionTables = richSource.replace(/^:::terra-docs table\[([^\]\r\n]*)\][ \t]*\r?\n([\s\S]*?)^:::[ \t]*$/gm, (source, caption, body) => {
|
|
1247
|
+
if (!enabled(options, 'table'))
|
|
1248
|
+
return rawPlaceholder(blocks, source);
|
|
1249
|
+
let header = caption;
|
|
1250
|
+
try {
|
|
1251
|
+
header = decodeURIComponent(caption);
|
|
1252
|
+
}
|
|
1253
|
+
catch {
|
|
1254
|
+
/* Keep a readable caption if an older hand-authored value is not URI-encoded. */
|
|
1255
|
+
}
|
|
1256
|
+
const tableToken = marked.lexer(body, { gfm: true }).find((token) => token.type === 'table');
|
|
1257
|
+
if (!tableToken)
|
|
1258
|
+
return rawPlaceholder(blocks, source);
|
|
1259
|
+
const table = tableBlock([tableToken.header ?? [], ...(tableToken.rows ?? [])], body, options, header);
|
|
1260
|
+
return table ? richPlaceholder(blocks, table) : rawPlaceholder(blocks, source);
|
|
1261
|
+
});
|
|
1262
|
+
const withGroupedBlocks = withCaptionTables.replace(/^(:{4,})terra-docs (accordion|tabs)[ \t]*\r?\n([\s\S]*?)^\1[ \t]*$/gm, (source, _fence, type, body) => {
|
|
1263
|
+
if (!enabled(options, type))
|
|
1264
|
+
return rawPlaceholder(blocks, source);
|
|
1265
|
+
const items = parseGroupedItems(body, options, blocks);
|
|
1266
|
+
return items
|
|
1267
|
+
? richPlaceholder(blocks, { _type: type, items })
|
|
1268
|
+
: rawPlaceholder(blocks, source);
|
|
1269
|
+
});
|
|
1270
|
+
const withAccordions = withGroupedBlocks.replace(/^(===|\|\|\|)\s*\[([^\]\n]+)\]\s*\n([\s\S]*?)^\1\s*$/gm, (source, delimiter, title, body) => {
|
|
1271
|
+
const type = delimiter === '===' ? 'accordion' : 'tabs';
|
|
1272
|
+
if (!enabled(options, type))
|
|
1273
|
+
return rawPlaceholder(blocks, source);
|
|
1274
|
+
return richPlaceholder(blocks, {
|
|
1275
|
+
_type: type,
|
|
1276
|
+
items: [
|
|
1277
|
+
{
|
|
1278
|
+
title,
|
|
1279
|
+
...(/TERRADOCSBLOCK\d+PLACEHOLDER/.test(body) ? {} : { markdown: body }),
|
|
1280
|
+
content: parseMarkdown(body, options, blocks),
|
|
1281
|
+
},
|
|
1282
|
+
],
|
|
1283
|
+
});
|
|
1284
|
+
});
|
|
1285
|
+
const withCallouts = transformCallouts(withAccordions, options, blocks, (body) => parseMarkdown(body, options, blocks));
|
|
1286
|
+
const source = withCallouts.replace(/^\$\$\s*\n([\s\S]*?)^\$\$\s*$/gm, (raw, code) => enabled(options, 'math')
|
|
1287
|
+
? richPlaceholder(blocks, { _type: 'math', code: code.trim(), inline: false, markdown: raw })
|
|
1288
|
+
: rawPlaceholder(blocks, raw));
|
|
1289
|
+
const parsed = marked.lexer(protectMarkdownInlineMath(source, inlineMath), { gfm: true });
|
|
1290
|
+
const result = [];
|
|
1291
|
+
for (const token of parsed) {
|
|
1292
|
+
if (token.type === 'space')
|
|
1293
|
+
continue;
|
|
1294
|
+
const marker = token.raw.trim().match(/^TERRADOCSBLOCK(\d+)PLACEHOLDER$/);
|
|
1295
|
+
if (marker) {
|
|
1296
|
+
const block = blocks[Number(marker[1])];
|
|
1297
|
+
if (block)
|
|
1298
|
+
result.push(block);
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
if (token.type === 'heading') {
|
|
1302
|
+
const depth = token.depth ?? 2;
|
|
1303
|
+
const style = depth === 1 ? 'normal' : `h${Math.min(6, depth)}`;
|
|
1304
|
+
result.push(textBlock(style, token.tokens, token.text ?? '', inlineMath));
|
|
1305
|
+
continue;
|
|
1306
|
+
}
|
|
1307
|
+
if (token.type === 'paragraph') {
|
|
1308
|
+
const image = token.tokens?.length === 1 && token.tokens[0]?.type === 'image'
|
|
1309
|
+
? token.tokens[0]
|
|
1310
|
+
: undefined;
|
|
1311
|
+
if (image && enabled(options, 'docImage')) {
|
|
1312
|
+
result.push({
|
|
1313
|
+
_type: 'docImage',
|
|
1314
|
+
_key: key(),
|
|
1315
|
+
alt: image.text ?? '',
|
|
1316
|
+
url: image.href ?? '',
|
|
1317
|
+
...(image.title ? { title: image.title } : {}),
|
|
1318
|
+
markdown: token.raw,
|
|
1319
|
+
});
|
|
1320
|
+
continue;
|
|
1321
|
+
}
|
|
1322
|
+
if (token.tokens?.some((child) => child.type === 'image')) {
|
|
1323
|
+
result.push({ _type: 'raw', _key: key(), markdown: token.raw });
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
if (containsUnsupportedInlineHtml(token.tokens)) {
|
|
1327
|
+
result.push({ _type: 'raw', _key: key(), markdown: token.raw });
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1330
|
+
const displayMath = token.raw.trim().match(/^\$\$\s*([\s\S]*?)\s*\$\$$/);
|
|
1331
|
+
if (displayMath && enabled(options, 'math')) {
|
|
1332
|
+
result.push({
|
|
1333
|
+
_type: 'math',
|
|
1334
|
+
_key: key(),
|
|
1335
|
+
code: displayMath[1] ?? '',
|
|
1336
|
+
inline: false,
|
|
1337
|
+
markdown: token.raw,
|
|
1338
|
+
});
|
|
1339
|
+
continue;
|
|
1340
|
+
}
|
|
1341
|
+
result.push(textBlock('normal', token.tokens, token.text ?? '', inlineMath));
|
|
1342
|
+
continue;
|
|
1343
|
+
}
|
|
1344
|
+
if (token.type === 'blockquote') {
|
|
1345
|
+
result.push(textBlock('blockquote', paragraphTokens(token.tokens), token.text ?? '', inlineMath));
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1348
|
+
if (token.type === 'list') {
|
|
1349
|
+
result.push(...markdownList(token, options));
|
|
1350
|
+
continue;
|
|
1351
|
+
}
|
|
1352
|
+
if (token.type === 'table') {
|
|
1353
|
+
if (enabled(options, 'table')) {
|
|
1354
|
+
const rows = [token.header ?? [], ...(token.rows ?? [])];
|
|
1355
|
+
const table = tableBlock(rows, token.raw, options);
|
|
1356
|
+
if (table) {
|
|
1357
|
+
result.push(table);
|
|
1358
|
+
continue;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
result.push({ _type: 'raw', _key: key(), markdown: token.raw });
|
|
1362
|
+
continue;
|
|
1363
|
+
}
|
|
1364
|
+
if (token.type === 'html') {
|
|
1365
|
+
const table = enabled(options, 'table')
|
|
1366
|
+
? htmlTableBlock(token.raw, options, blocks)
|
|
1367
|
+
: undefined;
|
|
1368
|
+
if (table)
|
|
1369
|
+
result.push(table);
|
|
1370
|
+
else
|
|
1371
|
+
result.push({ _type: 'raw', _key: key(), markdown: token.raw });
|
|
1372
|
+
continue;
|
|
1373
|
+
}
|
|
1374
|
+
if (token.type === 'code') {
|
|
1375
|
+
if (enabled(options, 'code'))
|
|
1376
|
+
result.push({
|
|
1377
|
+
_type: 'code',
|
|
1378
|
+
_key: key(),
|
|
1379
|
+
language: token.lang ?? '',
|
|
1380
|
+
value: token.text ?? '',
|
|
1381
|
+
});
|
|
1382
|
+
else
|
|
1383
|
+
result.push({ _type: 'raw', _key: key(), markdown: token.raw });
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
result.push({ _type: 'raw', _key: key(), markdown: token.raw });
|
|
1387
|
+
}
|
|
1388
|
+
return result;
|
|
1389
|
+
}
|
|
1390
|
+
function onlyOwnFields(value, fields) {
|
|
1391
|
+
return Object.keys(value).every((name) => fields.includes(name));
|
|
1392
|
+
}
|
|
1393
|
+
function markdownInlineBlock(block) {
|
|
1394
|
+
if (!onlyOwnFields(block, ['_type', '_key', 'style', 'listItem', 'level', 'markDefs', 'children']))
|
|
1395
|
+
return false;
|
|
1396
|
+
const style = String(block.style ?? 'normal');
|
|
1397
|
+
if (!['normal', 'blockquote', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(style))
|
|
1398
|
+
return false;
|
|
1399
|
+
if (block.listItem !== undefined && block.listItem !== 'bullet' && block.listItem !== 'number')
|
|
1400
|
+
return false;
|
|
1401
|
+
if (block.level !== undefined && (!Number.isInteger(block.level) || Number(block.level) < 1))
|
|
1402
|
+
return false;
|
|
1403
|
+
const definitions = Array.isArray(block.markDefs) ? block.markDefs : [];
|
|
1404
|
+
const links = new Set();
|
|
1405
|
+
for (const definition of definitions) {
|
|
1406
|
+
if (!definition || typeof definition !== 'object')
|
|
1407
|
+
return false;
|
|
1408
|
+
const mark = definition;
|
|
1409
|
+
if (!onlyOwnFields(mark, ['_type', '_key', 'href']) ||
|
|
1410
|
+
mark._type !== 'link' ||
|
|
1411
|
+
typeof mark._key !== 'string' ||
|
|
1412
|
+
typeof mark.href !== 'string')
|
|
1413
|
+
return false;
|
|
1414
|
+
links.add(mark._key);
|
|
1415
|
+
}
|
|
1416
|
+
const children = Array.isArray(block.children) ? block.children : [];
|
|
1417
|
+
return children.every((child) => {
|
|
1418
|
+
if (!child || typeof child !== 'object')
|
|
1419
|
+
return false;
|
|
1420
|
+
const value = child;
|
|
1421
|
+
if (value._type === 'span') {
|
|
1422
|
+
return (onlyOwnFields(value, ['_type', '_key', 'text', 'marks']) &&
|
|
1423
|
+
typeof value.text === 'string' &&
|
|
1424
|
+
Array.isArray(value.marks) &&
|
|
1425
|
+
value.marks.every((mark) => typeof mark === 'string' &&
|
|
1426
|
+
(['strong', 'em', 'strike-through', 'underline', 'code'].includes(mark) ||
|
|
1427
|
+
links.has(mark))));
|
|
1428
|
+
}
|
|
1429
|
+
return (value._type === 'math' &&
|
|
1430
|
+
onlyOwnFields(value, ['_type', '_key', 'code', 'inline']) &&
|
|
1431
|
+
typeof value.code === 'string' &&
|
|
1432
|
+
!/[$\r\n]/.test(value.code) &&
|
|
1433
|
+
value.inline === true);
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
function blockContentToMarkdown(block) {
|
|
1437
|
+
const markDefs = new Map((Array.isArray(block.markDefs) ? block.markDefs : [])
|
|
1438
|
+
.filter((mark) => typeof mark === 'object' && mark !== null && '_key' in mark && 'href' in mark)
|
|
1439
|
+
.map((mark) => [mark._key, mark.href]));
|
|
1440
|
+
const children = Array.isArray(block.children)
|
|
1441
|
+
? block.children
|
|
1442
|
+
: [];
|
|
1443
|
+
const readable = children
|
|
1444
|
+
.map((child) => {
|
|
1445
|
+
if (child._type === 'math')
|
|
1446
|
+
return '$' + String(child.code ?? '') + '$';
|
|
1447
|
+
const marks = child.marks ?? [];
|
|
1448
|
+
let text = marks.includes('code')
|
|
1449
|
+
? markdownCodeSpan(child.text ?? '')
|
|
1450
|
+
: escapeMarkdownText(child.text ?? '');
|
|
1451
|
+
for (const mark of marks) {
|
|
1452
|
+
if (mark === 'strong')
|
|
1453
|
+
text = '**' + text + '**';
|
|
1454
|
+
else if (mark === 'em')
|
|
1455
|
+
text = '*' + text + '*';
|
|
1456
|
+
else if (mark === 'strike-through')
|
|
1457
|
+
text = '~~' + text + '~~';
|
|
1458
|
+
else if (mark === 'underline')
|
|
1459
|
+
text = '<u>' + text + '</u>';
|
|
1460
|
+
else if (mark !== 'code' && markDefs.has(mark))
|
|
1461
|
+
text = '[' + text + '](' + markdownDestination(markDefs.get(mark) ?? '') + ')';
|
|
1462
|
+
}
|
|
1463
|
+
return text;
|
|
1464
|
+
})
|
|
1465
|
+
.join('');
|
|
1466
|
+
if (children.every((child) => child._type === 'span' && !child.marks?.length))
|
|
1467
|
+
return readable;
|
|
1468
|
+
if (inlineMarkdownRoundTrips(children, readable, markDefs))
|
|
1469
|
+
return readable;
|
|
1470
|
+
const preserved = children
|
|
1471
|
+
.map((child) => {
|
|
1472
|
+
if (child._type === 'math')
|
|
1473
|
+
return '$' + String(child.code ?? '') + '$';
|
|
1474
|
+
const marks = child.marks ?? [];
|
|
1475
|
+
let text = marks.includes('code')
|
|
1476
|
+
? '<code>' + htmlCodeText(child.text ?? '') + '</code>'
|
|
1477
|
+
: escapeMarkdownText(child.text ?? '');
|
|
1478
|
+
for (const mark of marks) {
|
|
1479
|
+
if (mark === 'strong')
|
|
1480
|
+
text = '<strong>' + text + '</strong>';
|
|
1481
|
+
else if (mark === 'em')
|
|
1482
|
+
text = '<em>' + text + '</em>';
|
|
1483
|
+
else if (mark === 'strike-through')
|
|
1484
|
+
text = '<s>' + text + '</s>';
|
|
1485
|
+
else if (mark === 'underline')
|
|
1486
|
+
text = '<u>' + text + '</u>';
|
|
1487
|
+
else if (mark !== 'code' && markDefs.has(mark))
|
|
1488
|
+
text = '[' + text + '](' + markdownDestination(markDefs.get(mark) ?? '') + ')';
|
|
1489
|
+
}
|
|
1490
|
+
return text;
|
|
1491
|
+
})
|
|
1492
|
+
.join('');
|
|
1493
|
+
if (!inlineMarkdownRoundTrips(children, preserved, markDefs))
|
|
1494
|
+
throw new Error('Portable Text inline marks cannot be represented without changing their structure.');
|
|
1495
|
+
return preserved;
|
|
1496
|
+
}
|
|
1497
|
+
function inlineMarkdownRoundTrips(children, markdown, sourceMarkDefs) {
|
|
1498
|
+
if (markdown.length === 0 &&
|
|
1499
|
+
children.length === 1 &&
|
|
1500
|
+
children[0]?._type === 'span' &&
|
|
1501
|
+
children[0].text === '' &&
|
|
1502
|
+
!children[0].marks?.length)
|
|
1503
|
+
return true;
|
|
1504
|
+
const sentinel = 'CodexInlineSentinel';
|
|
1505
|
+
const parsedBlocks = markdownToDocsValue(sentinel + markdown);
|
|
1506
|
+
if (parsedBlocks.length !== 1 || !('children' in parsedBlocks[0]))
|
|
1507
|
+
return false;
|
|
1508
|
+
const parsedBlock = parsedBlocks[0];
|
|
1509
|
+
const parsed = Array.isArray(parsedBlock.children)
|
|
1510
|
+
? parsedBlock.children
|
|
1511
|
+
: [];
|
|
1512
|
+
const sentinelIndex = parsed.findIndex((child) => child._type === 'span' && child.text?.startsWith(sentinel) && !child.marks?.length);
|
|
1513
|
+
if (sentinelIndex < 0)
|
|
1514
|
+
return false;
|
|
1515
|
+
const sentinelChild = parsed[sentinelIndex];
|
|
1516
|
+
const remainingText = String(sentinelChild.text ?? '').slice(sentinel.length);
|
|
1517
|
+
if (remainingText)
|
|
1518
|
+
sentinelChild.text = remainingText;
|
|
1519
|
+
else
|
|
1520
|
+
parsed.splice(sentinelIndex, 1);
|
|
1521
|
+
const parsedLinks = new Map((Array.isArray(parsedBlock.markDefs) ? parsedBlock.markDefs : [])
|
|
1522
|
+
.filter((mark) => typeof mark === 'object' && mark !== null && '_key' in mark && 'href' in mark)
|
|
1523
|
+
.map((mark) => [mark._key, mark.href]));
|
|
1524
|
+
const signature = (values, definitions) => {
|
|
1525
|
+
const result = [];
|
|
1526
|
+
for (const value of values) {
|
|
1527
|
+
if (value._type === 'math') {
|
|
1528
|
+
result.push({ math: String(value.code ?? ''), inline: true });
|
|
1529
|
+
continue;
|
|
1530
|
+
}
|
|
1531
|
+
if (value._type !== 'span')
|
|
1532
|
+
return undefined;
|
|
1533
|
+
const marks = (value.marks ?? [])
|
|
1534
|
+
.map((mark) => (definitions.has(mark) ? 'link:' + definitions.get(mark) : mark))
|
|
1535
|
+
.sort();
|
|
1536
|
+
const valueText = String(value.text ?? '');
|
|
1537
|
+
const pieces = marks.includes('code')
|
|
1538
|
+
? [valueText]
|
|
1539
|
+
: valueText.split(/(\$[^$\n]+\$)/g).filter(Boolean);
|
|
1540
|
+
for (const piece of pieces) {
|
|
1541
|
+
if (/^\$[^$\n]+\$$/.test(piece)) {
|
|
1542
|
+
result.push({ math: piece.slice(1, -1), inline: true });
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1545
|
+
const previous = result.at(-1);
|
|
1546
|
+
if (previous &&
|
|
1547
|
+
'text' in previous &&
|
|
1548
|
+
JSON.stringify(previous.marks) === JSON.stringify(marks))
|
|
1549
|
+
previous.text += piece;
|
|
1550
|
+
else
|
|
1551
|
+
result.push({ text: piece, marks });
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
return JSON.stringify(result);
|
|
1555
|
+
};
|
|
1556
|
+
return signature(children, sourceMarkDefs) === signature(parsed, parsedLinks);
|
|
1557
|
+
}
|
|
1558
|
+
function tableCellMarkdown(cell) {
|
|
1559
|
+
if (!cell || typeof cell !== 'object')
|
|
1560
|
+
return '';
|
|
1561
|
+
const value = cell;
|
|
1562
|
+
if (typeof value.markdown === 'string' && value.markdown)
|
|
1563
|
+
return value.markdown;
|
|
1564
|
+
if (!Array.isArray(value.content))
|
|
1565
|
+
return '';
|
|
1566
|
+
return value.content
|
|
1567
|
+
.map((block) => {
|
|
1568
|
+
if (emptyPortableTextParagraph(block))
|
|
1569
|
+
return '';
|
|
1570
|
+
return escapeTableAutolinks(docsValueToMarkdown([block])
|
|
1571
|
+
.replace(/(?:\r?\n)+$/, '')
|
|
1572
|
+
.replace(/\r?\n/g, '<br>'));
|
|
1573
|
+
})
|
|
1574
|
+
.join('<br data-docs-paragraph-break>');
|
|
1575
|
+
}
|
|
1576
|
+
function tableCellDocumentMarkdown(cell) {
|
|
1577
|
+
if (!cell || typeof cell !== 'object')
|
|
1578
|
+
return '';
|
|
1579
|
+
const value = cell;
|
|
1580
|
+
if (Array.isArray(value.content))
|
|
1581
|
+
return docsValueToMarkdown(value.content).trimEnd();
|
|
1582
|
+
return typeof value.markdown === 'string' ? value.markdown.trimEnd() : '';
|
|
1583
|
+
}
|
|
1584
|
+
/**
|
|
1585
|
+
* GFM turns bare email addresses and URLs into link marks. In a Docs table cell,
|
|
1586
|
+
* that is a data change when the original Portable Text was plain text. Encode
|
|
1587
|
+
* only the punctuation that starts an automatic link; HTML entities display
|
|
1588
|
+
* identically and keep the text unlinked on the next Markdown parse. Explicit
|
|
1589
|
+
* Markdown links and code spans retain their original destinations and marks.
|
|
1590
|
+
*/
|
|
1591
|
+
function escapeTableAutolinks(markdown) {
|
|
1592
|
+
const protectedParts = [];
|
|
1593
|
+
const protect = (source) => {
|
|
1594
|
+
protectedParts.push(source);
|
|
1595
|
+
return `DOCSTABLEPROTECTED${protectedParts.length - 1}TOKEN`;
|
|
1596
|
+
};
|
|
1597
|
+
const protectedMarkdown = markdown
|
|
1598
|
+
.replace(/\[[^\]]*\]\((?:<[^>]*>|[^)]*)\)/g, protect)
|
|
1599
|
+
.replace(/(`+)[\s\S]*?\1/g, protect);
|
|
1600
|
+
const escaped = protectedMarkdown
|
|
1601
|
+
.replace(/\b((?:https?|ftp)):\/\//gi, '$1://')
|
|
1602
|
+
.replace(/\b(www)\./gi, '$1.')
|
|
1603
|
+
.replace(/\b([A-Z0-9._%+-]+)@([A-Z0-9.-]+\.[A-Z]{2,})\b/gi, '$1@$2');
|
|
1604
|
+
return escaped.replace(/DOCSTABLEPROTECTED(\d+)TOKEN/g, (_match, index) => protectedParts[Number(index)] ?? _match);
|
|
1605
|
+
}
|
|
1606
|
+
function tableToMarkdown(block) {
|
|
1607
|
+
const rows = Array.isArray(block.rows) ? block.rows : [];
|
|
1608
|
+
const fallback = richBlockDirective(block);
|
|
1609
|
+
if (!rows.length)
|
|
1610
|
+
return fallback;
|
|
1611
|
+
const columnCounts = rows.map((row) => (Array.isArray(row.cells) ? row.cells.length : 0));
|
|
1612
|
+
const rectangular = columnCounts.every((count) => count === columnCounts[0]);
|
|
1613
|
+
const simpleRows = rectangular &&
|
|
1614
|
+
rows.every((row) => {
|
|
1615
|
+
if (row._type !== 'row' || !onlyOwnFields(row, ['_type', '_key', 'cells']))
|
|
1616
|
+
return false;
|
|
1617
|
+
return (Array.isArray(row.cells) &&
|
|
1618
|
+
row.cells.every((cell) => {
|
|
1619
|
+
if (!cell || typeof cell !== 'object')
|
|
1620
|
+
return false;
|
|
1621
|
+
const value = cell;
|
|
1622
|
+
if (!onlyOwnFields(value, ['_type', '_key', 'content', 'markdown']) ||
|
|
1623
|
+
value._type !== 'cell')
|
|
1624
|
+
return false;
|
|
1625
|
+
if (typeof value.markdown === 'string' && value.markdown)
|
|
1626
|
+
return !value.markdown.includes('\n');
|
|
1627
|
+
if (!Array.isArray(value.content))
|
|
1628
|
+
return false;
|
|
1629
|
+
return value.content.every((content) => {
|
|
1630
|
+
if (!content || typeof content !== 'object')
|
|
1631
|
+
return false;
|
|
1632
|
+
const paragraph = content;
|
|
1633
|
+
const representable = (paragraph._type === 'docImage' &&
|
|
1634
|
+
onlyOwnFields(paragraph, [
|
|
1635
|
+
'_type',
|
|
1636
|
+
'_key',
|
|
1637
|
+
'alt',
|
|
1638
|
+
'url',
|
|
1639
|
+
'title',
|
|
1640
|
+
'markdown',
|
|
1641
|
+
]) &&
|
|
1642
|
+
typeof paragraph.url === 'string') ||
|
|
1643
|
+
((paragraph._type === 'block' || paragraph._type === 'terraBlock') &&
|
|
1644
|
+
markdownInlineBlock(paragraph) &&
|
|
1645
|
+
!paragraph.listItem &&
|
|
1646
|
+
(paragraph.style === undefined || paragraph.style === 'normal'));
|
|
1647
|
+
if (!representable)
|
|
1648
|
+
return false;
|
|
1649
|
+
try {
|
|
1650
|
+
if (paragraph._type !== 'docImage')
|
|
1651
|
+
blockContentToMarkdown(paragraph);
|
|
1652
|
+
return true;
|
|
1653
|
+
}
|
|
1654
|
+
catch {
|
|
1655
|
+
return false;
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
}));
|
|
1659
|
+
});
|
|
1660
|
+
if (!onlyOwnFields(block, ['_type', '_key', 'header', 'rows', 'markdown']) || !simpleRows)
|
|
1661
|
+
return markdownTableDirective(block, rows);
|
|
1662
|
+
const cells = rows.map((row) => (Array.isArray(row.cells) ? row.cells : []).map((cell) => tableCellMarkdown(cell).replace(/\|/g, '\\|').replace(/\n/g, '<br>')));
|
|
1663
|
+
const width = Math.max(1, ...cells.map((row) => row.length));
|
|
1664
|
+
const padded = cells.map((row) => Array.from({ length: width }, (_cell, i) => row[i] ?? ''));
|
|
1665
|
+
const header = padded[0] ?? Array.from({ length: width }, () => '');
|
|
1666
|
+
const separator = Array.from({ length: width }, () => '---');
|
|
1667
|
+
const markdown = [
|
|
1668
|
+
'| ' + header.join(' | ') + ' |',
|
|
1669
|
+
'| ' + separator.join(' | ') + ' |',
|
|
1670
|
+
...padded.slice(1).map((row) => '| ' + row.join(' | ') + ' |'),
|
|
1671
|
+
].join('\n');
|
|
1672
|
+
const caption = String(block.header ?? 'Table');
|
|
1673
|
+
return caption !== 'Table'
|
|
1674
|
+
? ':::terra-docs table[' + encodeURIComponent(caption) + ']\n' + markdown + '\n:::'
|
|
1675
|
+
: markdown;
|
|
1676
|
+
}
|
|
1677
|
+
function markdownTableDirective(block, rows) {
|
|
1678
|
+
const source = block;
|
|
1679
|
+
const tableFields = Object.fromEntries(Object.entries(source).filter(([name]) => !['_type', '_key', 'rows', 'markdown'].includes(name)));
|
|
1680
|
+
const markdownRows = rows.map((row) => {
|
|
1681
|
+
const rowFields = Object.fromEntries(Object.entries(row).filter(([name]) => !['_type', '_key', 'cells'].includes(name)));
|
|
1682
|
+
const cells = Array.isArray(row.cells) ? row.cells : [];
|
|
1683
|
+
return {
|
|
1684
|
+
...rowFields,
|
|
1685
|
+
cells: cells.map((cell) => {
|
|
1686
|
+
if (!cell || typeof cell !== 'object')
|
|
1687
|
+
return cell;
|
|
1688
|
+
const value = cell;
|
|
1689
|
+
const cellFields = Object.fromEntries(Object.entries(value).filter(([name]) => !['_type', '_key', 'content', 'markdown'].includes(name)));
|
|
1690
|
+
return { ...cellFields, markdown: tableCellDocumentMarkdown(value) };
|
|
1691
|
+
}),
|
|
1692
|
+
};
|
|
1693
|
+
});
|
|
1694
|
+
return richBlockDirective({
|
|
1695
|
+
_type: 'table',
|
|
1696
|
+
...tableFields,
|
|
1697
|
+
_docsCellFormat: 'markdown-v1',
|
|
1698
|
+
rows: markdownRows,
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
function isListBlock(block) {
|
|
1702
|
+
return ((block._type === 'block' || block._type === 'terraBlock') &&
|
|
1703
|
+
(block.listItem === 'bullet' || block.listItem === 'number') &&
|
|
1704
|
+
(block.style === undefined || block.style === 'normal') &&
|
|
1705
|
+
markdownInlineBlock(block));
|
|
1706
|
+
}
|
|
1707
|
+
function listToMarkdown(blocks, start) {
|
|
1708
|
+
const lines = [];
|
|
1709
|
+
const ordinals = new Map();
|
|
1710
|
+
let index = start;
|
|
1711
|
+
while (index < blocks.length && isListBlock(blocks[index])) {
|
|
1712
|
+
const block = blocks[index];
|
|
1713
|
+
const level = Math.max(1, Number(block.level) || 1);
|
|
1714
|
+
for (const nestedLevel of ordinals.keys())
|
|
1715
|
+
if (nestedLevel > level)
|
|
1716
|
+
ordinals.delete(nestedLevel);
|
|
1717
|
+
const kind = String(block.listItem);
|
|
1718
|
+
const previous = ordinals.get(level);
|
|
1719
|
+
const ordinal = previous?.kind === kind ? previous.count + 1 : 1;
|
|
1720
|
+
ordinals.set(level, { kind, count: ordinal });
|
|
1721
|
+
const marker = kind === 'number' ? ordinal + '.' : '-';
|
|
1722
|
+
// A nested list must be indented far enough to clear the parent marker. Two spaces
|
|
1723
|
+
// are not enough after an ordered marker (`1. `) in CommonMark and flatten the item.
|
|
1724
|
+
const indentation = ' '.repeat(level - 1);
|
|
1725
|
+
const continuationIndentation = indentation + ' '.repeat(marker.length + 1);
|
|
1726
|
+
const content = blockContentToMarkdown(block).replace(/\n/g, '\n' + continuationIndentation);
|
|
1727
|
+
lines.push(indentation + marker + ' ' + content);
|
|
1728
|
+
index += 1;
|
|
1729
|
+
}
|
|
1730
|
+
return { markdown: lines.join('\n'), next: index };
|
|
1731
|
+
}
|
|
1732
|
+
function nestedMarkdown(block) {
|
|
1733
|
+
// Component parsing replaces JSX blocks with placeholders before parsing nested
|
|
1734
|
+
// containers such as callouts and tabs. That transformed source is useful while
|
|
1735
|
+
// parsing, but cannot be written back to Markdown: the placeholder has meaning
|
|
1736
|
+
// only in the temporary parser registry. Rebuild that nested source from its
|
|
1737
|
+
// structured content so code, diagrams, images, and other rich blocks survive.
|
|
1738
|
+
if (typeof block.markdown === 'string' &&
|
|
1739
|
+
block.markdown &&
|
|
1740
|
+
!/TERRADOCSBLOCK\d+PLACEHOLDER/.test(block.markdown))
|
|
1741
|
+
return block.markdown;
|
|
1742
|
+
return Array.isArray(block.content)
|
|
1743
|
+
? docsValueToMarkdown(block.content).trimEnd()
|
|
1744
|
+
: '';
|
|
1745
|
+
}
|
|
1746
|
+
function emptyPortableTextParagraph(value) {
|
|
1747
|
+
if (!value || typeof value !== 'object')
|
|
1748
|
+
return false;
|
|
1749
|
+
const block = value;
|
|
1750
|
+
if (block._type !== 'block' && block._type !== 'terraBlock')
|
|
1751
|
+
return false;
|
|
1752
|
+
if (Object.keys(block).some((name) => !['_type', '_key', 'style', 'markDefs', 'children'].includes(name)))
|
|
1753
|
+
return false;
|
|
1754
|
+
if (block.listItem || (block.style !== undefined && block.style !== 'normal'))
|
|
1755
|
+
return false;
|
|
1756
|
+
if (Array.isArray(block.markDefs) && block.markDefs.length > 0)
|
|
1757
|
+
return false;
|
|
1758
|
+
if (!Array.isArray(block.children))
|
|
1759
|
+
return false;
|
|
1760
|
+
return block.children.every((child) => {
|
|
1761
|
+
if (!child || typeof child !== 'object')
|
|
1762
|
+
return false;
|
|
1763
|
+
const span = child;
|
|
1764
|
+
return (span._type === 'span' &&
|
|
1765
|
+
String(span.text ?? '').trim() === '' &&
|
|
1766
|
+
(!Array.isArray(span.marks) || span.marks.length === 0) &&
|
|
1767
|
+
Object.keys(span).every((name) => ['_type', '_key', 'text', 'marks'].includes(name)));
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
function semanticMarkdownValue(value) {
|
|
1771
|
+
if (Array.isArray(value))
|
|
1772
|
+
return value.filter((item) => !emptyPortableTextParagraph(item)).map(semanticMarkdownValue);
|
|
1773
|
+
if (!value || typeof value !== 'object')
|
|
1774
|
+
return value;
|
|
1775
|
+
const block = value;
|
|
1776
|
+
const type = block._type;
|
|
1777
|
+
if (type === 'block' || type === 'terraBlock') {
|
|
1778
|
+
const definitions = new Map((Array.isArray(block.markDefs) ? block.markDefs : [])
|
|
1779
|
+
.filter((item) => Boolean(item) && typeof item === 'object')
|
|
1780
|
+
.map((item) => [String(item._key ?? ''), semanticMarkdownValue(item)]));
|
|
1781
|
+
const children = [];
|
|
1782
|
+
for (const child of Array.isArray(block.children) ? block.children : []) {
|
|
1783
|
+
if (!child || typeof child !== 'object') {
|
|
1784
|
+
children.push(semanticMarkdownValue(child));
|
|
1785
|
+
continue;
|
|
1786
|
+
}
|
|
1787
|
+
const item = child;
|
|
1788
|
+
if (item._type !== 'span') {
|
|
1789
|
+
children.push(semanticMarkdownValue(item));
|
|
1790
|
+
continue;
|
|
1791
|
+
}
|
|
1792
|
+
const marks = (Array.isArray(item.marks) ? item.marks : [])
|
|
1793
|
+
.map((mark) => definitions.get(String(mark)) ?? mark)
|
|
1794
|
+
.map((mark) => JSON.stringify(mark))
|
|
1795
|
+
.sort();
|
|
1796
|
+
const pieces = String(item.text ?? '')
|
|
1797
|
+
.split(/(\$[^$\n]+\$)/g)
|
|
1798
|
+
.filter(Boolean);
|
|
1799
|
+
for (const piece of pieces) {
|
|
1800
|
+
if (/^\$[^$\n]+\$$/.test(piece)) {
|
|
1801
|
+
children.push({ _type: 'math', code: piece.slice(1, -1), inline: true });
|
|
1802
|
+
continue;
|
|
1803
|
+
}
|
|
1804
|
+
const previous = children.at(-1);
|
|
1805
|
+
if (previous?._type === 'span' && JSON.stringify(previous.marks) === JSON.stringify(marks))
|
|
1806
|
+
previous.text = String(previous.text ?? '') + piece;
|
|
1807
|
+
else
|
|
1808
|
+
children.push({ _type: 'span', text: piece, marks });
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
const extra = Object.fromEntries(Object.entries(block)
|
|
1812
|
+
.filter(([name]) => ![
|
|
1813
|
+
'_type',
|
|
1814
|
+
'_key',
|
|
1815
|
+
'_rev',
|
|
1816
|
+
'_createdAt',
|
|
1817
|
+
'_updatedAt',
|
|
1818
|
+
'_system',
|
|
1819
|
+
'style',
|
|
1820
|
+
'listItem',
|
|
1821
|
+
'level',
|
|
1822
|
+
'markDefs',
|
|
1823
|
+
'children',
|
|
1824
|
+
].includes(name))
|
|
1825
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
1826
|
+
.map(([name, item]) => [name, semanticMarkdownValue(item)]));
|
|
1827
|
+
const markDefs = [...definitions.values()].map((item) => JSON.stringify(item)).sort();
|
|
1828
|
+
return {
|
|
1829
|
+
...extra,
|
|
1830
|
+
_type: 'textBlock',
|
|
1831
|
+
style: block.style ?? 'normal',
|
|
1832
|
+
listItem: block.listItem ?? null,
|
|
1833
|
+
level: block.level ?? null,
|
|
1834
|
+
markDefs,
|
|
1835
|
+
children,
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
// Empty, metadata-free Portable Text paragraphs have no visible Markdown
|
|
1839
|
+
// representation. Ignore them in all nested block arrays (including callouts
|
|
1840
|
+
// and table cells), while retaining the original records in the source archive.
|
|
1841
|
+
const semanticBlock = block;
|
|
1842
|
+
const nestedContent = Array.isArray(semanticBlock.content) ? semanticBlock.content : undefined;
|
|
1843
|
+
const extra = Object.fromEntries(Object.entries(semanticBlock)
|
|
1844
|
+
.filter(([name]) => !['_key', '_rev', '_createdAt', '_updatedAt', '_system'].includes(name))
|
|
1845
|
+
.filter(([name]) => !(name === '_type' && type === 'item'))
|
|
1846
|
+
.filter(([name]) => !(name === 'markdown' && nestedContent))
|
|
1847
|
+
// Accordions and tabs can also carry an empty editor cache at the root.
|
|
1848
|
+
// Grouped Markdown reconstructs the item bodies directly, so this cache
|
|
1849
|
+
// is not source content and must not force an otherwise faithful YAML
|
|
1850
|
+
// fallback.
|
|
1851
|
+
.filter(([name]) => !(name === 'markdown' && ['accordion', 'tabs'].includes(String(type))))
|
|
1852
|
+
.filter(([name]) => !(name === 'markdown' && ['math', 'docImage', 'table'].includes(String(type))))
|
|
1853
|
+
.filter(([name]) => !(name === 'markdown' && type === 'code' && ('value' in block || 'source' in block)))
|
|
1854
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
1855
|
+
.map(([name, item]) => [name, semanticMarkdownValue(item)]));
|
|
1856
|
+
return extra;
|
|
1857
|
+
}
|
|
1858
|
+
function markdownPreservesValue(value, markdown) {
|
|
1859
|
+
try {
|
|
1860
|
+
return (JSON.stringify(semanticMarkdownValue([value])) ===
|
|
1861
|
+
JSON.stringify(semanticMarkdownValue(markdownToDocsValue(markdown))));
|
|
1862
|
+
}
|
|
1863
|
+
catch {
|
|
1864
|
+
return false;
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
function richBlockDirective(block) {
|
|
1868
|
+
const type = String(block._type ?? '');
|
|
1869
|
+
if (!/^[A-Za-z][A-Za-z0-9]*$/.test(type))
|
|
1870
|
+
throw new Error('Cannot serialize Docs block with an invalid type.');
|
|
1871
|
+
// Remove only YAML's document-ending newline. Additional final newlines can
|
|
1872
|
+
// be meaningful content in block scalars (especially code values with a
|
|
1873
|
+
// `|+` chomping indicator), so trimming them would silently alter the block.
|
|
1874
|
+
const payload = stringifyYaml(block, { lineWidth: 0 }).replace(/\r?\n$/, '');
|
|
1875
|
+
const nestedFences = [...payload.matchAll(/^(:{3,})(?:[ \t].*)?$/gm)].map((match) => match[1].length);
|
|
1876
|
+
const fence = ':'.repeat(Math.max(3, 1 + Math.max(0, ...nestedFences)));
|
|
1877
|
+
return fence + 'terra-docs ' + type + '\n' + payload + '\n' + fence;
|
|
1878
|
+
}
|
|
1879
|
+
function colonFence(contents, minimum = 4) {
|
|
1880
|
+
const largest = contents.flatMap((content) => [...content.matchAll(/^(:+)(?:[ \t].*)?$/gm)].map((match) => match[1].length));
|
|
1881
|
+
return ':'.repeat(Math.max(minimum, 1 + Math.max(0, ...largest)));
|
|
1882
|
+
}
|
|
1883
|
+
function codeFence(code, language) {
|
|
1884
|
+
const tick = String.fromCharCode(96);
|
|
1885
|
+
const runs = code.match(new RegExp(tick + '+', 'g')) ?? [];
|
|
1886
|
+
const fence = tick.repeat(Math.max(3, 1 + Math.max(0, ...runs.map((run) => run.length))));
|
|
1887
|
+
const suffix = language ? language : '';
|
|
1888
|
+
return fence + suffix + '\n' + code.replace(/\n+$/, '') + '\n' + fence;
|
|
1889
|
+
}
|
|
1890
|
+
/** Serialize readable Markdown where it is faithful and typed source where it is not. */
|
|
1891
|
+
export function docsValueToMarkdown(value) {
|
|
1892
|
+
const blocks = value;
|
|
1893
|
+
const result = [];
|
|
1894
|
+
for (let index = 0; index < blocks.length;) {
|
|
1895
|
+
const item = blocks[index];
|
|
1896
|
+
if (isListBlock(item)) {
|
|
1897
|
+
const list = listToMarkdown(blocks, index);
|
|
1898
|
+
result.push(list.markdown);
|
|
1899
|
+
index = list.next;
|
|
1900
|
+
continue;
|
|
1901
|
+
}
|
|
1902
|
+
index += 1;
|
|
1903
|
+
if (item._type === 'block' || item._type === 'terraBlock') {
|
|
1904
|
+
if (!markdownInlineBlock(item) || item.listItem !== undefined) {
|
|
1905
|
+
result.push(richBlockDirective(item));
|
|
1906
|
+
continue;
|
|
1907
|
+
}
|
|
1908
|
+
const content = blockContentToMarkdown(item);
|
|
1909
|
+
const style = String(item.style ?? 'normal');
|
|
1910
|
+
if (/^h[2-6]$/.test(style))
|
|
1911
|
+
result.push('#'.repeat(Number(style[1])) + ' ' + content.replace(/\r?\n/g, '<br>'));
|
|
1912
|
+
else if (style === 'blockquote')
|
|
1913
|
+
result.push('> ' + content);
|
|
1914
|
+
else if (style === 'normal')
|
|
1915
|
+
result.push(content);
|
|
1916
|
+
else
|
|
1917
|
+
result.push(richBlockDirective(item));
|
|
1918
|
+
continue;
|
|
1919
|
+
}
|
|
1920
|
+
const knownFields = {
|
|
1921
|
+
raw: ['markdown'],
|
|
1922
|
+
code: ['markdown', 'language', 'source', 'value'],
|
|
1923
|
+
docImage: ['markdown', 'alt', 'url', 'title', 'width', 'height'],
|
|
1924
|
+
math: ['markdown', 'code', 'inline'],
|
|
1925
|
+
table: ['markdown', 'header', 'rows'],
|
|
1926
|
+
callout: ['markdown', 'kind', 'title', 'content'],
|
|
1927
|
+
accordion: ['markdown', 'items'],
|
|
1928
|
+
tabs: ['markdown', 'items'],
|
|
1929
|
+
};
|
|
1930
|
+
const extra = Object.keys(item).some((name) => !['_type', '_key', ...(knownFields[item._type] ?? [])].includes(name));
|
|
1931
|
+
if (item._type === 'raw' && !extra && typeof item.markdown === 'string') {
|
|
1932
|
+
result.push(markdownPreservesValue(item, item.markdown) ? item.markdown : richBlockDirective(item));
|
|
1933
|
+
continue;
|
|
1934
|
+
}
|
|
1935
|
+
if (item._type === 'code' && !extra) {
|
|
1936
|
+
const language = String(item.language ?? '');
|
|
1937
|
+
if (language && !/^[A-Za-z0-9_+.-]+$/.test(language)) {
|
|
1938
|
+
result.push(richBlockDirective(item));
|
|
1939
|
+
}
|
|
1940
|
+
else if (typeof item.markdown === 'string' &&
|
|
1941
|
+
item.markdown &&
|
|
1942
|
+
item.value === undefined &&
|
|
1943
|
+
item.source === undefined) {
|
|
1944
|
+
result.push(markdownPreservesValue(item, item.markdown) ? item.markdown : richBlockDirective(item));
|
|
1945
|
+
}
|
|
1946
|
+
else {
|
|
1947
|
+
const markdown = codeFence(String(item.value ?? item.source ?? ''), language);
|
|
1948
|
+
result.push(markdownPreservesValue(item, markdown) ? markdown : richBlockDirective(item));
|
|
1949
|
+
}
|
|
1950
|
+
continue;
|
|
1951
|
+
}
|
|
1952
|
+
if (item._type === 'docImage' && !extra) {
|
|
1953
|
+
if (item.width !== undefined || item.height !== undefined) {
|
|
1954
|
+
result.push(richBlockDirective(item));
|
|
1955
|
+
continue;
|
|
1956
|
+
}
|
|
1957
|
+
const alt = String(item.alt ?? '').replace(/\]/g, '\\]');
|
|
1958
|
+
const url = markdownDestination(String(item.url ?? ''));
|
|
1959
|
+
const title = item.title
|
|
1960
|
+
? ' "' + String(item.title).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'
|
|
1961
|
+
: '';
|
|
1962
|
+
const markdown = '';
|
|
1963
|
+
result.push(markdownPreservesValue(item, markdown) ? markdown : richBlockDirective(item));
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
if (item._type === 'math' && !extra && typeof item.code === 'string') {
|
|
1967
|
+
if (String(item.code).includes('$$') || (item.inline === true && /[$\r\n]/.test(item.code))) {
|
|
1968
|
+
result.push(richBlockDirective(item));
|
|
1969
|
+
}
|
|
1970
|
+
else if (item.inline === true) {
|
|
1971
|
+
const markdown = '$' + item.code + '$';
|
|
1972
|
+
result.push(markdownPreservesValue(item, markdown) ? markdown : richBlockDirective(item));
|
|
1973
|
+
}
|
|
1974
|
+
else {
|
|
1975
|
+
const markdown = '$$\n' + item.code + '\n$$';
|
|
1976
|
+
result.push(markdownPreservesValue(item, markdown) ? markdown : richBlockDirective(item));
|
|
1977
|
+
}
|
|
1978
|
+
continue;
|
|
1979
|
+
}
|
|
1980
|
+
if (item._type === 'table') {
|
|
1981
|
+
const markdown = tableToMarkdown(item);
|
|
1982
|
+
result.push(markdownPreservesValue(item, markdown) ? markdown : richBlockDirective(item));
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1985
|
+
if (item._type === 'callout' && !extra) {
|
|
1986
|
+
const kind = String(item.kind ?? 'info');
|
|
1987
|
+
const title = String(item.title ?? kind);
|
|
1988
|
+
const content = nestedMarkdown(item).replace(/\n+$/, '');
|
|
1989
|
+
if (/^[A-Za-z][\w-]*$/.test(kind) && !/[\]\r\n]/.test(title)) {
|
|
1990
|
+
const fence = colonFence([content], 3);
|
|
1991
|
+
const markdown = fence + kind + '[' + title + ']\n' + content + '\n' + fence;
|
|
1992
|
+
result.push(markdownPreservesValue(item, markdown) ? markdown : richBlockDirective(item));
|
|
1993
|
+
}
|
|
1994
|
+
else {
|
|
1995
|
+
result.push(richBlockDirective(item));
|
|
1996
|
+
}
|
|
1997
|
+
continue;
|
|
1998
|
+
}
|
|
1999
|
+
if ((item._type === 'accordion' || item._type === 'tabs') && !extra) {
|
|
2000
|
+
const entries = Array.isArray(item.items) ? item.items : [];
|
|
2001
|
+
const supported = entries.every((entry) => onlyOwnFields(entry, ['_type', '_key', 'title', 'markdown', 'content']) &&
|
|
2002
|
+
(entry._type === undefined || entry._type === 'item') &&
|
|
2003
|
+
(entry.markdown === undefined || typeof entry.markdown === 'string') &&
|
|
2004
|
+
(entry.content === undefined || Array.isArray(entry.content)));
|
|
2005
|
+
if (!supported || !entries.length) {
|
|
2006
|
+
result.push(richBlockDirective(item));
|
|
2007
|
+
continue;
|
|
2008
|
+
}
|
|
2009
|
+
const renderedItems = entries.map((entry) => {
|
|
2010
|
+
const title = typeof entry.title === 'string' ? entry.title : 'Item';
|
|
2011
|
+
const body = nestedMarkdown(entry).replace(/\n+$/, '');
|
|
2012
|
+
return ':::terra-item ' + JSON.stringify(title) + '\n' + body + '\n:::terra-item-end';
|
|
2013
|
+
});
|
|
2014
|
+
// Grouped Markdown supports nested typed blocks. Keep ordinary text,
|
|
2015
|
+
// tables, callouts, code, and other nested content readable instead of
|
|
2016
|
+
// wrapping the entire accordion or tab tree in YAML. Portable Text keys
|
|
2017
|
+
// are editor identity metadata; Markdown round trips intentionally mint
|
|
2018
|
+
// new keys while preserving the document structure and content.
|
|
2019
|
+
const fence = colonFence(renderedItems, 4);
|
|
2020
|
+
const markdown = fence + 'terra-docs ' + item._type + '\n' + renderedItems.join('\n') + '\n' + fence;
|
|
2021
|
+
result.push(markdownPreservesValue(item, markdown) ? markdown : richBlockDirective(item));
|
|
2022
|
+
continue;
|
|
2023
|
+
}
|
|
2024
|
+
result.push(richBlockDirective(item));
|
|
2025
|
+
}
|
|
2026
|
+
return (result
|
|
2027
|
+
.join('\n\n')
|
|
2028
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
2029
|
+
.replace(/(?:\r?\n)+$/, '') + '\n');
|
|
2030
|
+
}
|
|
2031
|
+
//# sourceMappingURL=markdown-model.js.map
|