| 177 | } |
| 178 | |
| 179 | _insert(item) { |
| 180 | this._resetCompilation(); |
| 181 | const { taps } = this; |
| 182 | const stage = typeof item.stage === "number" ? item.stage : 0; |
| 183 | |
| 184 | // Fast path: the overwhelmingly common `hook.tap("name", fn)` case |
| 185 | // has no `before` and default stage 0. If the list is empty or the |
| 186 | // last tap's stage is <= the new item's stage the item belongs at |
| 187 | // the end - append in O(1), skipping the Set allocation and the |
| 188 | // shift loop. |
| 189 | if (!(typeof item.before === "string" || Array.isArray(item.before))) { |
| 190 | const n = taps.length; |
| 191 | if (n === 0 || (taps[n - 1].stage || 0) <= stage) { |
| 192 | taps[n] = item; |
| 193 | return; |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | let before; |
| 198 | |
| 199 | if (typeof item.before === "string") { |
| 200 | before = new Set([item.before]); |
| 201 | } else if (Array.isArray(item.before)) { |
| 202 | before = new Set(item.before); |
| 203 | } |
| 204 | |
| 205 | let i = taps.length; |
| 206 | |
| 207 | while (i > 0) { |
| 208 | i--; |
| 209 | const tap = taps[i]; |
| 210 | taps[i + 1] = tap; |
| 211 | const xStage = tap.stage || 0; |
| 212 | if (before) { |
| 213 | if (before.has(tap.name)) { |
| 214 | before.delete(tap.name); |
| 215 | continue; |
| 216 | } |
| 217 | if (before.size > 0) { |
| 218 | continue; |
| 219 | } |
| 220 | } |
| 221 | if (xStage > stage) { |
| 222 | continue; |
| 223 | } |
| 224 | i++; |
| 225 | break; |
| 226 | } |
| 227 | taps[i] = item; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | Object.setPrototypeOf(Hook.prototype, null); |