livemark 0.2.0 → 0.7.0
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/LICENSE.md +9 -0
- package/README.md +5 -1
- package/build/actions/changelog/build.d.ts +14 -0
- package/build/actions/changelog/build.js +158 -0
- package/build/actions/changelog/build.unit.js +66 -0
- package/build/actions/config/define.d.ts +6 -0
- package/build/actions/config/define.js +8 -0
- package/build/actions/config/define.unit.js +29 -0
- package/build/actions/config/load.d.ts +5 -0
- package/build/actions/config/load.js +25 -0
- package/build/actions/config/load.unit.js +23 -0
- package/build/commands/build.d.ts +5 -0
- package/build/commands/build.js +14 -0
- package/build/commands/escape.d.ts +9 -0
- package/build/commands/escape.js +56 -0
- package/build/commands/preview.d.ts +5 -0
- package/build/commands/preview.js +18 -0
- package/build/commands/start.d.ts +5 -0
- package/build/commands/start.js +19 -0
- package/build/docs/markdown/includes/example.d.ts +58 -0
- package/build/docs/markdown/includes/example.js +5 -0
- package/build/entrypoints/main.d.ts +2 -0
- package/build/entrypoints/main.js +12 -0
- package/build/helpers/program.d.ts +2 -0
- package/build/helpers/program.js +5 -0
- package/build/index.d.ts +1 -4
- package/build/index.js +2 -5
- package/build/livemark.config.d.ts +58 -0
- package/build/livemark.config.js +25 -0
- package/build/models/config.d.ts +340 -0
- package/build/models/config.js +34 -0
- package/build/models/link.d.ts +13 -0
- package/build/models/link.js +9 -0
- package/build/models/patch.d.ts +21 -0
- package/build/models/patch.js +7 -0
- package/build/models/section.d.ts +75 -0
- package/build/models/section.js +26 -0
- package/build/models/theme.d.ts +72 -0
- package/build/models/theme.js +73 -0
- package/build/program.d.ts +2 -0
- package/build/program.js +16 -0
- package/build/vite.config.d.ts +2 -0
- package/build/vite.config.js +48 -0
- package/build/website/assets/logo.svg +117 -0
- package/build/website/client.tsx +10 -0
- package/build/website/components/Abbr.tsx +17 -0
- package/build/website/components/AnsiCode.tsx +15 -0
- package/build/website/components/Article.tsx +172 -0
- package/build/website/components/BackToTop.tsx +32 -0
- package/build/website/components/Banner.tsx +32 -0
- package/build/website/components/BlogIndex.tsx +121 -0
- package/build/website/components/BlogSidebar.tsx +162 -0
- package/build/website/components/Breadcrumbs.tsx +22 -0
- package/build/website/components/Callout.tsx +72 -0
- package/build/website/components/Card.tsx +48 -0
- package/build/website/components/Cards.tsx +8 -0
- package/build/website/components/ChangelogIndex.tsx +111 -0
- package/build/website/components/ChangelogSidebar.tsx +120 -0
- package/build/website/components/CodeBlock.tsx +135 -0
- package/build/website/components/CodeTabs.tsx +83 -0
- package/build/website/components/Column.tsx +4 -0
- package/build/website/components/Columns.tsx +12 -0
- package/build/website/components/Content.tsx +7 -0
- package/build/website/components/ContentTab.tsx +7 -0
- package/build/website/components/ContentTabs.tsx +82 -0
- package/build/website/components/DefaultCatchBoundary.tsx +54 -0
- package/build/website/components/DefinitionList.tsx +21 -0
- package/build/website/components/Details.tsx +30 -0
- package/build/website/components/FileTree.tsx +52 -0
- package/build/website/components/Footer.tsx +16 -0
- package/build/website/components/FootnoteRef.tsx +52 -0
- package/build/website/components/Heading.tsx +20 -0
- package/build/website/components/InlineBadge.tsx +9 -0
- package/build/website/components/InlineIcon.tsx +10 -0
- package/build/website/components/InlineToc.tsx +31 -0
- package/build/website/components/Layout.tsx +190 -0
- package/build/website/components/LinkButton.tsx +31 -0
- package/build/website/components/Mermaid.tsx +18 -0
- package/build/website/components/MermaidRenderer.tsx +37 -0
- package/build/website/components/MiniSidebar.tsx +49 -0
- package/build/website/components/NotFound.tsx +27 -0
- package/build/website/components/PackageTabs.tsx +74 -0
- package/build/website/components/PageToolbar.tsx +75 -0
- package/build/website/components/PrevNext.tsx +60 -0
- package/build/website/components/Search.tsx +28 -0
- package/build/website/components/SearchDialog.tsx +245 -0
- package/build/website/components/Section.tsx +24 -0
- package/build/website/components/SectionHeader.tsx +35 -0
- package/build/website/components/Sidebar.tsx +160 -0
- package/build/website/components/SidebarLinks.tsx +70 -0
- package/build/website/components/SidebarSections.tsx +71 -0
- package/build/website/components/SiteTitle.tsx +21 -0
- package/build/website/components/SortableTable.tsx +81 -0
- package/build/website/components/SoundCloud.tsx +16 -0
- package/build/website/components/TagIndex.tsx +120 -0
- package/build/website/components/Theme.tsx +39 -0
- package/build/website/components/Toc.tsx +226 -0
- package/build/website/components/YouTube.tsx +16 -0
- package/build/website/components/ZoomImage.tsx +25 -0
- package/build/website/content/article.ts +78 -0
- package/build/website/content/tag.ts +29 -0
- package/build/website/content-collections.ts +208 -0
- package/build/website/elements/accordion.tsx +78 -0
- package/build/website/elements/alert-dialog.tsx +185 -0
- package/build/website/elements/alert.tsx +74 -0
- package/build/website/elements/aspect-ratio.tsx +22 -0
- package/build/website/elements/avatar.tsx +107 -0
- package/build/website/elements/badge.tsx +51 -0
- package/build/website/elements/breadcrumb.tsx +120 -0
- package/build/website/elements/button-group.tsx +87 -0
- package/build/website/elements/button.tsx +57 -0
- package/build/website/elements/calendar.tsx +229 -0
- package/build/website/elements/card.tsx +102 -0
- package/build/website/elements/carousel.tsx +240 -0
- package/build/website/elements/chart.tsx +372 -0
- package/build/website/elements/checkbox.tsx +26 -0
- package/build/website/elements/collapsible.tsx +19 -0
- package/build/website/elements/command.tsx +210 -0
- package/build/website/elements/context-menu.tsx +270 -0
- package/build/website/elements/dialog.tsx +152 -0
- package/build/website/elements/direction.tsx +4 -0
- package/build/website/elements/drawer.tsx +127 -0
- package/build/website/elements/dropdown-menu.tsx +260 -0
- package/build/website/elements/empty.tsx +104 -0
- package/build/website/elements/field.tsx +235 -0
- package/build/website/elements/hover-card.tsx +49 -0
- package/build/website/elements/input-group.tsx +171 -0
- package/build/website/elements/input-otp.tsx +84 -0
- package/build/website/elements/input.tsx +18 -0
- package/build/website/elements/item.tsx +199 -0
- package/build/website/elements/kbd.tsx +26 -0
- package/build/website/elements/label.tsx +17 -0
- package/build/website/elements/menubar.tsx +282 -0
- package/build/website/elements/native-select.tsx +56 -0
- package/build/website/elements/navigation-menu.tsx +171 -0
- package/build/website/elements/pagination.tsx +133 -0
- package/build/website/elements/popover.tsx +88 -0
- package/build/website/elements/progress.tsx +81 -0
- package/build/website/elements/radio-group.tsx +36 -0
- package/build/website/elements/resizable.tsx +48 -0
- package/build/website/elements/scroll-area.tsx +51 -0
- package/build/website/elements/select.tsx +200 -0
- package/build/website/elements/separator.tsx +22 -0
- package/build/website/elements/sheet.tsx +130 -0
- package/build/website/elements/sidebar.tsx +717 -0
- package/build/website/elements/skeleton.tsx +13 -0
- package/build/website/elements/slider.tsx +57 -0
- package/build/website/elements/sonner.tsx +40 -0
- package/build/website/elements/spinner.tsx +16 -0
- package/build/website/elements/switch.tsx +30 -0
- package/build/website/elements/table.tsx +112 -0
- package/build/website/elements/tabs.tsx +79 -0
- package/build/website/elements/textarea.tsx +16 -0
- package/build/website/elements/toggle-group.tsx +87 -0
- package/build/website/elements/toggle.tsx +43 -0
- package/build/website/elements/tooltip.tsx +67 -0
- package/build/website/env.d.ts +14 -0
- package/build/website/helpers/article-icon.ts +61 -0
- package/build/website/helpers/article.ts +90 -0
- package/build/website/helpers/changelog-source.ts +16 -0
- package/build/website/helpers/changelog-source.unit.ts +38 -0
- package/build/website/helpers/dynamic-icon-resolver.tsx +19 -0
- package/build/website/helpers/dynamic-icon.tsx +12 -0
- package/build/website/helpers/favicon.ts +7 -0
- package/build/website/helpers/model.ts +4 -0
- package/build/website/helpers/resolve-asset-path.ts +9 -0
- package/build/website/helpers/resolve-includes.ts +131 -0
- package/build/website/helpers/resolve-includes.unit.ts +126 -0
- package/build/website/helpers/search-text.ts +15 -0
- package/build/website/helpers/section.ts +50 -0
- package/build/website/helpers/section.unit.ts +71 -0
- package/build/website/helpers/style.ts +6 -0
- package/build/website/helpers/theme.ts +27 -0
- package/build/website/helpers/toc-context.ts +10 -0
- package/build/website/helpers/toc.ts +46 -0
- package/build/website/helpers/toc.unit.ts +74 -0
- package/build/website/hooks/in-view.ts +30 -0
- package/build/website/hooks/media.ts +19 -0
- package/build/website/models/article.ts +55 -0
- package/build/website/models/toc.ts +5 -0
- package/build/website/plugins/rehype-inline-code.ts +107 -0
- package/build/website/plugins/rehype-task-list-a11y.ts +33 -0
- package/build/website/plugins/remark-abbr.ts +46 -0
- package/build/website/plugins/remark-abbr.unit.ts +99 -0
- package/build/website/plugins/remark-ansi.ts +248 -0
- package/build/website/plugins/remark-ansi.unit.ts +197 -0
- package/build/website/plugins/remark-badge.ts +50 -0
- package/build/website/plugins/remark-badge.unit.ts +96 -0
- package/build/website/plugins/remark-button.ts +60 -0
- package/build/website/plugins/remark-button.unit.ts +147 -0
- package/build/website/plugins/remark-callout.ts +57 -0
- package/build/website/plugins/remark-card.ts +80 -0
- package/build/website/plugins/remark-code-tabs.ts +87 -0
- package/build/website/plugins/remark-columns.ts +66 -0
- package/build/website/plugins/remark-custom-heading-id.ts +70 -0
- package/build/website/plugins/remark-custom-heading-id.unit.ts +131 -0
- package/build/website/plugins/remark-deflist.ts +36 -0
- package/build/website/plugins/remark-details.ts +49 -0
- package/build/website/plugins/remark-filetree.ts +89 -0
- package/build/website/plugins/remark-filetree.unit.ts +137 -0
- package/build/website/plugins/remark-github-callout.ts +71 -0
- package/build/website/plugins/remark-icon.ts +42 -0
- package/build/website/plugins/remark-image.ts +34 -0
- package/build/website/plugins/remark-media.ts +62 -0
- package/build/website/plugins/remark-media.unit.ts +74 -0
- package/build/website/plugins/remark-mermaid.ts +23 -0
- package/build/website/plugins/remark-npm.ts +52 -0
- package/build/website/plugins/remark-steps.ts +36 -0
- package/build/website/plugins/remark-steps.unit.ts +97 -0
- package/build/website/plugins/remark-tab.ts +100 -0
- package/build/website/plugins/remark-tab.unit.ts +181 -0
- package/build/website/plugins/remark-toc.ts +39 -0
- package/build/website/plugins/remark-toc.unit.ts +82 -0
- package/build/website/plugins/shiki-icon.ts +82 -0
- package/build/website/plugins/shiki-line-highlight.ts +174 -0
- package/build/website/plugins/vite-livemark.ts +91 -0
- package/build/website/routeTree.gen.ts +86 -0
- package/build/website/router.tsx +34 -0
- package/build/website/routes/$.tsx +92 -0
- package/build/website/routes/__root.tsx +97 -0
- package/build/website/server.ts +7 -0
- package/build/website/styles/general.css +163 -0
- package/build/website/styles/markdown.css +214 -0
- package/build/website/vite.config.ts +71 -0
- package/entrypoints/main.ts +12 -0
- package/package.json +120 -12
- package/build/descriptor/index.d.ts +0 -3
- package/build/descriptor/index.js +0 -4
- package/build/descriptor/load.d.ts +0 -8
- package/build/descriptor/load.js +0 -40
- package/build/descriptor/node.d.ts +0 -125
- package/build/descriptor/node.js +0 -9
- package/build/descriptor/save.d.ts +0 -8
- package/build/descriptor/save.js +0 -17
- package/build/descriptor/save.spec.js +0 -80
- package/build/descriptor/validate.d.ts +0 -9
- package/build/descriptor/validate.js +0 -14
- package/build/descriptor/validate.spec.js +0 -124
- package/build/dialect/Dialect.d.ts +0 -88
- package/build/dialect/Dialect.js +0 -2
- package/build/dialect/index.d.ts +0 -3
- package/build/dialect/index.js +0 -3
- package/build/dialect/load.d.ts +0 -4
- package/build/dialect/load.js +0 -7
- package/build/dialect/save.d.ts +0 -9
- package/build/dialect/save.js +0 -13
- package/build/dialect/validate.d.ts +0 -1
- package/build/dialect/validate.js +0 -4
- package/build/metadata/index.d.ts +0 -3
- package/build/metadata/index.js +0 -4
- package/build/metadata/load.d.ts +0 -10
- package/build/metadata/load.js +0 -55
- package/build/metadata/node.d.ts +0 -125
- package/build/metadata/node.js +0 -9
- package/build/metadata/save.d.ts +0 -8
- package/build/metadata/save.js +0 -17
- package/build/metadata/save.spec.js +0 -80
- package/build/metadata/validate.d.ts +0 -9
- package/build/metadata/validate.js +0 -14
- package/build/metadata/validate.spec.d.ts +0 -1
- package/build/metadata/validate.spec.js +0 -124
- package/build/package/Contributor.d.ts +0 -21
- package/build/package/Contributor.js +0 -2
- package/build/package/Package.d.ts +0 -65
- package/build/package/Package.js +0 -2
- package/build/package/index.d.ts +0 -4
- package/build/package/index.js +0 -3
- package/build/package/load.d.ts +0 -4
- package/build/package/load.js +0 -7
- package/build/package/save.d.ts +0 -9
- package/build/package/save.js +0 -13
- package/build/package/validate.d.ts +0 -1
- package/build/package/validate.js +0 -4
- package/build/resource/License.d.ts +0 -18
- package/build/resource/License.js +0 -2
- package/build/resource/Resource.d.ts +0 -67
- package/build/resource/Resource.js +0 -2
- package/build/resource/Source.d.ts +0 -17
- package/build/resource/Source.js +0 -2
- package/build/resource/index.d.ts +0 -5
- package/build/resource/index.js +0 -2
- package/build/resource/load.d.ts +0 -1
- package/build/resource/load.js +0 -2
- package/build/resource/save.d.ts +0 -9
- package/build/resource/save.js +0 -13
- package/build/resource/types/index.d.ts +0 -1
- package/build/resource/types/index.js +0 -2
- package/build/resource/types/table.d.ts +0 -29
- package/build/resource/types/table.js +0 -2
- package/build/resource/validate.d.ts +0 -1
- package/build/resource/validate.js +0 -4
- package/build/schema/Field.d.ts +0 -5
- package/build/schema/Field.js +0 -2
- package/build/schema/Schema.d.ts +0 -55
- package/build/schema/Schema.js +0 -2
- package/build/schema/fields/any.d.ts +0 -20
- package/build/schema/fields/any.js +0 -2
- package/build/schema/fields/array.d.ts +0 -32
- package/build/schema/fields/array.js +0 -2
- package/build/schema/fields/base.d.ts +0 -42
- package/build/schema/fields/base.js +0 -2
- package/build/schema/fields/boolean.d.ts +0 -28
- package/build/schema/fields/boolean.js +0 -2
- package/build/schema/fields/date.d.ts +0 -35
- package/build/schema/fields/date.js +0 -2
- package/build/schema/fields/datetime.d.ts +0 -35
- package/build/schema/fields/datetime.js +0 -2
- package/build/schema/fields/duration.d.ts +0 -28
- package/build/schema/fields/duration.js +0 -2
- package/build/schema/fields/geojson.d.ts +0 -26
- package/build/schema/fields/geojson.js +0 -2
- package/build/schema/fields/geopoint.d.ts +0 -27
- package/build/schema/fields/geopoint.js +0 -2
- package/build/schema/fields/index.d.ts +0 -16
- package/build/schema/fields/index.js +0 -17
- package/build/schema/fields/integer.d.ts +0 -37
- package/build/schema/fields/integer.js +0 -2
- package/build/schema/fields/list.d.ts +0 -36
- package/build/schema/fields/list.js +0 -2
- package/build/schema/fields/number.d.ts +0 -40
- package/build/schema/fields/number.js +0 -2
- package/build/schema/fields/object.d.ts +0 -32
- package/build/schema/fields/object.js +0 -2
- package/build/schema/fields/string.d.ts +0 -40
- package/build/schema/fields/string.js +0 -2
- package/build/schema/fields/time.d.ts +0 -35
- package/build/schema/fields/time.js +0 -2
- package/build/schema/fields/year.d.ts +0 -28
- package/build/schema/fields/year.js +0 -2
- package/build/schema/fields/yearmonth.d.ts +0 -28
- package/build/schema/fields/yearmonth.js +0 -2
- package/build/schema/index.d.ts +0 -4
- package/build/schema/index.js +0 -2
- package/build/schema/load.d.ts +0 -1
- package/build/schema/load.js +0 -2
- package/build/schema/save.d.ts +0 -9
- package/build/schema/save.js +0 -13
- package/build/schema/validate.d.ts +0 -1
- package/build/schema/validate.js +0 -4
- package/build/tsconfig.tsbuildinfo +0 -1
- package/index.ts +0 -0
- package/tsconfig.json +0 -10
- package/typedoc.json +0 -4
- /package/build/{descriptor/save.spec.d.ts → actions/changelog/build.unit.d.ts} +0 -0
- /package/build/{descriptor/validate.spec.d.ts → actions/config/define.unit.d.ts} +0 -0
- /package/build/{metadata/save.spec.d.ts → actions/config/load.unit.d.ts} +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { Root } from "mdast"
|
|
2
|
+
import type { LeafDirective } from "mdast-util-directive"
|
|
3
|
+
import { describe, expect, it } from "vite-plus/test"
|
|
4
|
+
import { transformButtonDirectives } from "./remark-button.ts"
|
|
5
|
+
|
|
6
|
+
function makeLeafDirective(
|
|
7
|
+
name: string,
|
|
8
|
+
attributes: Record<string, string>,
|
|
9
|
+
children: LeafDirective["children"] = [],
|
|
10
|
+
): LeafDirective {
|
|
11
|
+
return {
|
|
12
|
+
type: "leafDirective" as LeafDirective["type"],
|
|
13
|
+
name,
|
|
14
|
+
attributes,
|
|
15
|
+
children,
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function makeTree(...children: Root["children"]): Root {
|
|
20
|
+
return { type: "root", children }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function process(tree: Root) {
|
|
24
|
+
transformButtonDirectives(tree)
|
|
25
|
+
return tree
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe("transformButtonDirectives", () => {
|
|
29
|
+
it("should convert ::button with bracket text to LinkButton JSX element", () => {
|
|
30
|
+
const tree = process(
|
|
31
|
+
makeTree(
|
|
32
|
+
makeLeafDirective("button", { href: "/start" }, [
|
|
33
|
+
{ type: "text", value: "Get Started" },
|
|
34
|
+
]),
|
|
35
|
+
),
|
|
36
|
+
)
|
|
37
|
+
const node = tree.children[0]
|
|
38
|
+
expect(node).toMatchObject({
|
|
39
|
+
type: "mdxJsxFlowElement",
|
|
40
|
+
name: "LinkButton",
|
|
41
|
+
attributes: [
|
|
42
|
+
{ type: "mdxJsxAttribute", name: "href", value: "/start" },
|
|
43
|
+
{ type: "mdxJsxAttribute", name: "label", value: "Get Started" },
|
|
44
|
+
],
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it("should convert ::button with label attribute to LinkButton JSX element", () => {
|
|
49
|
+
const tree = process(
|
|
50
|
+
makeTree(
|
|
51
|
+
makeLeafDirective("button", { href: "/docs", label: "Read Docs" }),
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
const node = tree.children[0]
|
|
55
|
+
expect(node).toMatchObject({
|
|
56
|
+
type: "mdxJsxFlowElement",
|
|
57
|
+
name: "LinkButton",
|
|
58
|
+
attributes: [
|
|
59
|
+
{ type: "mdxJsxAttribute", name: "href", value: "/docs" },
|
|
60
|
+
{ type: "mdxJsxAttribute", name: "label", value: "Read Docs" },
|
|
61
|
+
],
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it("should prefer bracket text over label attribute", () => {
|
|
66
|
+
const tree = process(
|
|
67
|
+
makeTree(
|
|
68
|
+
makeLeafDirective("button", { href: "/x", label: "Fallback" }, [
|
|
69
|
+
{ type: "text", value: "Primary" },
|
|
70
|
+
]),
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
const node = tree.children[0]
|
|
74
|
+
expect(node).toMatchObject({
|
|
75
|
+
type: "mdxJsxFlowElement",
|
|
76
|
+
name: "LinkButton",
|
|
77
|
+
attributes: [
|
|
78
|
+
{ type: "mdxJsxAttribute", name: "href", value: "/x" },
|
|
79
|
+
{ type: "mdxJsxAttribute", name: "label", value: "Primary" },
|
|
80
|
+
],
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it("should pass variant attribute when provided", () => {
|
|
85
|
+
const tree = process(
|
|
86
|
+
makeTree(
|
|
87
|
+
makeLeafDirective("button", { href: "/a", variant: "outline" }, [
|
|
88
|
+
{ type: "text", value: "Click" },
|
|
89
|
+
]),
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
const node = tree.children[0]
|
|
93
|
+
expect(node).toMatchObject({
|
|
94
|
+
type: "mdxJsxFlowElement",
|
|
95
|
+
name: "LinkButton",
|
|
96
|
+
attributes: [
|
|
97
|
+
{ type: "mdxJsxAttribute", name: "href", value: "/a" },
|
|
98
|
+
{ type: "mdxJsxAttribute", name: "label", value: "Click" },
|
|
99
|
+
{ type: "mdxJsxAttribute", name: "variant", value: "outline" },
|
|
100
|
+
],
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it("should pass size attribute when provided", () => {
|
|
105
|
+
const tree = process(
|
|
106
|
+
makeTree(
|
|
107
|
+
makeLeafDirective("button", { href: "/a", size: "lg" }, [
|
|
108
|
+
{ type: "text", value: "Big" },
|
|
109
|
+
]),
|
|
110
|
+
),
|
|
111
|
+
)
|
|
112
|
+
const node = tree.children[0]
|
|
113
|
+
expect(node).toMatchObject({
|
|
114
|
+
type: "mdxJsxFlowElement",
|
|
115
|
+
name: "LinkButton",
|
|
116
|
+
attributes: [
|
|
117
|
+
{ type: "mdxJsxAttribute", name: "href", value: "/a" },
|
|
118
|
+
{ type: "mdxJsxAttribute", name: "label", value: "Big" },
|
|
119
|
+
{ type: "mdxJsxAttribute", name: "size", value: "lg" },
|
|
120
|
+
],
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it("should skip button directive without href", () => {
|
|
125
|
+
const tree = process(
|
|
126
|
+
makeTree(makeLeafDirective("button", { label: "No Link" })),
|
|
127
|
+
)
|
|
128
|
+
const node = tree.children[0]
|
|
129
|
+
expect(node).toMatchObject({ type: "leafDirective", name: "button" })
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it("should skip button directive without label or bracket text", () => {
|
|
133
|
+
const tree = process(
|
|
134
|
+
makeTree(makeLeafDirective("button", { href: "/no-label" })),
|
|
135
|
+
)
|
|
136
|
+
const node = tree.children[0]
|
|
137
|
+
expect(node).toMatchObject({ type: "leafDirective", name: "button" })
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it("should ignore unrelated leaf directives", () => {
|
|
141
|
+
const tree = process(
|
|
142
|
+
makeTree(makeLeafDirective("video", { type: "youtube", id: "abc" })),
|
|
143
|
+
)
|
|
144
|
+
const node = tree.children[0]
|
|
145
|
+
expect(node).toMatchObject({ type: "leafDirective", name: "video" })
|
|
146
|
+
})
|
|
147
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Paragraph, Root } from "mdast"
|
|
2
|
+
import type { ContainerDirective } from "mdast-util-directive"
|
|
3
|
+
import type { Plugin } from "unified"
|
|
4
|
+
import { visit } from "unist-util-visit"
|
|
5
|
+
|
|
6
|
+
const calloutTypes = new Set(["note", "tip", "info", "warning", "danger"])
|
|
7
|
+
|
|
8
|
+
/** Remark plugin that converts container directives into Callout JSX elements */
|
|
9
|
+
export const remarkCallout: Plugin<[], Root> = () => {
|
|
10
|
+
return tree => {
|
|
11
|
+
visit(
|
|
12
|
+
tree,
|
|
13
|
+
"containerDirective",
|
|
14
|
+
(node: ContainerDirective, index, parent) => {
|
|
15
|
+
if (!calloutTypes.has(node.name) || index === undefined || !parent)
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
const labelParagraph = node.children.find(
|
|
19
|
+
(child): child is Paragraph =>
|
|
20
|
+
child.type === "paragraph" && !!child.data?.directiveLabel,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const title = labelParagraph
|
|
24
|
+
? {
|
|
25
|
+
type: "mdxJsxAttribute" as const,
|
|
26
|
+
name: "title",
|
|
27
|
+
value: labelParagraph.children
|
|
28
|
+
.map(c => ("value" in c ? String(c.value) : ""))
|
|
29
|
+
.join(""),
|
|
30
|
+
}
|
|
31
|
+
: undefined
|
|
32
|
+
|
|
33
|
+
const body = node.children.filter(
|
|
34
|
+
child => !(child.type === "paragraph" && child.data?.directiveLabel),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
const jsxNode = {
|
|
38
|
+
type: "mdxJsxFlowElement" as const,
|
|
39
|
+
name: "Callout",
|
|
40
|
+
attributes: [
|
|
41
|
+
{
|
|
42
|
+
type: "mdxJsxAttribute" as const,
|
|
43
|
+
name: "type",
|
|
44
|
+
value: node.name,
|
|
45
|
+
},
|
|
46
|
+
...(title ? [title] : []),
|
|
47
|
+
],
|
|
48
|
+
children: body,
|
|
49
|
+
data: { _mdxExplicitJsx: true },
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
53
|
+
parent.children.splice(index, 1, jsxNode)
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Root } from "mdast"
|
|
2
|
+
import type { ContainerDirective } from "mdast-util-directive"
|
|
3
|
+
import type { Plugin } from "unified"
|
|
4
|
+
import { visit, SKIP } from "unist-util-visit"
|
|
5
|
+
|
|
6
|
+
/** Remark plugin that converts :::card directives into Card/Cards JSX elements */
|
|
7
|
+
export const remarkCard: Plugin<[], Root> = () => {
|
|
8
|
+
return tree => {
|
|
9
|
+
visit(
|
|
10
|
+
tree,
|
|
11
|
+
"containerDirective",
|
|
12
|
+
(node: ContainerDirective, index, parent) => {
|
|
13
|
+
if (node.name !== "card" || index === undefined || !parent) return
|
|
14
|
+
|
|
15
|
+
const title = node.attributes?.title ?? ""
|
|
16
|
+
const href = node.attributes?.href
|
|
17
|
+
const icon = node.attributes?.icon
|
|
18
|
+
|
|
19
|
+
const attributes = [
|
|
20
|
+
{ type: "mdxJsxAttribute" as const, name: "title", value: title },
|
|
21
|
+
...(href
|
|
22
|
+
? [{ type: "mdxJsxAttribute" as const, name: "href", value: href }]
|
|
23
|
+
: []),
|
|
24
|
+
...(icon
|
|
25
|
+
? [{ type: "mdxJsxAttribute" as const, name: "icon", value: icon }]
|
|
26
|
+
: []),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
const jsxNode = {
|
|
30
|
+
type: "mdxJsxFlowElement" as const,
|
|
31
|
+
name: "Card",
|
|
32
|
+
attributes,
|
|
33
|
+
children: node.children,
|
|
34
|
+
data: { _mdxExplicitJsx: true },
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
38
|
+
parent.children[index] = jsxNode
|
|
39
|
+
return SKIP
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
const children = tree.children
|
|
44
|
+
let i = 0
|
|
45
|
+
while (i < children.length) {
|
|
46
|
+
const node = children[i]
|
|
47
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
48
|
+
if (node?.type !== "mdxJsxFlowElement" || node.name !== "Card") {
|
|
49
|
+
i++
|
|
50
|
+
continue
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let j = i + 1
|
|
54
|
+
while (j < children.length) {
|
|
55
|
+
const next = children[j]
|
|
56
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
57
|
+
if (next?.type !== "mdxJsxFlowElement" || next.name !== "Card") break
|
|
58
|
+
j++
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (j - i < 2) {
|
|
62
|
+
i++
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const group = children.slice(i, j)
|
|
67
|
+
const wrapper = {
|
|
68
|
+
type: "mdxJsxFlowElement" as const,
|
|
69
|
+
name: "Cards",
|
|
70
|
+
attributes: [],
|
|
71
|
+
children: group,
|
|
72
|
+
data: { _mdxExplicitJsx: true },
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
76
|
+
children.splice(i, j - i, wrapper)
|
|
77
|
+
i++
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Code, Root } from "mdast"
|
|
2
|
+
import type { Plugin } from "unified"
|
|
3
|
+
|
|
4
|
+
const TAB_PATTERN = /\btab="([^"]+)"/
|
|
5
|
+
const SYNC_PATTERN = /\bsync="([^"]+)"/
|
|
6
|
+
|
|
7
|
+
/** Remark plugin that groups consecutive code blocks with tab="name" meta into a CodeTabs component */
|
|
8
|
+
export const remarkCodeTabs: Plugin<[], Root> = () => {
|
|
9
|
+
return tree => {
|
|
10
|
+
const children = tree.children
|
|
11
|
+
let i = 0
|
|
12
|
+
|
|
13
|
+
while (i < children.length) {
|
|
14
|
+
const node = children[i]
|
|
15
|
+
if (node?.type !== "code" || !node.meta) {
|
|
16
|
+
i++
|
|
17
|
+
continue
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const firstMatch = TAB_PATTERN.exec(node.meta)
|
|
21
|
+
if (!firstMatch) {
|
|
22
|
+
i++
|
|
23
|
+
continue
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const group: { name: string; code: Code }[] = [
|
|
27
|
+
{ name: firstMatch[1]!, code: node },
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
let j = i + 1
|
|
31
|
+
while (j < children.length) {
|
|
32
|
+
const next = children[j]
|
|
33
|
+
if (next?.type !== "code" || !next.meta) break
|
|
34
|
+
const nextMatch = TAB_PATTERN.exec(next.meta)
|
|
35
|
+
if (!nextMatch) break
|
|
36
|
+
group.push({ name: nextMatch[1]!, code: next })
|
|
37
|
+
j++
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (group.length < 2) {
|
|
41
|
+
i++
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const firstMeta = group[0]!.code.meta!
|
|
46
|
+
const syncMatch = SYNC_PATTERN.exec(firstMeta)
|
|
47
|
+
|
|
48
|
+
for (const item of group) {
|
|
49
|
+
item.code.meta =
|
|
50
|
+
item.code
|
|
51
|
+
.meta!.replace(TAB_PATTERN, "")
|
|
52
|
+
.replace(SYNC_PATTERN, "")
|
|
53
|
+
.trim() || null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const codeTabsAttrs: {
|
|
57
|
+
type: "mdxJsxAttribute"
|
|
58
|
+
name: string
|
|
59
|
+
value: string
|
|
60
|
+
}[] = [
|
|
61
|
+
{
|
|
62
|
+
type: "mdxJsxAttribute",
|
|
63
|
+
name: "tabs",
|
|
64
|
+
value: JSON.stringify(group.map(g => g.name)),
|
|
65
|
+
},
|
|
66
|
+
]
|
|
67
|
+
if (syncMatch) {
|
|
68
|
+
codeTabsAttrs.push({
|
|
69
|
+
type: "mdxJsxAttribute",
|
|
70
|
+
name: "sync",
|
|
71
|
+
value: syncMatch[1]!,
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const jsxNode = {
|
|
76
|
+
type: "mdxJsxFlowElement",
|
|
77
|
+
name: "CodeTabs",
|
|
78
|
+
attributes: codeTabsAttrs,
|
|
79
|
+
children: group.map(g => g.code),
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
83
|
+
children.splice(i, group.length, jsxNode)
|
|
84
|
+
i++
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Root } from "mdast"
|
|
2
|
+
import type { ContainerDirective } from "mdast-util-directive"
|
|
3
|
+
import type { Plugin } from "unified"
|
|
4
|
+
import { visit, SKIP } from "unist-util-visit"
|
|
5
|
+
|
|
6
|
+
/** Remark plugin that converts consecutive :::column directives into a Columns grid */
|
|
7
|
+
export const remarkColumns: Plugin<[], Root> = () => {
|
|
8
|
+
return tree => {
|
|
9
|
+
visit(
|
|
10
|
+
tree,
|
|
11
|
+
"containerDirective",
|
|
12
|
+
(node: ContainerDirective, index, parent) => {
|
|
13
|
+
if (node.name !== "column" || index === undefined || !parent) return
|
|
14
|
+
|
|
15
|
+
const jsxNode = {
|
|
16
|
+
type: "mdxJsxFlowElement" as const,
|
|
17
|
+
name: "Column",
|
|
18
|
+
attributes: [],
|
|
19
|
+
children: node.children,
|
|
20
|
+
data: { _mdxExplicitJsx: true },
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
24
|
+
parent.children[index] = jsxNode
|
|
25
|
+
return SKIP
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const children = tree.children
|
|
30
|
+
let i = 0
|
|
31
|
+
while (i < children.length) {
|
|
32
|
+
const node = children[i]
|
|
33
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
34
|
+
if (node?.type !== "mdxJsxFlowElement" || node.name !== "Column") {
|
|
35
|
+
i++
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let j = i + 1
|
|
40
|
+
while (j < children.length) {
|
|
41
|
+
const next = children[j]
|
|
42
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
43
|
+
if (next?.type !== "mdxJsxFlowElement" || next.name !== "Column") break
|
|
44
|
+
j++
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (j - i < 2) {
|
|
48
|
+
i++
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const group = children.slice(i, j)
|
|
53
|
+
const wrapper = {
|
|
54
|
+
type: "mdxJsxFlowElement" as const,
|
|
55
|
+
name: "Columns",
|
|
56
|
+
attributes: [],
|
|
57
|
+
children: group,
|
|
58
|
+
data: { _mdxExplicitJsx: true },
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
62
|
+
children.splice(i, j - i, wrapper)
|
|
63
|
+
i++
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Heading, Root } from "mdast"
|
|
2
|
+
import type { Plugin } from "unified"
|
|
3
|
+
import { SKIP, visit } from "unist-util-visit"
|
|
4
|
+
|
|
5
|
+
declare module "mdast" {
|
|
6
|
+
interface HeadingData {
|
|
7
|
+
hProperties?: Record<string, string | number | boolean | null | undefined>
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CUSTOM_ID_PATTERN = /\s*\[#([^\]]+)\]\s*$/
|
|
12
|
+
const TOC_HIDDEN_PATTERN = /\s*\[!toc\]\s*$/
|
|
13
|
+
const TOC_ONLY_PATTERN = /\s*\[toc\]\s*$/
|
|
14
|
+
|
|
15
|
+
/** Walk a mdast tree and process heading annotations: `[#id]`, `[!toc]`, and `[toc]` */
|
|
16
|
+
export function transformHeadingAnnotations(tree: Root) {
|
|
17
|
+
visit(tree, "heading", (node: Heading, index, parent) => {
|
|
18
|
+
const lastChild = node.children[node.children.length - 1]
|
|
19
|
+
if (!lastChild || lastChild.type !== "text") return undefined
|
|
20
|
+
|
|
21
|
+
if (TOC_ONLY_PATTERN.test(lastChild.value)) {
|
|
22
|
+
if (parent && index !== undefined) {
|
|
23
|
+
parent.children.splice(index, 1)
|
|
24
|
+
return [SKIP, index] as const
|
|
25
|
+
}
|
|
26
|
+
return undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (TOC_HIDDEN_PATTERN.test(lastChild.value)) {
|
|
30
|
+
lastChild.value = lastChild.value.replace(TOC_HIDDEN_PATTERN, "")
|
|
31
|
+
if (lastChild.value === "" && node.children.length > 1) {
|
|
32
|
+
node.children.pop()
|
|
33
|
+
}
|
|
34
|
+
node.data = node.data ?? {}
|
|
35
|
+
node.data.hProperties = {
|
|
36
|
+
...node.data.hProperties,
|
|
37
|
+
"data-toc-hidden": true,
|
|
38
|
+
}
|
|
39
|
+
return undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const match = CUSTOM_ID_PATTERN.exec(lastChild.value)
|
|
43
|
+
if (!match) return undefined
|
|
44
|
+
|
|
45
|
+
const customId = match[1]
|
|
46
|
+
if (!customId) return undefined
|
|
47
|
+
|
|
48
|
+
lastChild.value = lastChild.value.replace(CUSTOM_ID_PATTERN, "")
|
|
49
|
+
|
|
50
|
+
if (lastChild.value === "" && node.children.length > 1) {
|
|
51
|
+
node.children.pop()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
node.data = node.data ?? {}
|
|
55
|
+
node.data.hProperties = { ...node.data.hProperties, id: customId }
|
|
56
|
+
return undefined
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @deprecated Use transformHeadingAnnotations instead */
|
|
61
|
+
export const transformCustomHeadingIds = transformHeadingAnnotations
|
|
62
|
+
|
|
63
|
+
/** Remark plugin that processes heading annotations: `[#custom-id]`, `[!toc]`, and `[toc]` */
|
|
64
|
+
const remarkCustomHeadingId: Plugin<[], Root> = () => {
|
|
65
|
+
return tree => {
|
|
66
|
+
transformHeadingAnnotations(tree)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default remarkCustomHeadingId
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { Heading, Root, Text } from "mdast"
|
|
2
|
+
import { describe, expect, it } from "vite-plus/test"
|
|
3
|
+
import {
|
|
4
|
+
transformCustomHeadingIds,
|
|
5
|
+
transformHeadingAnnotations,
|
|
6
|
+
} from "./remark-custom-heading-id.ts"
|
|
7
|
+
|
|
8
|
+
function makeHeading(depth: 1 | 2 | 3 | 4 | 5 | 6, text: string): Heading {
|
|
9
|
+
return { type: "heading", depth, children: [{ type: "text", value: text }] }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function makeBoldHeading(boldText: string, trailingText: string): Heading {
|
|
13
|
+
return {
|
|
14
|
+
type: "heading",
|
|
15
|
+
depth: 2,
|
|
16
|
+
children: [
|
|
17
|
+
{ type: "strong", children: [{ type: "text", value: boldText }] },
|
|
18
|
+
{ type: "text", value: trailingText },
|
|
19
|
+
],
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function makeTree(...headings: Heading[]): Root {
|
|
24
|
+
return { type: "root", children: headings }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findHeading(tree: Root, index: number): Heading {
|
|
28
|
+
const node = tree.children[index]
|
|
29
|
+
if (!node || node.type !== "heading") throw new Error("No heading at index")
|
|
30
|
+
return node
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function headingText(heading: Heading): string {
|
|
34
|
+
return heading.children
|
|
35
|
+
.filter((c): c is Text => c.type === "text")
|
|
36
|
+
.map(c => c.value)
|
|
37
|
+
.join("")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe("transformHeadingAnnotations", () => {
|
|
41
|
+
function process(tree: Root) {
|
|
42
|
+
transformHeadingAnnotations(tree)
|
|
43
|
+
return tree
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
it("should set a custom id from [#custom-id] syntax", () => {
|
|
47
|
+
const tree = process(makeTree(makeHeading(2, "My Heading [#custom-id]")))
|
|
48
|
+
const heading = findHeading(tree, 0)
|
|
49
|
+
expect(heading.data?.hProperties).toEqual({ id: "custom-id" })
|
|
50
|
+
expect(headingText(heading)).toBe("My Heading")
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it("should leave headings without custom ids unchanged", () => {
|
|
54
|
+
const tree = process(makeTree(makeHeading(2, "Normal Heading")))
|
|
55
|
+
const heading = findHeading(tree, 0)
|
|
56
|
+
expect(heading.data).toBeUndefined()
|
|
57
|
+
expect(headingText(heading)).toBe("Normal Heading")
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it("should handle different heading depths", () => {
|
|
61
|
+
const tree = process(
|
|
62
|
+
makeTree(
|
|
63
|
+
makeHeading(3, "Deep Heading [#deep]"),
|
|
64
|
+
makeHeading(4, "Deeper Heading [#deeper]"),
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
const h3 = findHeading(tree, 0)
|
|
69
|
+
expect(h3.data?.hProperties).toEqual({ id: "deep" })
|
|
70
|
+
expect(h3.depth).toBe(3)
|
|
71
|
+
|
|
72
|
+
const h4 = findHeading(tree, 1)
|
|
73
|
+
expect(h4.data?.hProperties).toEqual({ id: "deeper" })
|
|
74
|
+
expect(h4.depth).toBe(4)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it("should handle ids with hyphens and numbers", () => {
|
|
78
|
+
const tree = process(
|
|
79
|
+
makeTree(makeHeading(2, "Section 1 [#section-1-intro]")),
|
|
80
|
+
)
|
|
81
|
+
const heading = findHeading(tree, 0)
|
|
82
|
+
expect(heading.data?.hProperties).toEqual({ id: "section-1-intro" })
|
|
83
|
+
expect(headingText(heading)).toBe("Section 1")
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it("should preserve inline formatting before the id", () => {
|
|
87
|
+
const tree = process(
|
|
88
|
+
makeTree(makeBoldHeading("Bold", " heading [#bold-heading]")),
|
|
89
|
+
)
|
|
90
|
+
const heading = findHeading(tree, 0)
|
|
91
|
+
expect(heading.data?.hProperties).toEqual({ id: "bold-heading" })
|
|
92
|
+
expect(heading.children.some(c => c.type === "strong")).toBe(true)
|
|
93
|
+
expect(headingText(heading)).toBe(" heading")
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it("should add data-toc-hidden for [!toc] headings", () => {
|
|
97
|
+
const tree = process(makeTree(makeHeading(2, "Hidden Heading [!toc]")))
|
|
98
|
+
const heading = findHeading(tree, 0)
|
|
99
|
+
expect(heading.data?.hProperties).toEqual({ "data-toc-hidden": true })
|
|
100
|
+
expect(headingText(heading)).toBe("Hidden Heading")
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it("should remove [toc] headings from the tree", () => {
|
|
104
|
+
const tree = process(
|
|
105
|
+
makeTree(
|
|
106
|
+
makeHeading(2, "Visible Heading"),
|
|
107
|
+
makeHeading(2, "TOC Only Heading [toc]"),
|
|
108
|
+
makeHeading(3, "Another Visible"),
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
expect(tree.children).toHaveLength(2)
|
|
112
|
+
expect(headingText(findHeading(tree, 0))).toBe("Visible Heading")
|
|
113
|
+
expect(headingText(findHeading(tree, 1))).toBe("Another Visible")
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it("should remove consecutive [toc] headings correctly", () => {
|
|
117
|
+
const tree = process(
|
|
118
|
+
makeTree(
|
|
119
|
+
makeHeading(2, "First [toc]"),
|
|
120
|
+
makeHeading(2, "Second [toc]"),
|
|
121
|
+
makeHeading(2, "Kept"),
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
expect(tree.children).toHaveLength(1)
|
|
125
|
+
expect(headingText(findHeading(tree, 0))).toBe("Kept")
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it("should be available as transformCustomHeadingIds for backward compatibility", () => {
|
|
129
|
+
expect(transformCustomHeadingIds).toBe(transformHeadingAnnotations)
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Root, Parent } from "mdast"
|
|
2
|
+
import type { Plugin } from "unified"
|
|
3
|
+
import { visit, SKIP } from "unist-util-visit"
|
|
4
|
+
|
|
5
|
+
/** Remark plugin that converts defList nodes into DefinitionList/DefinitionTerm/DefinitionDetail JSX elements */
|
|
6
|
+
export const remarkDeflist: Plugin<[], Root> = () => {
|
|
7
|
+
return tree => {
|
|
8
|
+
visit(tree, "defList", (node: Parent, index, parent) => {
|
|
9
|
+
if (index === undefined || !parent) return
|
|
10
|
+
|
|
11
|
+
const children = node.children.map(child => {
|
|
12
|
+
const name =
|
|
13
|
+
child.type === "defListTerm" ? "DefinitionTerm" : "DefinitionDetail"
|
|
14
|
+
return {
|
|
15
|
+
type: "mdxJsxFlowElement" as const,
|
|
16
|
+
name,
|
|
17
|
+
attributes: [],
|
|
18
|
+
children: (child as Parent).children,
|
|
19
|
+
data: { _mdxExplicitJsx: true },
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const jsxNode = {
|
|
24
|
+
type: "mdxJsxFlowElement" as const,
|
|
25
|
+
name: "DefinitionList",
|
|
26
|
+
attributes: [],
|
|
27
|
+
children,
|
|
28
|
+
data: { _mdxExplicitJsx: true },
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// @ts-expect-error mdxJsxFlowElement is not in mdast types
|
|
32
|
+
parent.children.splice(index, 1, jsxNode)
|
|
33
|
+
return SKIP
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|