Skip to content

Commit d4c5cac

Browse files
committed
Refactor code-style
* Add more docs to JSDoc * Add support for `null` in input of API types
1 parent f93734b commit d4c5cac

File tree

3 files changed

+76
-47
lines changed

3 files changed

+76
-47
lines changed

lib/contents.js

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
/**
2-
* @typedef {import('mdast').Root|import('mdast').Content} Node
32
* @typedef {import('mdast').List} List
43
* @typedef {import('mdast').ListItem} ListItem
54
* @typedef {import('mdast').PhrasingContent} PhrasingContent
65
* @typedef {import('mdast').StaticPhrasingContent} StaticPhrasingContent
76
* @typedef {import('./search.js').SearchEntry} SearchEntry
8-
*
7+
*/
8+
9+
/**
910
* @typedef ContentsOptions
10-
* @property {boolean} [tight=false]
11+
* Build configuration.
12+
* @property {boolean | null | undefined} [tight=false]
1113
* Whether to compile list-items tightly.
12-
* @property {boolean} [ordered=false]
14+
* @property {boolean | null | undefined} [ordered=false]
1315
* Whether to compile list-items as an ordered list, otherwise they are
1416
* unordered.
15-
* @property {string|null} [prefix=null]
17+
* @property {string | null | undefined} [prefix=null]
1618
* Add a prefix to links to headings in the table of contents.
1719
* Useful for example when later going from mdast to hast and sanitizing with
1820
* `hast-util-sanitize`.
@@ -61,11 +63,12 @@ export function contents(map, settings) {
6163
* Insert an entry into `parent`.
6264
*
6365
* @param {SearchEntry} entry
64-
* @param {List|ListItem} parent
66+
* @param {List | ListItem} parent
6567
* @param {ContentsOptions} settings
6668
*/
6769
function insert(entry, parent, settings) {
6870
let index = -1
71+
const tail = parent.children[parent.children.length - 1]
6972

7073
if (parent.type === 'list') {
7174
if (entry.depth === 1) {
@@ -87,7 +90,8 @@ function insert(entry, parent, settings) {
8790
]
8891
})
8992
} else if (parent.children.length > 0) {
90-
insert(entry, parent.children[parent.children.length - 1], settings)
93+
const tail = parent.children[parent.children.length - 1]
94+
insert(entry, tail, settings)
9195
} else {
9296
/** @type {ListItem} */
9397
const item = {type: 'listItem', spread: false, children: []}
@@ -96,17 +100,9 @@ function insert(entry, parent, settings) {
96100
}
97101
}
98102
// List item
99-
else if (
100-
parent.children[parent.children.length - 1] &&
101-
parent.children[parent.children.length - 1].type === 'list'
102-
) {
103+
else if (tail && tail.type === 'list') {
103104
entry.depth--
104-
insert(
105-
entry,
106-
// @ts-expect-error It’s a `list`, we just checked.
107-
parent.children[parent.children.length - 1],
108-
settings
109-
)
105+
insert(entry, tail, settings)
110106
} else {
111107
/** @type {List} */
112108
const item = {
@@ -154,16 +150,18 @@ function all(nodes) {
154150

155151
/**
156152
* @param {PhrasingContent} node
157-
* @returns {StaticPhrasingContent|Array<StaticPhrasingContent>}
153+
* @returns {StaticPhrasingContent | Array<StaticPhrasingContent>}
158154
*/
159155
function one(node) {
156+
if (node.type === 'footnoteReference') {
157+
return []
158+
}
159+
160160
if (
161161
node.type === 'link' ||
162162
node.type === 'linkReference' ||
163-
node.type === 'footnote' ||
164-
node.type === 'footnoteReference'
163+
node.type === 'footnote'
165164
) {
166-
// @ts-expect-error Looks like a parent.
167165
return all(node.children)
168166
}
169167

lib/index.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
/**
2-
* @typedef {import('mdast').Root|import('mdast').Content} Node
2+
* @typedef {import('mdast').Root} Root
3+
* @typedef {import('mdast').Content} Content
34
* @typedef {import('mdast').List} List
45
* @typedef {import('./search.js').SearchOptions} SearchOptions
56
* @typedef {import('./contents.js').ContentsOptions} ContentsOptions
7+
*/
8+
9+
/**
10+
* @typedef {Root | Content} Node
611
* @typedef {SearchOptions & ContentsOptions & ExtraOptions} Options
712
*
813
* @typedef ExtraOptions
9-
* @property {string} [heading]
14+
* Extra configuration fields.
15+
* @property {string | null | undefined} [heading]
1016
* Heading to look for, wrapped in `new RegExp('^(' + value + ')$', 'i')`.
1117
*
1218
* @typedef Result
13-
* @property {number|null} index
14-
* @property {number|null} endIndex
15-
* @property {List|null} map
19+
* Results.
20+
* @property {number | null} index
21+
* Where the contents section starts, if looking for a heading.
22+
* @property {number | null} endIndex
23+
* Where the contents section ends, if looking for a heading.
24+
* @property {List | null} map
25+
* Built table of contents (`List`).
1626
*/
1727

1828
import {search} from './search.js'
@@ -32,14 +42,17 @@ import {toExpression} from './to-expression.js'
3242
* Only top-level headings (those not in blockquotes or lists), are used.
3343
* This default behavior can be changed by passing `options.parents`.
3444
*
35-
* @param {Node} node
36-
* @param {Options} [options]
45+
* @param {Node} tree
46+
* Tree to search and generate from.
47+
* @param {Options | null | undefined} [options]
48+
* Configuration.
3749
* @returns {Result}
50+
* Results.
3851
*/
39-
export function toc(node, options) {
52+
export function toc(tree, options) {
4053
const settings = options || {}
41-
const heading = settings.heading ? toExpression(settings.heading) : null
42-
const result = search(node, heading, settings)
54+
const heading = settings.heading ? toExpression(settings.heading) : undefined
55+
const result = search(tree, heading, settings)
4356

4457
return {
4558
index: heading ? result.index : null,

lib/search.js

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,53 @@
11
/**
2-
* @typedef {import('mdast').Root|import('mdast').Content} Node
2+
* @typedef {import('mdast').Root} Root
3+
* @typedef {import('mdast').Content} Content
34
* @typedef {import('mdast').Heading} Heading
45
* @typedef {import('mdast').PhrasingContent} PhrasingContent
5-
* @typedef {string} IsType
6-
* @typedef {Record<string, unknown>} IsProps
7-
* @typedef {import('unist-util-is').TestFunctionAnything} IsTestFunctionAnything
6+
* @typedef {import('unist-util-is').Test} Test
7+
*/
8+
9+
/**
10+
* @typedef {Root | Content} Node
11+
* @typedef {Heading['depth']} Rank
812
*
13+
*/
14+
15+
/**
916
* @typedef SearchOptions
10-
* @property {string} [skip]
17+
* Search configuration.
18+
* @property {string | null | undefined} [skip]
1119
* Headings to skip, wrapped in `new RegExp('^(' + value + ')$', 'i')`.
1220
* Any heading matching this expression will not be present in the table of
1321
* contents.
14-
* @property {IsType|IsProps|IsTestFunctionAnything|Array<IsType|IsProps|IsTestFunctionAnything>} [parents]
22+
* @property {Test} [parents]
1523
* Allow headings to be children of certain node types (default: the to `toc`
1624
* given `tree`, to only allow top-level headings).
25+
*
1726
* Internally, uses `unist-util-is` to check, so `parents` can be any
1827
* `is`-compatible test.
19-
* @property {Heading['depth']} [maxDepth=6]
28+
* @property {Rank | null | undefined} [maxDepth=6]
2029
* Maximum heading depth to include in the table of contents.
30+
*
2131
* This is inclusive: when set to `3`, level three headings are included
2232
* (those with three hashes, `###`).
2333
*
2434
* @typedef SearchEntry
25-
* @property {Heading['depth']} depth
26-
* @property {Array<PhrasingContent>} children
35+
* Entry.
2736
* @property {string} id
37+
* ID of entry.
38+
* @property {Array<PhrasingContent>} children
39+
* Contents of entry.
40+
* @property {Rank} depth
41+
* Rank of entry.
2842
*
2943
* @typedef SearchResult
44+
* Results.
3045
* @property {number} index
46+
* Where the contents section starts, if looking for a heading.
3147
* @property {number} endIndex
48+
* Where the contents section ends, if looking for a heading.
3249
* @property {Array<SearchEntry>} map
50+
* List of entries.
3351
*/
3452

3553
import Slugger from 'github-slugger'
@@ -44,20 +62,20 @@ const slugs = new Slugger()
4462
* Search a node for a toc.
4563
*
4664
* @param {Node} root
47-
* @param {RegExp|null} expression
65+
* @param {RegExp | undefined} expression
4866
* @param {SearchOptions} settings
4967
* @returns {SearchResult}
5068
*/
5169
export function search(root, expression, settings) {
52-
const skip = settings.skip && toExpression(settings.skip)
70+
const skip = settings.skip ? toExpression(settings.skip) : undefined
5371
const parents = convert(settings.parents || ((d) => d === root))
5472
/** @type {Array<SearchEntry>} */
5573
const map = []
56-
/** @type {number|undefined} */
74+
/** @type {number | undefined} */
5775
let index
58-
/** @type {number} */
76+
/** @type {number | undefined} */
5977
let endIndex
60-
/** @type {Heading} */
78+
/** @type {Heading | undefined} */
6179
let opening
6280

6381
slugs.reset()
@@ -103,10 +121,10 @@ export function search(root, expression, settings) {
103121
})
104122

105123
return {
106-
index: index || -1,
124+
index: index === undefined ? -1 : index,
107125
// <sindresorhus/eslint-plugin-unicorn#980>
108126
// @ts-expect-error Looks like a parent.
109-
endIndex: index ? endIndex || root.children.length : -1, // eslint-disable-line unicorn/explicit-length-check
127+
endIndex: index === undefined ? -1 : endIndex || root.children.length, // eslint-disable-line unicorn/explicit-length-check
110128
map
111129
}
112130
}

0 commit comments

Comments
 (0)