@0dep/toc 1.0.1 → 2.0.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/types/index.d.ts CHANGED
@@ -1,60 +1,80 @@
1
- declare module '@0dep/toc' {
2
- /**
3
- * Return the markdown with the toc between every `<!-- toc -->` and `<!-- /toc -->` pair regenerated. Each
4
- * pair lists every heading below its own start marker. A pair is left alone when it is unbalanced, has a
5
- * problem on its start marker, or has no headings below it, and nothing outside the pairs is ever touched.
6
- * The start marker line is kept as written, options included.
7
- * */
8
- export function buildToc(source: string): string;
9
- /**
10
- * Return the toc block, markers included, for the headings below `fromLine`, by default every heading so the
11
- * block can be pasted into a document without markers. Returns an empty string when there is nothing to list.
12
- * @param fromLine zero based line number, typically the start marker's
13
- * @param options rendered into the start marker, e.g. `{ collapsed: 'Contents' }`
14
- * */
15
- export function renderToc(source: string, fromLine?: number, options?: TocOptions): string;
16
- /**
17
- * Every marker pair in document order as zero based line numbers, outside fenced code blocks. A start marker
18
- * pairs with the first end marker after it. A missing side is -1: a start marker without an end marker, or an
19
- * end marker with no open start marker before it. `options` holds the recognised options written on the start
20
- * marker and `problem`, only present when there is one, says why the marker cannot be used.
21
- * */
22
- export function findMarkers(source: string): Marker[];
23
- /**
24
- * Slug a heading's rendered text the way github-slugger does: lowercase, drop everything that is not a
25
- * letter, number, mark, space, hyphen or underscore, then turn each space into a hyphen. Nothing is trimmed
26
- * or collapsed.
27
- * */
28
- export function slugify(text: string): string;
29
- /**
30
- * Reduce a heading's inline markdown to the text GitHub renders and slugs.
31
- * */
32
- export function headingText(markdown: string): string;
33
- export const TOC_START: "<!-- toc -->";
34
- export const TOC_END: "<!-- /toc -->";
35
- /**
36
- * Options written on a start marker. `collapsible` wraps the list in a details element that starts open,
37
- * `collapsed` in one that starts closed. Each is `true` for the default summary "Table of contents" or a
38
- * string for a custom one. `attributes` are the other `name="value"` pairs on the marker, rendered on the
39
- * summary element in the order written, only present when there are any.
40
- */
41
- export type TocOptions = {
42
- collapsible?: true | string;
43
- collapsed?: true | string;
44
- attributes?: Record<string, string>;
45
- };
46
- /**
47
- * A marker pair. `start` and `end` are zero based line numbers, -1 when that side is missing. `problem` is
48
- * only present when the start marker cannot be used: an unknown option or an impossible combination.
49
- */
50
- export type Marker = {
51
- start: number;
52
- end: number;
53
- options: TocOptions;
54
- problem?: string;
55
- };
56
-
57
- export {};
58
- }
59
-
1
+ /**
2
+ * The markdown with the toc between every `<!-- toc -->` and `<!-- /toc -->` pair regenerated.
3
+ * @param {string} source
4
+ * @returns {string}
5
+ */
6
+ export function buildToc(source: string): string;
7
+ /**
8
+ * The toc block, markers included, for the headings below `fromLine`, empty when there is nothing to list.
9
+ * @param {string} source
10
+ * @param {number} [fromLine] zero based
11
+ * @param {TocOptions} [options]
12
+ * @returns {string}
13
+ */
14
+ export function renderToc(source: string, fromLine?: number, options?: TocOptions): string;
15
+ /**
16
+ * Every marker pair in document order, shared with later calls for the same source.
17
+ * @param {string} source
18
+ * @returns {Marker[]}
19
+ */
20
+ export function findMarkers(source: string): Marker[];
21
+ /**
22
+ * Every link to an anchor in the document, in order, shared with later calls for the same source.
23
+ * @param {string} source
24
+ * @returns {Anchor[]}
25
+ */
26
+ export function findAnchors(source: string): Anchor[];
27
+ /**
28
+ * The GitHub anchor slug of a heading's rendered text.
29
+ * @param {string} text
30
+ * @returns {string}
31
+ */
32
+ export function slugify(text: string): string;
33
+ /**
34
+ * The text GitHub renders for a heading's inline markdown.
35
+ * @param {string} markdown
36
+ * @returns {string}
37
+ */
38
+ export function headingText(markdown: string): string;
39
+ export const TOC_START: "<!-- toc -->";
40
+ export const TOC_END: "<!-- /toc -->";
41
+ /**
42
+ * Options written on a start marker, each `true` or a summary text, and the other attributes for the summary element.
43
+ */
44
+ export type TocOptions = {
45
+ collapsible?: true | string;
46
+ collapsed?: true | string;
47
+ levels?: string;
48
+ attributes?: Record<string, string>;
49
+ };
50
+ /**
51
+ * A heading with its zero based line, level, inline markdown and GitHub slug.
52
+ */
53
+ export type Headline = {
54
+ line: number;
55
+ level: number;
56
+ markdown: string;
57
+ slug: string;
58
+ };
59
+ /**
60
+ * A link to an anchor with its zero based line, text, anchor as written, whether it has a target and, when it
61
+ * has none and one heading clearly matches, a suggestion.
62
+ */
63
+ export type Anchor = {
64
+ line: number;
65
+ text: string;
66
+ anchor: string;
67
+ valid: boolean;
68
+ suggestion?: string;
69
+ };
70
+ /**
71
+ * A marker pair as zero based lines, -1 for a missing side, with its options, a problem when they cannot be used and a warning when one is ignored.
72
+ */
73
+ export type Marker = {
74
+ start: number;
75
+ end: number;
76
+ options: TocOptions;
77
+ problem?: string;
78
+ warning?: string;
79
+ };
60
80
  //# sourceMappingURL=index.d.ts.map
