1
1
/**
2
- * @typedef Options
3
- * @property {Test } [ignore]
2
+ * @typedef Options Configuration.
3
+ * @property {Test } [ignore] `unist-util-is` test used to assert parents
4
4
*
5
5
* @typedef {import('mdast').Text } Text
6
6
* @typedef {import('mdast').Parent } Parent
26
26
* @typedef {Array.<Pair> } Pairs
27
27
*/
28
28
29
- /**
30
- * @callback Handler
31
- * @param {Text } node
32
- * @param {Parent } parent
33
- * @returns {VisitorResult }
34
- */
35
-
36
29
/**
37
30
* @callback ReplaceFunction
38
- * @param {...string } parameters
39
- * @param {RegExpMatchObject } matchObject
31
+ * @param {...unknown } parameters
40
32
* @returns {Array.<PhrasingContent>|PhrasingContent|string|false|undefined|null }
41
33
*/
42
34
@@ -47,168 +39,157 @@ import {convert} from 'unist-util-is'
47
39
var own = { } . hasOwnProperty
48
40
49
41
/**
50
- * @param {Node } tree
51
- * @param {Find|FindAndReplaceSchema|FindAndReplaceList } find
52
- * @param {Replace|Options } [replace]
53
- * @param {Options } [options]
42
+ * @param tree mdast tree
43
+ * @param find Value to find and remove. When `string`, escaped and made into a global `RegExp`
44
+ * @param [replace] Value to insert.
45
+ * * When `string`, turned into a Text node.
46
+ * * When `Function`, called with the results of calling `RegExp.exec` as
47
+ * arguments, in which case it can return a single or a list of `Node`,
48
+ * a `string` (which is wrapped in a `Text` node), or `false` to not replace
49
+ * @param [options] Configuration.
54
50
*/
55
- export function findAndReplace ( tree , find , replace , options ) {
56
- /** @type {Options } */
57
- var settings
58
- /** @type {FindAndReplaceSchema|FindAndReplaceList } */
59
- var schema
60
-
61
- if ( typeof find === 'string' || find instanceof RegExp ) {
62
- // @ts -expect-error don’t expect options twice.
63
- schema = [ [ find , replace ] ]
64
- settings = options
65
- } else {
66
- schema = find
67
- // @ts -expect-error don’t expect replace twice.
68
- settings = replace
69
- }
70
-
71
- if ( ! settings ) {
72
- settings = { }
73
- }
74
-
75
- search ( tree , settings , handlerFactory ( toPairs ( schema ) ) )
51
+ export const findAndReplace =
52
+ /**
53
+ * @type {(
54
+ * ((tree: Node, find: Find, replace?: Replace, options?: Options) => Node) &
55
+ * ((tree: Node, schema: FindAndReplaceSchema|FindAndReplaceList, options?: Options) => Node)
56
+ * )}
57
+ **/
58
+ (
59
+ /**
60
+ * @param {Node } tree
61
+ * @param {Find|FindAndReplaceSchema|FindAndReplaceList } find
62
+ * @param {Replace|Options } [replace]
63
+ * @param {Options } [options]
64
+ */
65
+ function ( tree , find , replace , options ) {
66
+ /** @type {Options } */
67
+ var settings
68
+ /** @type {FindAndReplaceSchema|FindAndReplaceList } */
69
+ var schema
70
+
71
+ if ( typeof find === 'string' || find instanceof RegExp ) {
72
+ // @ts -expect-error don’t expect options twice.
73
+ schema = [ [ find , replace ] ]
74
+ settings = options
75
+ } else {
76
+ schema = find
77
+ // @ts -expect-error don’t expect replace twice.
78
+ settings = replace
79
+ }
76
80
77
- return tree
81
+ if ( ! settings ) {
82
+ settings = { }
83
+ }
78
84
79
- /**
80
- * @param {Pairs } pairs
81
- * @returns {Handler }
82
- */
83
- function handlerFactory ( pairs ) {
84
- var pair = pairs [ 0 ]
85
+ var ignored = convert ( settings . ignore || [ ] )
86
+ var pairs = toPairs ( schema )
87
+ var pairIndex = - 1
85
88
86
- return handler
89
+ while ( ++ pairIndex < pairs . length ) {
90
+ visitParents ( tree , 'text' , visitor )
91
+ }
87
92
88
- /**
89
- * @type {Handler }
90
- */
91
- function handler ( node , parent ) {
92
- var find = pair [ 0 ]
93
- var replace = pair [ 1 ]
94
- /** @type {Array.<PhrasingContent> } */
95
- var nodes = [ ]
96
- var start = 0
97
- var index = parent . children . indexOf ( node )
98
- /** @type {number } */
99
- var position
100
- /** @type {RegExpMatchArray } */
101
- var match
102
- /** @type {Handler } */
103
- var subhandler
104
- /** @type {PhrasingContent } */
105
- var child
106
- /** @type {Array.<PhrasingContent>|PhrasingContent|string|false|undefined|null } */
107
- var value
108
-
109
- find . lastIndex = 0
110
-
111
- match = find . exec ( node . value )
112
-
113
- while ( match ) {
114
- position = match . index
115
- // @ts -expect-error this is perfectly fine, typescript.
116
- value = replace ( ...match , { index : position , input : match . input } )
117
-
118
- if ( typeof value === 'string' && value . length > 0 ) {
119
- value = { type : 'text' , value}
120
- }
93
+ return tree
121
94
122
- if ( value !== false ) {
123
- if ( start !== position ) {
124
- nodes . push ( { type : 'text' , value : node . value . slice ( start , position ) } )
125
- }
95
+ /** @type {import('unist-util-visit-parents').Visitor<Text> } */
96
+ function visitor ( node , parents ) {
97
+ var index = - 1
98
+ /** @type {Parent } */
99
+ var parent
100
+ /** @type {Parent } */
101
+ var grandparent
126
102
127
- if ( value ) {
128
- nodes = [ ] . concat ( nodes , value )
103
+ while ( ++ index < parents . length ) {
104
+ // @ts -expect-error mdast vs. unist parent.
105
+ parent = parents [ index ]
106
+
107
+ if (
108
+ ignored (
109
+ parent ,
110
+ // @ts -expect-error mdast vs. unist parent.
111
+ grandparent ? grandparent . children . indexOf ( parent ) : undefined ,
112
+ grandparent
113
+ )
114
+ ) {
115
+ return
129
116
}
130
117
131
- start = position + match [ 0 ] . length
118
+ grandparent = parent
132
119
}
133
120
134
- if ( ! find . global ) {
135
- break
136
- }
121
+ return handler ( node , grandparent )
122
+ }
123
+
124
+ /**
125
+ * @param {Text } node
126
+ * @param {Parent } parent
127
+ * @returns {VisitorResult }
128
+ */
129
+ function handler ( node , parent ) {
130
+ var find = pairs [ pairIndex ] [ 0 ]
131
+ var replace = pairs [ pairIndex ] [ 1 ]
132
+ /** @type {Array.<PhrasingContent> } */
133
+ var nodes = [ ]
134
+ var start = 0
135
+ var index = parent . children . indexOf ( node )
136
+ /** @type {number } */
137
+ var position
138
+ /** @type {RegExpMatchArray } */
139
+ var match
140
+ /** @type {Array.<PhrasingContent>|PhrasingContent|string|false|undefined|null } */
141
+ var value
142
+
143
+ find . lastIndex = 0
137
144
138
145
match = find . exec ( node . value )
139
- }
140
146
141
- if ( position === undefined ) {
142
- nodes = [ node ]
143
- index --
144
- } else {
145
- if ( start < node . value . length ) {
146
- nodes . push ( { type : 'text' , value : node . value . slice ( start ) } )
147
- }
147
+ while ( match ) {
148
+ position = match . index
149
+ // @ts -expect-error this is perfectly fine, typescript.
150
+ value = replace ( ...match , { index : match . index , input : match . input } )
148
151
149
- parent . children . splice ( index , 1 , ...nodes )
150
- }
152
+ if ( typeof value === 'string' && value . length > 0 ) {
153
+ value = { type : 'text' , value}
154
+ }
151
155
152
- if ( pairs . length > 1 ) {
153
- subhandler = handlerFactory ( pairs . slice ( 1 ) )
154
- position = - 1
156
+ if ( value !== false ) {
157
+ if ( start !== position ) {
158
+ nodes . push ( {
159
+ type : 'text' ,
160
+ value : node . value . slice ( start , position )
161
+ } )
162
+ }
155
163
156
- while ( ++ position < nodes . length ) {
157
- child = nodes [ position ]
164
+ if ( value ) {
165
+ nodes = [ ] . concat ( nodes , value )
166
+ }
158
167
159
- if ( child . type === 'text' ) {
160
- subhandler ( child , parent )
161
- } else {
162
- search ( child , settings , subhandler )
168
+ start = position + match [ 0 ] . length
163
169
}
170
+
171
+ if ( ! find . global ) {
172
+ break
173
+ }
174
+
175
+ match = find . exec ( node . value )
164
176
}
165
- }
166
177
167
- return index + nodes . length + 1
168
- }
169
- }
170
- }
178
+ if ( position === undefined ) {
179
+ nodes = [ node ]
180
+ index --
181
+ } else {
182
+ if ( start < node . value . length ) {
183
+ nodes . push ( { type : 'text' , value : node . value . slice ( start ) } )
184
+ }
171
185
172
- /**
173
- * @param {Node } tree
174
- * @param {Options } options
175
- * @param {Handler } handler
176
- * @returns {void }
177
- */
178
- function search ( tree , options , handler ) {
179
- var ignored = convert ( options . ignore || [ ] )
180
-
181
- visitParents ( tree , 'text' , visitor )
182
-
183
- /** @type {import('unist-util-visit-parents').Visitor<Text> } */
184
- function visitor ( node , parents ) {
185
- var index = - 1
186
- /** @type {Parent } */
187
- var parent
188
- /** @type {Parent } */
189
- var grandparent
190
-
191
- while ( ++ index < parents . length ) {
192
- // @ts -expect-error mdast vs. unist parent.
193
- parent = parents [ index ]
194
-
195
- if (
196
- ignored (
197
- parent ,
198
- // @ts -expect-error mdast vs. unist parent.
199
- grandparent ? grandparent . children . indexOf ( parent ) : undefined ,
200
- grandparent
201
- )
202
- ) {
203
- return
204
- }
186
+ parent . children . splice ( index , 1 , ...nodes )
187
+ }
205
188
206
- grandparent = parent
189
+ return index + nodes . length + 1
190
+ }
207
191
}
208
-
209
- return handler ( node , grandparent )
210
- }
211
- }
192
+ )
212
193
213
194
/**
214
195
* @param {FindAndReplaceSchema|FindAndReplaceList } schema
0 commit comments