11/**
2- * @typedef Options
3- * @property {Test } [ignore]
2+ * @typedef Options Configuration.
3+ * @property {Test } [ignore] `unist-util-is` test used to assert parents
44 *
55 * @typedef {import('mdast').Text } Text
66 * @typedef {import('mdast').Parent } Parent
2626 * @typedef {Array.<Pair> } Pairs
2727 */
2828
29- /**
30- * @callback Handler
31- * @param {Text } node
32- * @param {Parent } parent
33- * @returns {VisitorResult }
34- */
35-
3629/**
3730 * @callback ReplaceFunction
38- * @param {...string } parameters
39- * @param {RegExpMatchObject } matchObject
31+ * @param {...unknown } parameters
4032 * @returns {Array.<PhrasingContent>|PhrasingContent|string|false|undefined|null }
4133 */
4234
@@ -47,168 +39,157 @@ import {convert} from 'unist-util-is'
4739var own = { } . hasOwnProperty
4840
4941/**
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.
5450 */
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+ }
7680
77- return tree
81+ if ( ! settings ) {
82+ settings = { }
83+ }
7884
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
8588
86- return handler
89+ while ( ++ pairIndex < pairs . length ) {
90+ visitParents ( tree , 'text' , visitor )
91+ }
8792
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
12194
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
126102
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
129116 }
130117
131- start = position + match [ 0 ] . length
118+ grandparent = parent
132119 }
133120
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
137144
138145 match = find . exec ( node . value )
139- }
140146
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 } )
148151
149- parent . children . splice ( index , 1 , ...nodes )
150- }
152+ if ( typeof value === 'string' && value . length > 0 ) {
153+ value = { type : 'text' , value}
154+ }
151155
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+ }
155163
156- while ( ++ position < nodes . length ) {
157- child = nodes [ position ]
164+ if ( value ) {
165+ nodes = [ ] . concat ( nodes , value )
166+ }
158167
159- if ( child . type === 'text' ) {
160- subhandler ( child , parent )
161- } else {
162- search ( child , settings , subhandler )
168+ start = position + match [ 0 ] . length
163169 }
170+
171+ if ( ! find . global ) {
172+ break
173+ }
174+
175+ match = find . exec ( node . value )
164176 }
165- }
166177
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+ }
171185
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+ }
205188
206- grandparent = parent
189+ return index + nodes . length + 1
190+ }
207191 }
208-
209- return handler ( node , grandparent )
210- }
211- }
192+ )
212193
213194/**
214195 * @param {FindAndReplaceSchema|FindAndReplaceList } schema
0 commit comments