1
1
/**
2
- * @typedef Options
3
- * @property {Test } [ignore]
4
- *
5
2
* @typedef {import('hast').Text } Text
6
- * @typedef {import('hast').Parent } Parent
7
3
* @typedef {import('hast').Root } Root
8
4
* @typedef {import('hast').Element } Element
9
5
* @typedef {import('hast').Content } Content
10
- * @typedef {Root|Content } Node
11
- *
12
6
* @typedef {import('hast-util-is-element').Test } Test
13
7
* @typedef {import('unist-util-visit-parents').VisitorResult } VisitorResult
8
+ */
9
+
10
+ /**
11
+ * @typedef {Root | Content } Node
14
12
*
15
13
* @typedef RegExpMatchObject
14
+ * Info on the match.
16
15
* @property {number } index
16
+ * The index of the search at which the result was found.
17
17
* @property {string } input
18
+ * A copy of the search string in the text node.
18
19
* @property {[Root, ...Array<Element>, Text] } stack
20
+ * All ancestors of the text node, where the last node is the text itself.
19
21
*
20
- * @typedef {string|RegExp } Find
21
- * @typedef {string|ReplaceFunction } Replace
22
+ * @callback ReplaceFunction
23
+ * Callback called when a search matches.
24
+ * @param {...any } parameters
25
+ * The parameters are the result of the search expressions, which can be
26
+ * several if a regex captures groups.
27
+ *
28
+ * The last parameter is a `RegExpMatchObject`.
29
+ * @returns {Array<Content> | Content | string | false | undefined | null }
30
+ * Resulting nodes (where `string` is turned into a `Text` node).
22
31
*
32
+ * The values `null` and `undefined` and an empty string mean the match is
33
+ * removed.
34
+ *
35
+ * The value `false` means that this isn’t a match after all, and it is not
36
+ * replaced.
37
+ *
38
+ * @typedef {string | RegExp } Find
39
+ * @typedef {string | ReplaceFunction } Replace
23
40
* @typedef {[Find, Replace] } FindAndReplaceTuple
24
41
* @typedef {Record<string, Replace> } FindAndReplaceSchema
25
42
* @typedef {Array<FindAndReplaceTuple> } FindAndReplaceList
26
- *
27
43
* @typedef {[RegExp, ReplaceFunction] } Pair
28
44
* @typedef {Array<Pair> } Pairs
29
- */
30
-
31
- /**
32
- * @callback ReplaceFunction
33
- * @param {...any } parameters
34
- * @returns {Array<Content>|Content|string|false|undefined|null }
45
+ *
46
+ * @typedef Options
47
+ * Configuration.
48
+ * @property {Test | null | undefined } [ignore]
49
+ * Test for which elements to ignore.
35
50
*/
36
51
37
52
import { visitParents } from 'unist-util-visit-parents'
@@ -43,15 +58,25 @@ const own = {}.hasOwnProperty
43
58
export const defaultIgnore = [ 'title' , 'script' , 'style' , 'svg' , 'math' ]
44
59
45
60
/**
61
+ * Find patterns in a tree and replace them.
62
+ *
63
+ * The algorithm searches the tree in *preorder* for complete values in `Text`
64
+ * nodes.
65
+ * Partial matches are not supported.
66
+ *
46
67
* @param {Node } tree
47
- * @param {Find|FindAndReplaceSchema|FindAndReplaceList } find
48
- * @param {Replace|Options } [replace]
49
- * @param {Options } [options]
68
+ * Tree to change.
69
+ * @param {Find | FindAndReplaceSchema | FindAndReplaceList } find
70
+ * Patterns to find.
71
+ * @param {Replace | Options | null | undefined } [replace]
72
+ * `Replace` (when `find` is `Find`) or configuration.
73
+ * @param {Options | null | undefined } [options]
74
+ * Configuration (when `find` is not `Find`).
50
75
*/
51
76
export function findAndReplace ( tree , find , replace , options ) {
52
- /** @type {Options| undefined } */
77
+ /** @type {Options | null | undefined } */
53
78
let settings
54
- /** @type {FindAndReplaceSchema| FindAndReplaceList } */
79
+ /** @type {FindAndReplaceSchema | FindAndReplaceList } */
55
80
let schema
56
81
57
82
if ( typeof find === 'string' || find instanceof RegExp ) {
@@ -81,7 +106,7 @@ export function findAndReplace(tree, find, replace, options) {
81
106
/** @type {import('unist-util-visit-parents/complex-types.js').BuildVisitor<Node, 'text'> } */
82
107
function visitor ( node , parents ) {
83
108
let index = - 1
84
- /** @type {Root| Element| undefined } */
109
+ /** @type {Root | Element | undefined } */
85
110
let grandparent
86
111
87
112
while ( ++ index < parents . length ) {
@@ -107,9 +132,14 @@ export function findAndReplace(tree, find, replace, options) {
107
132
}
108
133
109
134
/**
135
+ * Handle a text node which is not in an ignored parent.
136
+ *
110
137
* @param {Text } node
111
- * @param {Array<Root|Element> } parents
138
+ * Text node.
139
+ * @param {Array<Root | Element> } parents
140
+ * Parents.
112
141
* @returns {VisitorResult }
142
+ * Result.
113
143
*/
114
144
function handler ( node , parents ) {
115
145
const parent = parents [ parents . length - 1 ]
@@ -120,15 +150,13 @@ export function findAndReplace(tree, find, replace, options) {
120
150
let change = false
121
151
/** @type {Array<Content> } */
122
152
let nodes = [ ]
123
- /** @type {number|undefined } */
124
- let position
125
153
126
154
find . lastIndex = 0
127
155
128
156
let match = find . exec ( node . value )
129
157
130
158
while ( match ) {
131
- position = match . index
159
+ const position = match . index
132
160
/** @type {RegExpMatchObject } */
133
161
const matchObject = {
134
162
index : match . index ,
@@ -180,8 +208,12 @@ export function findAndReplace(tree, find, replace, options) {
180
208
}
181
209
182
210
/**
183
- * @param {FindAndReplaceSchema|FindAndReplaceList } schema
211
+ * Turn a schema into pairs.
212
+ *
213
+ * @param {FindAndReplaceSchema | FindAndReplaceList } schema
214
+ * Schema.
184
215
* @returns {Pairs }
216
+ * Clean pairs.
185
217
*/
186
218
function toPairs ( schema ) {
187
219
/** @type {Pairs } */
@@ -215,16 +247,24 @@ function toPairs(schema) {
215
247
}
216
248
217
249
/**
250
+ * Turn a find into an expression.
251
+ *
218
252
* @param {Find } find
253
+ * Find.
219
254
* @returns {RegExp }
255
+ * Expression.
220
256
*/
221
257
function toExpression ( find ) {
222
258
return typeof find === 'string' ? new RegExp ( escape ( find ) , 'g' ) : find
223
259
}
224
260
225
261
/**
262
+ * Turn a replace into a function.
263
+ *
226
264
* @param {Replace } replace
265
+ * Replace.
227
266
* @returns {ReplaceFunction }
267
+ * Function.
228
268
*/
229
269
function toFunction ( replace ) {
230
270
return typeof replace === 'function' ? replace : ( ) => replace
0 commit comments