|
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