@@ -1,23 +1 @@
1
- {
2
- "version": 3,
3
- "file": "index.d.ts",
4
- "names": [
5
- "buildToc",
6
- "renderToc",
7
- "findMarkers",
8
- "slugify",
9
- "headingText",
10
- "TOC_START",
11
- "TOC_END",
12
- "TocOptions",
13
- "Marker"
14
- ],
15
- "sources": [
16
- "../index.js"
17
- ],
18
- "sourcesContent": [
19
- null
20
- ],
21
- "mappings": ";;;;;;;iBAcgBA,QAAQA;;;;;;;iBAyBRC,SAASA;;;;;;;iBAcTC,WAAWA;;;;;;iBAWXC,OAAOA;;;;iBAYPC,WAAWA;cA5EdC,SAASA;cACTC,OAAOA;;;;;;;aAyT0FC,UAAUA;;;;;;;;;aAMpCC,MAAMA",
22
- "ignoreList": []
23
- }
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,iCAHW,MAAM,GACJ,MAAM,CAgBlB;AAED;;;;;;GAMG;AACH,kCALW,MAAM,aACN,MAAM,YACN,UAAU,GACR,MAAM,CAMlB;AAED;;;;GAIG;AACH,oCAHW,MAAM,GACJ,MAAM,EAAE,CAIpB;AAED;;;;GAIG;AACH,oCAHW,MAAM,GACJ,MAAM,EAAE,CAIpB;AAED;;;;GAIG;AACH,8BAHW,MAAM,GACJ,MAAM,CAOlB;AAED;;;;GAIG;AACH,sCAHW,MAAM,GACJ,MAAM,CAUlB;AAvFD,wBAAyB,cAAc,CAAC;AACxC,sBAAuB,eAAe,CAAC;;;;yBA6Z1B;IAAE,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE;;;;uBAKhH;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;;qBAM/D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;;;;qBAKnF;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE"}
package/index.cjs DELETED
@@ -1,332 +0,0 @@
1
- 'use strict';
2
-
3
- const TOC_START = '<!-- toc -->';
4
- const TOC_END = '<!-- /toc -->';
5
- const DEFAULT_SUMMARY = 'Table of contents';
6
- const KNOWN_OPTIONS = ['collapsible', 'collapsed'];
7
- const NUL = String.fromCharCode(0);
8
-
9
- /**
10
- * Return the markdown with the toc between every `<!-- toc -->` and `<!-- /toc -->` pair regenerated. Each
11
- * pair lists every heading below its own start marker. A pair is left alone when it is unbalanced, has a
12
- * problem on its start marker, or has no headings below it, and nothing outside the pairs is ever touched.
13
- * The start marker line is kept as written, options included.
14
- * @param {string} source
15
- * @returns {string}
16
- */
17
- function buildToc(source) {
18
- const { lines, eol } = splitLines(source);
19
- const { headlines, markers } = scan(lines);
20
- /** @type {string[]} */
21
- const out = [];
22
- let cursor = 0;
23
- for (const { start, end, options, problem } of markers) {
24
- if (start === -1 || end === -1 || problem) continue;
25
- const listed = headlines.filter((h) => h.line > start);
26
- if (listed.length === 0) continue;
27
- out.push(...lines.slice(cursor, start), renderBlock(listed, lines[start], options, eol));
28
- cursor = end + 1;
29
- }
30
- out.push(...lines.slice(cursor));
31
- return out.join(eol);
32
- }
33
-
34
- /**
35
- * Return the toc block, markers included, for the headings below `fromLine`, by default every heading so the
36
- * block can be pasted into a document without markers. Returns an empty string when there is nothing to list.
37
- * @param {string} source
38
- * @param {number} [fromLine] zero based line number, typically the start marker's
39
- * @param {TocOptions} [options] rendered into the start marker, e.g. `{ collapsed: 'Contents' }`
40
- * @returns {string}
41
- */
42
- function renderToc(source, fromLine = -1, options = {}) {
43
- const { lines, eol } = splitLines(source);
44
- const listed = scan(lines).headlines.filter((h) => h.line > fromLine);
45
- return listed.length === 0 ? '' : renderBlock(listed, formatMarker(options), options, eol);
46
- }
47
-
48
- /**
49
- * Every marker pair in document order as zero based line numbers, outside fenced code blocks. A start marker
50
- * pairs with the first end marker after it. A missing side is -1: a start marker without an end marker, or an
51
- * end marker with no open start marker before it. `options` holds the recognised options written on the start
52
- * marker and `problem`, only present when there is one, says why the marker cannot be used.
53
- * @param {string} source
54
- * @returns {Marker[]}
55
- */
56
- function findMarkers(source) {
57
- return scan(splitLines(source).lines).markers;
58
- }
59
-
60
- /**
61
- * Slug a heading's rendered text the way github-slugger does: lowercase, drop everything that is not a
62
- * letter, number, mark, space, hyphen or underscore, then turn each space into a hyphen. Nothing is trimmed
63
- * or collapsed.
64
- * @param {string} text
65
- * @returns {string}
66
- */
67
- function slugify(text) {
68
- return text
69
- .toLowerCase()
70
- .replace(/[^\p{L}\p{N}\p{M} _-]/gu, '')
71
- .replace(/ /g, '-');
72
- }
73
-
74
- /**
75
- * Reduce a heading's inline markdown to the text GitHub renders and slugs.
76
- * @param {string} markdown
77
- * @returns {string}
78
- */
79
- function headingText(markdown) {
80
- const { text, restore } = protect(stripClosingHashes(markdown));
81
- const rendered = stripLinks(text)
82
- .replace(/<\/?[a-zA-Z][^>]*>/g, '')
83
- .replace(/~~(?=\S)(.+?)(?<=\S)~~/g, '$1')
84
- .replace(/\*+(?=\S)|(?<=\S)\*+/g, '')
85
- .replace(/(?<![\p{L}\p{N}_])_+(?=\S)|(?<=\S)_+(?![\p{L}\p{N}_])/gu, '');
86
- return restore(rendered).trim();
87
- }
88
-
89
- /**
90
- * Split the source into lines and remember its line ending, CRLF when the source has any, so the toc is
91
- * written the way the rest of the file is and a Windows authored file does not end up with mixed endings.
92
- * @param {string} source
93
- * @returns {{ lines: string[], eol: string }}
94
- */
95
- function splitLines(source) {
96
- return { lines: source.split(/\r?\n/), eol: source.includes('\r\n') ? '\r\n' : '\n' };
97
- }
98
-
99
- /**
100
- * Scan the lines for every marker pair and every ATX and setext heading, all outside fenced code blocks. A
101
- * marker is a line holding nothing but the comment, indented at most three spaces like a heading, since four
102
- * make an indented code block. A start marker, `<!-- toc -->` with optional options before the closing `-->`,
103
- * opens a pair that the first end marker after it closes; a start marker inside an open pair is content and an end marker outside a pair is
104
- * reported with start -1.
105
- * @param {string[]} lines
106
- * @returns {{ headlines: Array<{ line: number, level: number, markdown: string }>, markers: Marker[] }}
107
- */
108
- function scan(lines) {
109
- /** @type {Array<{ line: number, level: number, markdown: string }>} */
110
- const headlines = [];
111
- /** @type {Marker[]} */
112
- const markers = [];
113
- /** @type {{ char: string, length: number } | null} */
114
- let fence = null;
115
- /** @type {Marker | null} */
116
- let open = null;
117
-
118
- for (const [i, line] of lines.entries()) {
119
- const fenceMatch = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);
120
- if (fence) {
121
- if (fenceMatch && fenceMatch[1][0] === fence.char && fenceMatch[1].length >= fence.length && !fenceMatch[2].trim()) {
122
- fence = null;
123
- }
124
- continue;
125
- }
126
- if (fenceMatch && !(fenceMatch[1][0] === '`' && fenceMatch[2].includes('`'))) {
127
- fence = { char: fenceMatch[1][0], length: fenceMatch[1].length };
128
- continue;
129
- }
130
-
131
- const startMatch = /^ {0,3}<!--\s*toc(?:\s+(.*?))?\s*-->\s*$/.exec(line);
132
- if (startMatch) {
133
- if (!open) markers.push((open = { start: i, end: -1, ...parseOptions(startMatch[1]) }));
134
- continue;
135
- }
136
- if (/^ {0,3}<!--\s*\/toc\s*-->\s*$/.test(line)) {
137
- if (open) open.end = i;
138
- else markers.push({ start: -1, end: i, options: {} });
139
- open = null;
140
- continue;
141
- }
142
-
143
- const atx = /^ {0,3}(#{1,6})\s+(.+?)\s*$/.exec(line);
144
- if (atx) {
145
- headlines.push({ line: i, level: atx[1].length, markdown: atx[2] });
146
- continue;
147
- }
148
-
149
- const setext = /^ {0,3}(=+|-+)\s*$/.exec(line);
150
- if (setext && i > 0 && isParagraphText(lines[i - 1])) {
151
- headlines.push({ line: i - 1, level: setext[1][0] === '=' ? 1 : 2, markdown: lines[i - 1].trim() });
152
- }
153
- }
154
- return { headlines, markers };
155
- }
156
-
157
- /**
158
- * The toc block for the given headings, wrapped in the given start marker line and the end marker. Indentation
159
- * is relative to the shallowest level listed so far, so the list never starts indented, which markdown would
160
- * render flat anyway, and duplicate slugs get github style `-1`, `-2` suffixes. With
161
- * `collapsible` or `collapsed` the list goes inside a details element, open or closed to start with, blank
162
- * lines around it so it renders as markdown, and any other attributes from the marker on the summary element.
163
- * @param {Array<{ level: number, markdown: string }>} headlines
164
- * @param {string} startLine the start marker as written in the document
165
- * @param {TocOptions} options
166
- * @param {string} [eol] line ending, LF by default
167
- */
168
- function renderBlock(headlines, startLine, options, eol = '\n') {
169
- /** @type {Record<string, number>} */
170
- const occurrences = {};
171
- let minLevel = Infinity;
172
- const tocLines = headlines.map(({ level, markdown }) => {
173
- minLevel = Math.min(minLevel, level);
174
- const base = slugify(headingText(markdown));
175
- let slug = base;
176
- while (Object.hasOwn(occurrences, slug)) {
177
- occurrences[base]++;
178
- slug = `${base}-${occurrences[base]}`;
179
- }
180
- occurrences[slug] = 0;
181
- return `${' '.repeat(level - minLevel)}- [${headingLabel(markdown)}](#${slug})`;
182
- });
183
- const details = options.collapsible ?? options.collapsed;
184
- if (details === undefined) return [startLine, '', ...tocLines, '', TOC_END].join(eol);
185
- const summary = details === true ? DEFAULT_SUMMARY : details;
186
- const tag = options.collapsible === undefined ? '<details>' : '<details open>';
187
- const attrs = formatAttributes(options.attributes ?? {})
188
- .map((a) => ` ${a}`)
189
- .join('');
190
- return [startLine, tag, `<summary${attrs}>${summary}</summary>`, '', ...tocLines, '', '</details>', TOC_END].join(eol);
191
- }
192
-
193
- /**
194
- * Parse what is written on a start marker: the options as bare names (`collapsed`) or quoted values
195
- * (`collapsed="Contents"`), and any other well-formed `name="value"` as an attribute for the summary element.
196
- * Anything else, bare names that are not options, unquoted values, malformed names, is a problem, as is a
197
- * combination that makes no sense. A marker with a problem is never used.
198
- * @param {string | undefined} text
199
- * @returns {{ options: TocOptions, problem?: string }}
200
- */
201
- function parseOptions(text) {
202
- /** @type {TocOptions} */
203
- const options = {};
204
- /** @type {Record<string, string>} */
205
- const attributes = {};
206
- /** @type {string[]} */
207
- const unknown = [];
208
- for (const [token, name, value] of (text ?? '').matchAll(/([^\s="]+)(?:="([^"]*)")?(?=\s|$)|\S+/g)) {
209
- if (name && KNOWN_OPTIONS.includes(name)) options[/** @type {'collapsible' | 'collapsed'} */ (name)] = value ?? true;
210
- else if (name && value !== undefined && /^[a-zA-Z][\w:.-]*$/.test(name)) attributes[name] = value;
211
- else unknown.push(token);
212
- }
213
- const names = Object.keys(attributes);
214
- if (names.length) options.attributes = attributes;
215
- if (unknown.length) return { options, problem: `unknown TOC option ${unknown.join(' ')}` };
216
- if (options.collapsible !== undefined && options.collapsed !== undefined) {
217
- return { options, problem: 'TOC options collapsible and collapsed exclude each other' };
218
- }
219
- if (names.length && options.collapsible === undefined && options.collapsed === undefined) {
220
- return { options, problem: `TOC attributes ${names.join(', ')} need collapsible or collapsed` };
221
- }
222
- return { options };
223
- }
224
-
225
- /**
226
- * The start marker line for the given options, the inverse of `parseOptions`: options first, then attributes.
227
- * @param {TocOptions} options
228
- */
229
- function formatMarker(options) {
230
- const { attributes = {}, ...named } = options;
231
- const parts = [
232
- ...Object.entries(named).map(([name, value]) => (value === true ? name : `${name}="${value}"`)),
233
- ...formatAttributes(attributes),
234
- ];
235
- return parts.length ? `<!-- toc ${parts.join(' ')} -->` : TOC_START;
236
- }
237
-
238
- /**
239
- * @param {Record<string, string>} attributes
240
- * @returns {string[]} `name="value"` in the order given
241
- */
242
- function formatAttributes(attributes) {
243
- return Object.entries(attributes).map(([name, value]) => `${name}="${value}"`);
244
- }
245
-
246
- /**
247
- * The label used in the toc: the heading's own markdown, except that links become their text since a link
248
- * cannot nest inside the toc link.
249
- * @param {string} markdown
250
- * @returns {string}
251
- */
252
- function headingLabel(markdown) {
253
- const { text, restore } = protect(stripClosingHashes(markdown), { keepCodeSpans: true });
254
- return restore(stripLinks(text)).trim();
255
- }
256
-
257
- /**
258
- * Replace code spans (with their content, or the whole span when `keepCodeSpans` is set) and backslash escapes
259
- * (with the escaped character) by placeholders so the inline markdown passes leave them alone.
260
- * @param {string} markdown
261
- * @param {{ keepCodeSpans?: boolean }} [options]
262
- */
263
- function protect(markdown, { keepCodeSpans = false } = {}) {
264
- /** @type {string[]} */
265
- const kept = [];
266
- /** @param {string} value */
267
- const keep = (value) => `${NUL}${kept.push(value) - 1}${NUL}`;
268
- const text = markdown
269
- .replace(/(`+)(.+?)\1(?!`)/g, (span, _ticks, code) => keep(keepCodeSpans ? span : unpadCodeSpan(code)))
270
- .replace(/\\([!-/:-@[-`{-~])/g, (_, char) => keep(char));
271
- return {
272
- text,
273
- /** @param {string} value */
274
- restore: (value) => value.replace(new RegExp(`${NUL}(\\d+)${NUL}`, 'g'), (_, i) => kept[Number(i)]),
275
- };
276
- }
277
-
278
- /**
279
- * Strip one leading and one trailing space from code span content when both are present and the content is
280
- * not only spaces, as CommonMark does.
281
- * @param {string} code
282
- */
283
- function unpadCodeSpan(code) {
284
- if (code.length > 2 && code.startsWith(' ') && code.endsWith(' ') && code.trim() !== '') return code.slice(1, -1);
285
- return code;
286
- }
287
-
288
- /** @param {string} markdown */
289
- function stripClosingHashes(markdown) {
290
- return markdown.replace(/(^|\s+)#+\s*$/, '');
291
- }
292
-
293
- /**
294
- * Links, images and reference links become their text, autolinks their url. Used for both the slug text and
295
- * the toc label since a link cannot nest inside the toc link.
296
- * @param {string} text
297
- */
298
- function stripLinks(text) {
299
- return text
300
- .replace(/<(https?:\/\/[^>\s]+|mailto:[^>\s]+)>/g, '$1')
301
- .replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
302
- .replace(/\[([^\]]*)\]\([^)]*\)/g, '$1')
303
- .replace(/\[([^\]]*)\]\[[^\]]*\]/g, '$1');
304
- }
305
-
306
- /** @param {string} line */
307
- function isParagraphText(line) {
308
- const trimmed = line.trim();
309
- return trimmed !== '' && !/^(#|>|[-*+]\s|\d+[.)]\s|\||[-=]+\s*$|```|~~~|<!--)/.test(trimmed);
310
- }
311
-
312
- /**
313
- * Options written on a start marker. `collapsible` wraps the list in a details element that starts open,
314
- * `collapsed` in one that starts closed. Each is `true` for the default summary "Table of contents" or a
315
- * string for a custom one. `attributes` are the other `name="value"` pairs on the marker, rendered on the
316
- * summary element in the order written, only present when there are any.
317
- * @typedef {{ collapsible?: true | string, collapsed?: true | string, attributes?: Record<string, string> }} TocOptions
318
- */
319
-
320
- /**
321
- * A marker pair. `start` and `end` are zero based line numbers, -1 when that side is missing. `problem` is
322
- * only present when the start marker cannot be used: an unknown option or an impossible combination.
323
- * @typedef {{ start: number, end: number, options: TocOptions, problem?: string }} Marker
324
- */
325
-
326
- exports.TOC_END = TOC_END;
327
- exports.TOC_START = TOC_START;
328
- exports.buildToc = buildToc;
329
- exports.findMarkers = findMarkers;
330
- exports.headingText = headingText;
331
- exports.renderToc = renderToc;
332
- exports.slugify = slugify;