syntax-tree / mdast-util-find-and-replace

Compare 306095d ... +1 ... 7357886

Coverage Reach
index.js

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.

Showing 1 of 3 files from the diff.
Other files ignored by Codecov
package.json has changed.
test.js has changed.

@@ -1,6 +1,6 @@
Loading
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,17 +26,9 @@
Loading
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 @@
Loading
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

Everything is accounted for!

No changes detected that need to be reviewed.
What changes does Codecov check for?
Lines, not adjusted in diff, that have changed coverage data.
Files that introduced coverage data that had none before.
Files that have missing coverage data that once were tracked.
Files Coverage
index.js 100.00%
Project Totals (1 files) 100.00%
Loading