|
1 | 1 | /** |
2 | | - * @typedef {import('unist').Parent} Parent |
3 | | - * @typedef {import('mdast').Root|import('mdast').Content} Node |
4 | | - * @typedef {import('mdast').Heading} Heading |
5 | | - * |
6 | | - * @typedef {(value: string, node: Heading) => boolean} TestFunction |
7 | | - * Function called for each heading with its content and `node` itself check |
8 | | - * if it’s the one to look for. |
9 | | - * |
10 | | - * @typedef {string|RegExp|TestFunction} Test |
11 | | - * |
12 | | - * @typedef Options |
13 | | - * Configuration (optional). |
14 | | - * @property {Test} test |
15 | | - * Heading to look for. |
16 | | - * When `string`, wrapped in `new RegExp('^(' + value + ')$', 'i')`; |
17 | | - * when `RegExp`, wrapped in `function (value) {expression.test(value)}` |
18 | | - * @property {boolean} [ignoreFinalDefinitions=false] |
19 | | - * Ignore final definitions otherwise in the section. |
20 | | - * |
21 | | - * @typedef ZoneInfo |
22 | | - * Extra info. |
23 | | - * @property {Parent|null} parent |
24 | | - * Parent of the range. |
25 | | - * @property {number} start |
26 | | - * index of `start` in `parent` |
27 | | - * @property {number} end |
28 | | - * index of `end` in `parent` |
29 | | - * |
30 | | - * @callback Handler |
31 | | - * Callback called when a range is found. |
32 | | - * @param {Heading|undefined} start |
33 | | - * Start of range. |
34 | | - * @param {Array<Node>} between |
35 | | - * Nodes between `start` and `end`. |
36 | | - * @param {Node|undefined} end |
37 | | - * End of range, if any. |
38 | | - * @param {ZoneInfo} scope |
39 | | - * Extra info. |
| 2 | + * @typedef {import('./lib/index.js').Handler} Handler |
| 3 | + * @typedef {import('./lib/index.js').Options} Options |
| 4 | + * @typedef {import('./lib/index.js').TestFunction} TestFunction |
| 5 | + * @typedef {import('./lib/index.js').Test} Test |
| 6 | + * @typedef {import('./lib/index.js').ZoneInfo} ZoneInfo |
40 | 7 | */ |
41 | 8 |
|
42 | | -import {toString} from 'mdast-util-to-string' |
43 | | - |
44 | | -/** |
45 | | - * Search `tree` and transform a section without affecting other parts with |
46 | | - * `handler`. |
47 | | - * |
48 | | - * A “section” is a heading that passes `test`, until the next heading of the |
49 | | - * same or lower depth, or the end of the document. |
50 | | - * If `ignoreFinalDefinitions: true`, final definitions “in” the section are |
51 | | - * excluded. |
52 | | - * |
53 | | - * @param {Node} tree |
54 | | - * @param {Test|Options} options |
55 | | - * @param {Handler} handler |
56 | | - */ |
57 | | -// eslint-disable-next-line complexity |
58 | | -export function headingRange(tree, options, handler) { |
59 | | - let test = options |
60 | | - /** @type {Array<Node>} */ |
61 | | - const children = 'children' in tree ? tree.children : [] |
62 | | - /** @type {boolean|undefined} */ |
63 | | - let ignoreFinalDefinitions |
64 | | - |
65 | | - // Object, not regex. |
66 | | - if (test && typeof test === 'object' && !('exec' in test)) { |
67 | | - ignoreFinalDefinitions = test.ignoreFinalDefinitions |
68 | | - test = test.test |
69 | | - } |
70 | | - |
71 | | - // Transform a string into an applicable expression. |
72 | | - if (typeof test === 'string') { |
73 | | - test = new RegExp('^(' + test + ')$', 'i') |
74 | | - } |
75 | | - |
76 | | - // Regex. |
77 | | - if (test && 'exec' in test) { |
78 | | - test = wrapExpression(test) |
79 | | - } |
80 | | - |
81 | | - if (typeof test !== 'function') { |
82 | | - throw new TypeError( |
83 | | - 'Expected `string`, `regexp`, or `function` for `test`, not `' + |
84 | | - test + |
85 | | - '`' |
86 | | - ) |
87 | | - } |
88 | | - |
89 | | - let index = -1 |
90 | | - /** @type {number|undefined} */ |
91 | | - let start |
92 | | - /** @type {number|undefined} */ |
93 | | - let end |
94 | | - /** @type {number|undefined} */ |
95 | | - let depth |
96 | | - |
97 | | - // Find the range. |
98 | | - while (++index < children.length) { |
99 | | - const child = children[index] |
100 | | - |
101 | | - if (child.type === 'heading') { |
102 | | - if (depth && child.depth <= depth) { |
103 | | - end = index |
104 | | - break |
105 | | - } |
106 | | - |
107 | | - if (!depth && test(toString(child), child)) { |
108 | | - depth = child.depth |
109 | | - start = index |
110 | | - // Assume no end heading is found. |
111 | | - end = children.length |
112 | | - } |
113 | | - } |
114 | | - } |
115 | | - |
116 | | - // When we have a starting heading. |
117 | | - if (depth && end !== undefined && start !== undefined) { |
118 | | - if (ignoreFinalDefinitions) { |
119 | | - while ( |
120 | | - children[end - 1].type === 'definition' || |
121 | | - children[end - 1].type === 'footnoteDefinition' |
122 | | - ) { |
123 | | - end-- |
124 | | - } |
125 | | - } |
126 | | - |
127 | | - /** @type {Array<Node>} */ |
128 | | - const nodes = handler( |
129 | | - // @ts-expect-error `start` points to a heading. |
130 | | - children[start], |
131 | | - children.slice(start + 1, end), |
132 | | - children[end], |
133 | | - {parent: tree, start, end: children[end] ? end : null} |
134 | | - ) |
135 | | - |
136 | | - if (nodes) { |
137 | | - // Ensure no empty nodes are inserted. |
138 | | - // This could be the case if `end` is in `nodes` but no `end` node exists. |
139 | | - /** @type {Array<Node>} */ |
140 | | - const result = [] |
141 | | - let index = -1 |
142 | | - |
143 | | - while (++index < nodes.length) { |
144 | | - if (nodes[index]) result.push(nodes[index]) |
145 | | - } |
146 | | - |
147 | | - children.splice(start, end - start + 1, ...result) |
148 | | - } |
149 | | - } |
150 | | -} |
151 | | - |
152 | | -/** |
153 | | - * Wrap an expression into an assertion function. |
154 | | - * @param {RegExp} expression |
155 | | - * @returns {(value: string) => boolean} |
156 | | - */ |
157 | | -function wrapExpression(expression) { |
158 | | - return assertion |
159 | | - |
160 | | - /** |
161 | | - * Assert `value` matches the bound `expression`. |
162 | | - * @param {string} value |
163 | | - * @returns {boolean} |
164 | | - */ |
165 | | - function assertion(value) { |
166 | | - return expression.test(value) |
167 | | - } |
168 | | -} |
| 9 | +export {headingRange} from './lib/index.js' |
0 commit comments