@classic-homes/theme-docs 0.1.0 → 0.2.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/dist/lib/components/Breadcrumbs.svelte +55 -0
- package/dist/lib/components/Breadcrumbs.svelte.d.ts +14 -0
- package/dist/lib/components/CategoryIndex.svelte +51 -0
- package/dist/lib/components/CategoryIndex.svelte.d.ts +13 -0
- package/dist/lib/components/DocPage.svelte +172 -0
- package/dist/lib/components/DocPage.svelte.d.ts +60 -0
- package/dist/lib/components/DocPager.svelte +49 -0
- package/dist/lib/components/DocPager.svelte.d.ts +12 -0
- package/dist/lib/components/MarkdownPage.svelte +3 -1
- package/dist/lib/components/MermaidDiagram.svelte +2 -0
- package/dist/lib/components/MermaidInit.svelte +2 -0
- package/dist/lib/components/TableOfContents.svelte +114 -125
- package/dist/lib/components/TableOfContents.svelte.d.ts +11 -4
- package/dist/lib/components/TagIndex.svelte +42 -0
- package/dist/lib/components/TagIndex.svelte.d.ts +14 -0
- package/dist/lib/components/TagList.svelte +45 -0
- package/dist/lib/components/TagList.svelte.d.ts +15 -0
- package/dist/lib/components/TocPanel.svelte +27 -9
- package/dist/lib/components/TocPanel.svelte.d.ts +10 -3
- package/dist/lib/components/enhance.d.ts +29 -0
- package/dist/lib/components/enhance.js +179 -0
- package/dist/lib/components/sidebar.d.ts +33 -0
- package/dist/lib/components/sidebar.js +84 -0
- package/dist/lib/content/browser.d.ts +6 -0
- package/dist/lib/content/browser.js +5 -0
- package/dist/lib/content/index.d.ts +13 -0
- package/dist/lib/content/index.js +12 -0
- package/dist/lib/content/load.d.ts +77 -0
- package/dist/lib/content/load.js +366 -0
- package/dist/lib/content/nav.d.ts +36 -0
- package/dist/lib/content/nav.js +81 -0
- package/dist/lib/content/render.d.ts +38 -0
- package/dist/lib/content/render.js +84 -0
- package/dist/lib/content/types.d.ts +90 -0
- package/dist/lib/content/types.js +5 -0
- package/dist/lib/index.d.ts +14 -2
- package/dist/lib/index.js +14 -2
- package/dist/lib/parser/api.d.ts +12 -0
- package/dist/lib/parser/api.js +10 -0
- package/dist/lib/parser/extensions.d.ts +27 -15
- package/dist/lib/parser/extensions.js +58 -53
- package/dist/lib/parser/index.d.ts +4 -1
- package/dist/lib/parser/index.js +104 -27
- package/dist/lib/sanitize/index.d.ts +11 -0
- package/dist/lib/sanitize/index.js +122 -0
- package/dist/lib/search/index.d.ts +57 -0
- package/dist/lib/search/index.js +82 -0
- package/dist/lib/styles/markdown.css +138 -0
- package/dist/lib/types/frontmatter.d.ts +21 -0
- package/dist/lib/vite/index.d.ts +17 -0
- package/dist/lib/vite/index.js +38 -0
- package/package.json +51 -4
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shapes of the docs content model built by `loadDocs` and `renderDocs`.
|
|
3
|
+
* Plain data: safe to serialize into a bundle and to import from client code.
|
|
4
|
+
*/
|
|
5
|
+
import type { FrontmatterData } from '../types/frontmatter.js';
|
|
6
|
+
import type { TocEntry } from '../types/docs.js';
|
|
7
|
+
/** One sidebar entry. A category's `route` is its linked doc or generated-index page. */
|
|
8
|
+
export type NavItem = {
|
|
9
|
+
type: 'page';
|
|
10
|
+
title: string;
|
|
11
|
+
route: string;
|
|
12
|
+
} | {
|
|
13
|
+
type: 'category';
|
|
14
|
+
label: string;
|
|
15
|
+
route?: string;
|
|
16
|
+
/** From `_category_.json`. Undefined means the site's default. */
|
|
17
|
+
collapsible?: boolean;
|
|
18
|
+
collapsed?: boolean;
|
|
19
|
+
items: NavItem[];
|
|
20
|
+
};
|
|
21
|
+
/** A markdown file, with its links rewritten to site routes. */
|
|
22
|
+
export interface DocSource {
|
|
23
|
+
/** Site route, e.g. `/docs/it/network/vpn` (`index.md` maps to its folder) */
|
|
24
|
+
route: string;
|
|
25
|
+
/** Path under the docs directory, posix separators, e.g. `it/network/vpn/index.md` */
|
|
26
|
+
file: string;
|
|
27
|
+
/** ID of the sidebar the page belongs to, or null when it sits outside every sidebar root */
|
|
28
|
+
sidebar: string | null;
|
|
29
|
+
/** `title` front matter, else the first `# heading`, else the file name */
|
|
30
|
+
title: string;
|
|
31
|
+
/** `sidebar_label` front matter: the page's name in navigation (Docusaurus parity) */
|
|
32
|
+
sidebarLabel?: string;
|
|
33
|
+
description: string;
|
|
34
|
+
tags: string[];
|
|
35
|
+
/** `sidebar_position` front matter */
|
|
36
|
+
position?: number;
|
|
37
|
+
/** The page's full front matter, including fields this package doesn't know */
|
|
38
|
+
frontmatter: FrontmatterData;
|
|
39
|
+
/** Markdown body (no front matter), links resolved */
|
|
40
|
+
markdown: string;
|
|
41
|
+
}
|
|
42
|
+
/** A sidebar autogenerated from one directory, as Docusaurus `{type: 'autogenerated', dirName}` does. */
|
|
43
|
+
export interface Sidebar {
|
|
44
|
+
/** The directory it was generated from (relative to the docs dir), or `default` for the root */
|
|
45
|
+
id: string;
|
|
46
|
+
/** The directory, relative to the docs dir ('' for the root) */
|
|
47
|
+
dir: string;
|
|
48
|
+
/** `_category_.json` label of the directory, else its name */
|
|
49
|
+
label: string;
|
|
50
|
+
/** `_category_.json` position of the directory */
|
|
51
|
+
position?: number;
|
|
52
|
+
/** Route of the directory itself */
|
|
53
|
+
route: string;
|
|
54
|
+
/** The directory's index page if it has one, else its shallowest, lowest-positioned page */
|
|
55
|
+
landingRoute: string;
|
|
56
|
+
items: NavItem[];
|
|
57
|
+
}
|
|
58
|
+
/** A generated-index page (`_category_.json` `link: { type: 'generated-index' }`). */
|
|
59
|
+
export interface CategoryPage {
|
|
60
|
+
route: string;
|
|
61
|
+
sidebar: string;
|
|
62
|
+
title: string;
|
|
63
|
+
description: string;
|
|
64
|
+
/** The category's items, in sidebar order */
|
|
65
|
+
items: NavItem[];
|
|
66
|
+
}
|
|
67
|
+
export interface Tag {
|
|
68
|
+
id: string;
|
|
69
|
+
label: string;
|
|
70
|
+
description: string;
|
|
71
|
+
}
|
|
72
|
+
export interface DocsContent {
|
|
73
|
+
pages: DocSource[];
|
|
74
|
+
sidebars: Sidebar[];
|
|
75
|
+
categories: CategoryPage[];
|
|
76
|
+
/** The tag vocabulary when one was given, else every tag used, in first-use order */
|
|
77
|
+
tags: Tag[];
|
|
78
|
+
/** Non-fatal problems, e.g. broken links when `onBrokenLinks` is `'warn'` */
|
|
79
|
+
warnings: string[];
|
|
80
|
+
}
|
|
81
|
+
/** A page after `renderDocs`: HTML instead of markdown, plus what layouts and search need. */
|
|
82
|
+
export interface RenderedDoc extends Omit<DocSource, 'markdown'> {
|
|
83
|
+
html: string;
|
|
84
|
+
/** Headings with IDs, all levels */
|
|
85
|
+
toc: TocEntry[];
|
|
86
|
+
/** Whether the body has its own `<h1>`. When it doesn't, the layout shows `title`. */
|
|
87
|
+
hasH1: boolean;
|
|
88
|
+
/** Searchable plain text: the page without markup, code blocks or diagrams */
|
|
89
|
+
text: string;
|
|
90
|
+
}
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
* with syntax highlighting, frontmatter support, and rich markdown extensions.
|
|
6
6
|
*
|
|
7
7
|
* Supported Markdown Extensions:
|
|
8
|
-
* - Admonitions/Callouts: :::note, :::tip, :::warning, :::important, :::caution
|
|
8
|
+
* - Admonitions/Callouts: :::note, :::info, :::tip, :::warning, :::important, :::caution, :::danger
|
|
9
9
|
* - Footnotes: [^1] references and [^1]: definitions
|
|
10
10
|
* - Definition Lists: Term followed by : Definition
|
|
11
11
|
* - Mermaid Diagrams: ```mermaid code blocks (rendered client-side)
|
|
12
12
|
*
|
|
13
|
+
* Node/server code (build scripts, loaders) should import the pipeline from
|
|
14
|
+
* `@classic-homes/theme-docs/parser`, which has no Svelte imports, and sanitize
|
|
15
|
+
* rendered HTML with `@classic-homes/theme-docs/sanitize`.
|
|
16
|
+
*
|
|
13
17
|
* @packageDocumentation
|
|
14
18
|
*/
|
|
15
19
|
export { default as MarkdownPage } from './components/MarkdownPage.svelte';
|
|
@@ -20,12 +24,20 @@ export { default as TableOfContents } from './components/TableOfContents.svelte'
|
|
|
20
24
|
export { default as TocPanel } from './components/TocPanel.svelte';
|
|
21
25
|
export { default as MermaidDiagram } from './components/MermaidDiagram.svelte';
|
|
22
26
|
export { default as MermaidInit } from './components/MermaidInit.svelte';
|
|
27
|
+
export { default as DocPage } from './components/DocPage.svelte';
|
|
28
|
+
export { default as CategoryIndex } from './components/CategoryIndex.svelte';
|
|
29
|
+
export { default as Breadcrumbs } from './components/Breadcrumbs.svelte';
|
|
30
|
+
export { default as DocPager } from './components/DocPager.svelte';
|
|
31
|
+
export { default as TagList } from './components/TagList.svelte';
|
|
32
|
+
export { default as TagIndex } from './components/TagIndex.svelte';
|
|
23
33
|
export { mountComponents } from './components/mount.js';
|
|
34
|
+
export { enhanceCodeBlocks, highlightTerms, labelDiagram } from './components/enhance.js';
|
|
35
|
+
export { toSidebarNav, revealActive, type ToSidebarNavOptions } from './components/sidebar.js';
|
|
24
36
|
export type { AuthorInfo, FrontmatterData, ParsedMarkdown, ParseOptions, MarkdownPageProps, } from './types/frontmatter.js';
|
|
25
37
|
export type { DocsItem, DocsSection, DocsHubConfig, DocsHubProps, DocsCardProps, TocEntry, TableOfContentsProps, } from './types/docs.js';
|
|
26
38
|
export { parseMarkdown, extractToc } from './parser/index.js';
|
|
27
39
|
export { createSlugger, type HeadingIdStyle } from './parser/slug.js';
|
|
28
40
|
export { highlightCode, getHighlighter, escapeHtml } from './highlighter/index.js';
|
|
29
41
|
export { cn } from './utils.js';
|
|
30
|
-
export { ADMONITION_TYPES, type AdmonitionType, admonitionExtension, footnoteExtension, definitionListExtension, mermaidExtension, getAllExtensions, resetFootnoteStore, renderFootnotes, } from './parser/extensions.js';
|
|
42
|
+
export { ADMONITION_TYPES, type AdmonitionType, admonitionExtension, footnoteExtension, definitionListExtension, mermaidExtension, componentExtension, getAllExtensions, createFootnoteStore, type FootnoteStore, resetFootnoteStore, renderFootnotes, renderMermaidPlaceholder, } from './parser/extensions.js';
|
|
31
43
|
export { tv, type VariantProps } from 'tailwind-variants';
|
package/dist/lib/index.js
CHANGED
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
* with syntax highlighting, frontmatter support, and rich markdown extensions.
|
|
6
6
|
*
|
|
7
7
|
* Supported Markdown Extensions:
|
|
8
|
-
* - Admonitions/Callouts: :::note, :::tip, :::warning, :::important, :::caution
|
|
8
|
+
* - Admonitions/Callouts: :::note, :::info, :::tip, :::warning, :::important, :::caution, :::danger
|
|
9
9
|
* - Footnotes: [^1] references and [^1]: definitions
|
|
10
10
|
* - Definition Lists: Term followed by : Definition
|
|
11
11
|
* - Mermaid Diagrams: ```mermaid code blocks (rendered client-side)
|
|
12
12
|
*
|
|
13
|
+
* Node/server code (build scripts, loaders) should import the pipeline from
|
|
14
|
+
* `@classic-homes/theme-docs/parser`, which has no Svelte imports, and sanitize
|
|
15
|
+
* rendered HTML with `@classic-homes/theme-docs/sanitize`.
|
|
16
|
+
*
|
|
13
17
|
* @packageDocumentation
|
|
14
18
|
*/
|
|
15
19
|
// Components
|
|
@@ -21,13 +25,21 @@ export { default as TableOfContents } from './components/TableOfContents.svelte'
|
|
|
21
25
|
export { default as TocPanel } from './components/TocPanel.svelte';
|
|
22
26
|
export { default as MermaidDiagram } from './components/MermaidDiagram.svelte';
|
|
23
27
|
export { default as MermaidInit } from './components/MermaidInit.svelte';
|
|
28
|
+
export { default as DocPage } from './components/DocPage.svelte';
|
|
29
|
+
export { default as CategoryIndex } from './components/CategoryIndex.svelte';
|
|
30
|
+
export { default as Breadcrumbs } from './components/Breadcrumbs.svelte';
|
|
31
|
+
export { default as DocPager } from './components/DocPager.svelte';
|
|
32
|
+
export { default as TagList } from './components/TagList.svelte';
|
|
33
|
+
export { default as TagIndex } from './components/TagIndex.svelte';
|
|
24
34
|
export { mountComponents } from './components/mount.js';
|
|
35
|
+
export { enhanceCodeBlocks, highlightTerms, labelDiagram } from './components/enhance.js';
|
|
36
|
+
export { toSidebarNav, revealActive } from './components/sidebar.js';
|
|
25
37
|
// Utilities
|
|
26
38
|
export { parseMarkdown, extractToc } from './parser/index.js';
|
|
27
39
|
export { createSlugger } from './parser/slug.js';
|
|
28
40
|
export { highlightCode, getHighlighter, escapeHtml } from './highlighter/index.js';
|
|
29
41
|
export { cn } from './utils.js';
|
|
30
42
|
// Markdown Extensions
|
|
31
|
-
export { ADMONITION_TYPES, admonitionExtension, footnoteExtension, definitionListExtension, mermaidExtension, getAllExtensions, resetFootnoteStore, renderFootnotes, } from './parser/extensions.js';
|
|
43
|
+
export { ADMONITION_TYPES, admonitionExtension, footnoteExtension, definitionListExtension, mermaidExtension, componentExtension, getAllExtensions, createFootnoteStore, resetFootnoteStore, renderFootnotes, renderMermaidPlaceholder, } from './parser/extensions.js';
|
|
32
44
|
// Re-export tailwind-variants types for consumer convenience
|
|
33
45
|
export { tv } from 'tailwind-variants';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@classic-homes/theme-docs/parser` — the markdown pipeline without any Svelte imports.
|
|
3
|
+
*
|
|
4
|
+
* Safe to load in Node (build scripts, server loaders, workers) and in non-Svelte bundles
|
|
5
|
+
* such as a CMS preview. The package root re-exports all of this alongside the components.
|
|
6
|
+
*/
|
|
7
|
+
export { parseMarkdown, extractToc } from './index.js';
|
|
8
|
+
export { createSlugger, type HeadingIdStyle } from './slug.js';
|
|
9
|
+
export { ADMONITION_TYPES, type AdmonitionType, admonitionExtension, footnoteExtension, definitionListExtension, mermaidExtension, componentExtension, getAllExtensions, createFootnoteStore, type FootnoteStore, resetFootnoteStore, renderFootnotes, renderMermaidPlaceholder, } from './extensions.js';
|
|
10
|
+
export { highlightCode, getHighlighter, escapeHtml } from '../highlighter/index.js';
|
|
11
|
+
export type { AuthorInfo, FrontmatterData, ParsedMarkdown, ParseOptions, } from '../types/frontmatter.js';
|
|
12
|
+
export type { TocEntry } from '../types/docs.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@classic-homes/theme-docs/parser` — the markdown pipeline without any Svelte imports.
|
|
3
|
+
*
|
|
4
|
+
* Safe to load in Node (build scripts, server loaders, workers) and in non-Svelte bundles
|
|
5
|
+
* such as a CMS preview. The package root re-exports all of this alongside the components.
|
|
6
|
+
*/
|
|
7
|
+
export { parseMarkdown, extractToc } from './index.js';
|
|
8
|
+
export { createSlugger } from './slug.js';
|
|
9
|
+
export { ADMONITION_TYPES, admonitionExtension, footnoteExtension, definitionListExtension, mermaidExtension, componentExtension, getAllExtensions, createFootnoteStore, resetFootnoteStore, renderFootnotes, renderMermaidPlaceholder, } from './extensions.js';
|
|
10
|
+
export { highlightCode, getHighlighter, escapeHtml } from '../highlighter/index.js';
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Mermaid diagram placeholders (rendered client-side)
|
|
9
9
|
* - Component placeholders for allowlisted `<Name prop="…" />` tags (mounted client-side)
|
|
10
10
|
*/
|
|
11
|
-
import type { MarkedExtension } from 'marked';
|
|
11
|
+
import type { MarkedExtension, Tokens } from 'marked';
|
|
12
12
|
/**
|
|
13
13
|
* Admonition types and their corresponding icons/classes
|
|
14
14
|
*/
|
|
@@ -34,7 +34,24 @@ export type AdmonitionType = (typeof ADMONITION_TYPES)[number];
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function admonitionExtension(): MarkedExtension;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* Footnotes collected while parsing one document.
|
|
38
|
+
*
|
|
39
|
+
* Each `parseMarkdown` call creates its own store, so concurrent parses (e.g. a server
|
|
40
|
+
* rendering many pages at once) never mix up each other's footnotes.
|
|
41
|
+
*/
|
|
42
|
+
export interface FootnoteStore {
|
|
43
|
+
definitions: Map<string, {
|
|
44
|
+
content: string;
|
|
45
|
+
tokens: Tokens.Generic[];
|
|
46
|
+
}>;
|
|
47
|
+
references: Set<string>;
|
|
48
|
+
}
|
|
49
|
+
export declare function createFootnoteStore(): FootnoteStore;
|
|
50
|
+
/**
|
|
51
|
+
* Reset the default footnote store.
|
|
52
|
+
*
|
|
53
|
+
* @deprecated `parseMarkdown` now keeps a store per call. Only needed if you build a
|
|
54
|
+
* `Marked` instance yourself from `footnoteExtension()` without passing a store.
|
|
38
55
|
*/
|
|
39
56
|
export declare function resetFootnoteStore(): void;
|
|
40
57
|
/**
|
|
@@ -45,23 +62,16 @@ export declare function resetFootnoteStore(): void;
|
|
|
45
62
|
*
|
|
46
63
|
* [^1]: This is the footnote content.
|
|
47
64
|
*/
|
|
48
|
-
export declare function footnoteExtension(): MarkedExtension;
|
|
65
|
+
export declare function footnoteExtension(store?: FootnoteStore): MarkedExtension;
|
|
49
66
|
/**
|
|
50
67
|
* Render collected footnotes as a section
|
|
51
68
|
* Call this after parsing to get the footnotes HTML
|
|
52
|
-
*/
|
|
53
|
-
export declare function renderFootnotes(): string;
|
|
54
|
-
/**
|
|
55
|
-
* Definition list extension for marked
|
|
56
|
-
*
|
|
57
|
-
* Syntax:
|
|
58
|
-
* Term 1
|
|
59
|
-
* : Definition for term 1
|
|
60
69
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
70
|
+
* @param store - The store the footnote extension wrote to (default: the shared store)
|
|
71
|
+
* @param renderInline - Renders a footnote's inline tokens to HTML. Without it the
|
|
72
|
+
* footnote text is escaped and shown as written.
|
|
64
73
|
*/
|
|
74
|
+
export declare function renderFootnotes(store?: FootnoteStore, renderInline?: (tokens: Tokens.Generic[]) => string): string;
|
|
65
75
|
export declare function definitionListExtension(): MarkedExtension;
|
|
66
76
|
/**
|
|
67
77
|
* Mermaid code block extension for marked
|
|
@@ -75,6 +85,7 @@ export declare function definitionListExtension(): MarkedExtension;
|
|
|
75
85
|
* A --> B
|
|
76
86
|
* ```
|
|
77
87
|
*/
|
|
88
|
+
export declare function renderMermaidPlaceholder(code: string): string;
|
|
78
89
|
export declare function mermaidExtension(): MarkedExtension;
|
|
79
90
|
/**
|
|
80
91
|
* Component placeholder extension for marked
|
|
@@ -93,5 +104,6 @@ export declare function componentExtension(names: readonly string[]): MarkedExte
|
|
|
93
104
|
* Get all markdown extensions
|
|
94
105
|
*
|
|
95
106
|
* @param components - Names of components to render as placeholders (see `componentExtension`)
|
|
107
|
+
* @param footnotes - Store for this document's footnotes (default: the shared store)
|
|
96
108
|
*/
|
|
97
|
-
export declare function getAllExtensions(components?: readonly string[]): MarkedExtension[];
|
|
109
|
+
export declare function getAllExtensions(components?: readonly string[], footnotes?: FootnoteStore): MarkedExtension[];
|
|
@@ -76,13 +76,13 @@ export function admonitionExtension() {
|
|
|
76
76
|
const innerHtml = this.parser.parse(token.tokens ?? []);
|
|
77
77
|
const titleHtml = this.parser.parseInline(token.titleTokens ?? []);
|
|
78
78
|
const iconMap = {
|
|
79
|
-
note: `<svg class="admonition-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>`,
|
|
80
|
-
info: `<svg class="admonition-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>`,
|
|
81
|
-
tip: `<svg class="admonition-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>`,
|
|
82
|
-
warning: `<svg class="admonition-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>`,
|
|
83
|
-
important: `<svg class="admonition-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"/><path d="M12 8v4"/><path d="M12 16h.01"/></svg>`,
|
|
84
|
-
caution: `<svg class="admonition-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7.86 2h8.28L22 7.86v8.28L16.14 22H7.86L2 16.14V7.86L7.86 2z"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>`,
|
|
85
|
-
danger: `<svg class="admonition-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"/></svg>`,
|
|
79
|
+
note: `<svg class="admonition-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>`,
|
|
80
|
+
info: `<svg class="admonition-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>`,
|
|
81
|
+
tip: `<svg class="admonition-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>`,
|
|
82
|
+
warning: `<svg class="admonition-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>`,
|
|
83
|
+
important: `<svg class="admonition-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"/><path d="M12 8v4"/><path d="M12 16h.01"/></svg>`,
|
|
84
|
+
caution: `<svg class="admonition-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7.86 2h8.28L22 7.86v8.28L16.14 22H7.86L2 16.14V7.86L7.86 2z"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>`,
|
|
85
|
+
danger: `<svg class="admonition-icon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"/></svg>`,
|
|
86
86
|
};
|
|
87
87
|
return `<div class="admonition admonition-${token.admonitionType}">
|
|
88
88
|
<div class="admonition-heading">
|
|
@@ -96,18 +96,19 @@ export function admonitionExtension() {
|
|
|
96
96
|
],
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
|
|
100
|
-
definitions: new Map(),
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
export function createFootnoteStore() {
|
|
100
|
+
return { definitions: new Map(), references: new Set() };
|
|
101
|
+
}
|
|
102
|
+
/** Store used when an extension is created without one (the pre-0.2 global API). */
|
|
103
|
+
let defaultFootnoteStore = createFootnoteStore();
|
|
103
104
|
/**
|
|
104
|
-
* Reset footnote store
|
|
105
|
+
* Reset the default footnote store.
|
|
106
|
+
*
|
|
107
|
+
* @deprecated `parseMarkdown` now keeps a store per call. Only needed if you build a
|
|
108
|
+
* `Marked` instance yourself from `footnoteExtension()` without passing a store.
|
|
105
109
|
*/
|
|
106
110
|
export function resetFootnoteStore() {
|
|
107
|
-
|
|
108
|
-
definitions: new Map(),
|
|
109
|
-
references: new Set(),
|
|
110
|
-
};
|
|
111
|
+
defaultFootnoteStore = createFootnoteStore();
|
|
111
112
|
}
|
|
112
113
|
/**
|
|
113
114
|
* Footnotes extension for marked
|
|
@@ -117,7 +118,8 @@ export function resetFootnoteStore() {
|
|
|
117
118
|
*
|
|
118
119
|
* [^1]: This is the footnote content.
|
|
119
120
|
*/
|
|
120
|
-
export function footnoteExtension() {
|
|
121
|
+
export function footnoteExtension(store) {
|
|
122
|
+
const footnotes = () => store ?? defaultFootnoteStore;
|
|
121
123
|
return {
|
|
122
124
|
extensions: [
|
|
123
125
|
// Footnote definition: [^id]: content
|
|
@@ -141,7 +143,7 @@ export function footnoteExtension() {
|
|
|
141
143
|
tokens: [],
|
|
142
144
|
};
|
|
143
145
|
this.lexer.inline(content, token.tokens);
|
|
144
|
-
|
|
146
|
+
footnotes().definitions.set(id, { content, tokens: token.tokens });
|
|
145
147
|
return token;
|
|
146
148
|
}
|
|
147
149
|
return undefined;
|
|
@@ -162,7 +164,7 @@ export function footnoteExtension() {
|
|
|
162
164
|
const match = src.match(/^\[\^([^\]]+)\](?!:)/);
|
|
163
165
|
if (match) {
|
|
164
166
|
const id = match[1];
|
|
165
|
-
|
|
167
|
+
footnotes().references.add(id);
|
|
166
168
|
return {
|
|
167
169
|
type: 'footnoteRef',
|
|
168
170
|
raw: match[0],
|
|
@@ -172,7 +174,8 @@ export function footnoteExtension() {
|
|
|
172
174
|
return undefined;
|
|
173
175
|
},
|
|
174
176
|
renderer(token) {
|
|
175
|
-
|
|
177
|
+
const id = escapeHtml(token.id);
|
|
178
|
+
return `<sup class="footnote-ref"><a href="#fn-${id}" id="fnref-${id}" aria-label="Footnote ${id}">[${id}]</a></sup>`;
|
|
176
179
|
},
|
|
177
180
|
},
|
|
178
181
|
],
|
|
@@ -181,38 +184,33 @@ export function footnoteExtension() {
|
|
|
181
184
|
/**
|
|
182
185
|
* Render collected footnotes as a section
|
|
183
186
|
* Call this after parsing to get the footnotes HTML
|
|
187
|
+
*
|
|
188
|
+
* @param store - The store the footnote extension wrote to (default: the shared store)
|
|
189
|
+
* @param renderInline - Renders a footnote's inline tokens to HTML. Without it the
|
|
190
|
+
* footnote text is escaped and shown as written.
|
|
184
191
|
*/
|
|
185
|
-
export function renderFootnotes() {
|
|
186
|
-
if (
|
|
192
|
+
export function renderFootnotes(store = defaultFootnoteStore, renderInline) {
|
|
193
|
+
if (store.definitions.size === 0) {
|
|
187
194
|
return '';
|
|
188
195
|
}
|
|
189
196
|
const items = [];
|
|
190
|
-
for (const [
|
|
191
|
-
if (
|
|
197
|
+
for (const [rawId, { content, tokens }] of store.definitions) {
|
|
198
|
+
if (store.references.has(rawId)) {
|
|
199
|
+
const id = escapeHtml(rawId);
|
|
200
|
+
const body = renderInline ? renderInline(tokens) : escapeHtml(content);
|
|
192
201
|
items.push(`<li id="fn-${id}" class="footnote-item">
|
|
193
|
-
<p>${
|
|
202
|
+
<p>${body} <a href="#fnref-${id}" class="footnote-backref" aria-label="Back to reference ${id}">↩</a></p>
|
|
194
203
|
</li>`);
|
|
195
204
|
}
|
|
196
205
|
}
|
|
197
206
|
if (items.length === 0) {
|
|
198
207
|
return '';
|
|
199
208
|
}
|
|
200
|
-
return `<section class="footnotes">
|
|
209
|
+
return `<section class="footnotes" aria-label="Footnotes">
|
|
201
210
|
<hr class="footnotes-separator" />
|
|
202
211
|
<ol class="footnotes-list">${items.join('')}</ol>
|
|
203
212
|
</section>`;
|
|
204
213
|
}
|
|
205
|
-
/**
|
|
206
|
-
* Definition list extension for marked
|
|
207
|
-
*
|
|
208
|
-
* Syntax:
|
|
209
|
-
* Term 1
|
|
210
|
-
* : Definition for term 1
|
|
211
|
-
*
|
|
212
|
-
* Term 2
|
|
213
|
-
* : Definition for term 2
|
|
214
|
-
* : Another definition for term 2
|
|
215
|
-
*/
|
|
216
214
|
export function definitionListExtension() {
|
|
217
215
|
return {
|
|
218
216
|
extensions: [
|
|
@@ -254,6 +252,11 @@ export function definitionListExtension() {
|
|
|
254
252
|
if (items.length === 0) {
|
|
255
253
|
return undefined;
|
|
256
254
|
}
|
|
255
|
+
// Terms and definitions are inline markdown, like everywhere else in a page
|
|
256
|
+
for (const item of items) {
|
|
257
|
+
item.termTokens = this.lexer.inlineTokens(item.term);
|
|
258
|
+
item.definitionTokens = item.definitions.map((def) => this.lexer.inlineTokens(def));
|
|
259
|
+
}
|
|
257
260
|
return {
|
|
258
261
|
type: 'defList',
|
|
259
262
|
raw,
|
|
@@ -265,8 +268,10 @@ export function definitionListExtension() {
|
|
|
265
268
|
renderer(token) {
|
|
266
269
|
const itemsHtml = token.items
|
|
267
270
|
.map((item) => {
|
|
268
|
-
const defsHtml = item.
|
|
269
|
-
|
|
271
|
+
const defsHtml = item.definitionTokens
|
|
272
|
+
.map((tokens) => `<dd>${this.parser.parseInline(tokens)}</dd>`)
|
|
273
|
+
.join('');
|
|
274
|
+
return `<dt>${this.parser.parseInline(item.termTokens)}</dt>${defsHtml}`;
|
|
270
275
|
})
|
|
271
276
|
.join('');
|
|
272
277
|
return `<dl class="definition-list">${itemsHtml}</dl>`;
|
|
@@ -287,6 +292,14 @@ export function definitionListExtension() {
|
|
|
287
292
|
* A --> B
|
|
288
293
|
* ```
|
|
289
294
|
*/
|
|
295
|
+
export function renderMermaidPlaceholder(code) {
|
|
296
|
+
// A placeholder div with the mermaid code; the client-side Mermaid library picks it up.
|
|
297
|
+
// The <pre> shows the source until (or if) mermaid renders it.
|
|
298
|
+
const escapedCode = escapeHtml(code);
|
|
299
|
+
return `<div class="mermaid-diagram" data-mermaid="${escapedCode}">
|
|
300
|
+
<pre class="mermaid">${escapedCode}</pre>
|
|
301
|
+
</div>`;
|
|
302
|
+
}
|
|
290
303
|
export function mermaidExtension() {
|
|
291
304
|
return {
|
|
292
305
|
extensions: [
|
|
@@ -294,10 +307,10 @@ export function mermaidExtension() {
|
|
|
294
307
|
name: 'mermaidBlock',
|
|
295
308
|
level: 'block',
|
|
296
309
|
start(src) {
|
|
297
|
-
return src.match(/^```mermaid/)?.index;
|
|
310
|
+
return src.match(/^```mermaid[ \t]*\n/)?.index;
|
|
298
311
|
},
|
|
299
312
|
tokenizer(src) {
|
|
300
|
-
const match = src.match(/^```mermaid\n([\s\S]*?)```/);
|
|
313
|
+
const match = src.match(/^```mermaid[ \t]*\n([\s\S]*?)```/);
|
|
301
314
|
if (match) {
|
|
302
315
|
return {
|
|
303
316
|
type: 'mermaidBlock',
|
|
@@ -308,16 +321,7 @@ export function mermaidExtension() {
|
|
|
308
321
|
return undefined;
|
|
309
322
|
},
|
|
310
323
|
renderer(token) {
|
|
311
|
-
|
|
312
|
-
// The client-side Mermaid library will pick this up
|
|
313
|
-
const escapedCode = token.code
|
|
314
|
-
.replace(/&/g, '&')
|
|
315
|
-
.replace(/</g, '<')
|
|
316
|
-
.replace(/>/g, '>')
|
|
317
|
-
.replace(/"/g, '"');
|
|
318
|
-
return `<div class="mermaid-diagram" data-mermaid="${escapedCode}">
|
|
319
|
-
<pre class="mermaid">${token.code}</pre>
|
|
320
|
-
</div>`;
|
|
324
|
+
return renderMermaidPlaceholder(token.code);
|
|
321
325
|
},
|
|
322
326
|
},
|
|
323
327
|
],
|
|
@@ -367,11 +371,12 @@ export function componentExtension(names) {
|
|
|
367
371
|
* Get all markdown extensions
|
|
368
372
|
*
|
|
369
373
|
* @param components - Names of components to render as placeholders (see `componentExtension`)
|
|
374
|
+
* @param footnotes - Store for this document's footnotes (default: the shared store)
|
|
370
375
|
*/
|
|
371
|
-
export function getAllExtensions(components = []) {
|
|
376
|
+
export function getAllExtensions(components = [], footnotes) {
|
|
372
377
|
return [
|
|
373
378
|
admonitionExtension(),
|
|
374
|
-
footnoteExtension(),
|
|
379
|
+
footnoteExtension(footnotes),
|
|
375
380
|
definitionListExtension(),
|
|
376
381
|
mermaidExtension(),
|
|
377
382
|
...(components.length > 0 ? [componentExtension(components)] : []),
|
|
@@ -18,8 +18,11 @@ import type { ParsedMarkdown, ParseOptions } from '../types/index.js';
|
|
|
18
18
|
* @param options.theme - Shiki theme for code highlighting ('github-dark' | 'github-light' | 'one-dark-pro')
|
|
19
19
|
* @param options.generateHeadingIds - Whether to generate IDs for headings (default: true)
|
|
20
20
|
* @param options.headingIdStyle - 'default', or 'github' for GitHub/Docusaurus-compatible IDs
|
|
21
|
+
* @param options.headingAnchors - Add a `#` permalink to each heading (default: false)
|
|
21
22
|
* @param options.components - Tag names to render as component placeholders (see `mountComponents`)
|
|
22
|
-
* @
|
|
23
|
+
* @param options.externalLinks - Open http(s) links in a new tab, announced to screen readers
|
|
24
|
+
* @param options.langAlias - Map fence names to Shiki languages, e.g. `{ ios: 'text' }`
|
|
25
|
+
* @returns Parsed markdown with frontmatter data, cleaned markdown, rendered HTML, and TOC
|
|
23
26
|
*
|
|
24
27
|
* @example
|
|
25
28
|
* ```typescript
|