1'use strict' 2module.exports = Yallist 3 4Yallist.Node = Node 5Yallist.create = Yallist 6 7function Yallist (list) { 8 var self = this 9 if (!(self instanceof Yallist)) { 10 self = new Yallist() 11 } 12 13 self.tail = null 14 self.head = null 15 self.length = 0 16 17 if (list && typeof list.forEach === 'function') { 18 list.forEach(function (item) { 19 self.push(item) 20 }) 21 } else if (arguments.length > 0) { 22 for (var i = 0, l = arguments.length; i < l; i++) { 23 self.push(arguments[i]) 24 } 25 } 26 27 return self 28} 29 30Yallist.prototype.removeNode = function (node) { 31 if (node.list !== this) { 32 throw new Error('removing node which does not belong to this list') 33 } 34 35 var next = node.next 36 var prev = node.prev 37 38 if (next) { 39 next.prev = prev 40 } 41 42 if (prev) { 43 prev.next = next 44 } 45 46 if (node === this.head) { 47 this.head = next 48 } 49 if (node === this.tail) { 50 this.tail = prev 51 } 52 53 node.list.length-- 54 node.next = null 55 node.prev = null 56 node.list = null 57 58 return next 59} 60 61Yallist.prototype.unshiftNode = function (node) { 62 if (node === this.head) { 63 return 64 } 65 66 if (node.list) { 67 node.list.removeNode(node) 68 } 69 70 var head = this.head 71 node.list = this 72 node.next = head 73 if (head) { 74 head.prev = node 75 } 76 77 this.head = node 78 if (!this.tail) { 79 this.tail = node 80 } 81 this.length++ 82} 83 84Yallist.prototype.pushNode = function (node) { 85 if (node === this.tail) { 86 return 87 } 88 89 if (node.list) { 90 node.list.removeNode(node) 91 } 92 93 var tail = this.tail 94 node.list = this 95 node.prev = tail 96 if (tail) { 97 tail.next = node 98 } 99 100 this.tail = node 101 if (!this.head) { 102 this.head = node 103 } 104 this.length++ 105} 106 107Yallist.prototype.push = function () { 108 for (var i = 0, l = arguments.length; i < l; i++) { 109 push(this, arguments[i]) 110 } 111 return this.length 112} 113 114Yallist.prototype.unshift = function () { 115 for (var i = 0, l = arguments.length; i < l; i++) { 116 unshift(this, arguments[i]) 117 } 118 return this.length 119} 120 121Yallist.prototype.pop = function () { 122 if (!this.tail) { 123 return undefined 124 } 125 126 var res = this.tail.value 127 this.tail = this.tail.prev 128 if (this.tail) { 129 this.tail.next = null 130 } else { 131 this.head = null 132 } 133 this.length-- 134 return res 135} 136 137Yallist.prototype.shift = function () { 138 if (!this.head) { 139 return undefined 140 } 141 142 var res = this.head.value 143 this.head = this.head.next 144 if (this.head) { 145 this.head.prev = null 146 } else { 147 this.tail = null 148 } 149 this.length-- 150 return res 151} 152 153Yallist.prototype.forEach = function (fn, thisp) { 154 thisp = thisp || this 155 for (var walker = this.head, i = 0; walker !== null; i++) { 156 fn.call(thisp, walker.value, i, this) 157 walker = walker.next 158 } 159} 160 161Yallist.prototype.forEachReverse = function (fn, thisp) { 162 thisp = thisp || this 163 for (var walker = this.tail, i = this.length - 1; walker !== null; i--) { 164 fn.call(thisp, walker.value, i, this) 165 walker = walker.prev 166 } 167} 168 169Yallist.prototype.get = function (n) { 170 for (var i = 0, walker = this.head; walker !== null && i < n; i++) { 171 // abort out of the list early if we hit a cycle 172 walker = walker.next 173 } 174 if (i === n && walker !== null) { 175 return walker.value 176 } 177} 178 179Yallist.prototype.getReverse = function (n) { 180 for (var i = 0, walker = this.tail; walker !== null && i < n; i++) { 181 // abort out of the list early if we hit a cycle 182 walker = walker.prev 183 } 184 if (i === n && walker !== null) { 185 return walker.value 186 } 187} 188 189Yallist.prototype.map = function (fn, thisp) { 190 thisp = thisp || this 191 var res = new Yallist() 192 for (var walker = this.head; walker !== null;) { 193 res.push(fn.call(thisp, walker.value, this)) 194 walker = walker.next 195 } 196 return res 197} 198 199Yallist.prototype.mapReverse = function (fn, thisp) { 200 thisp = thisp || this 201 var res = new Yallist() 202 for (var walker = this.tail; walker !== null;) { 203 res.push(fn.call(thisp, walker.value, this)) 204 walker = walker.prev 205 } 206 return res 207} 208 209Yallist.prototype.reduce = function (fn, initial) { 210 var acc 211 var walker = this.head 212 if (arguments.length > 1) { 213 acc = initial 214 } else if (this.head) { 215 walker = this.head.next 216 acc = this.head.value 217 } else { 218 throw new TypeError('Reduce of empty list with no initial value') 219 } 220 221 for (var i = 0; walker !== null; i++) { 222 acc = fn(acc, walker.value, i) 223 walker = walker.next 224 } 225 226 return acc 227} 228 229Yallist.prototype.reduceReverse = function (fn, initial) { 230 var acc 231 var walker = this.tail 232 if (arguments.length > 1) { 233 acc = initial 234 } else if (this.tail) { 235 walker = this.tail.prev 236 acc = this.tail.value 237 } else { 238 throw new TypeError('Reduce of empty list with no initial value') 239 } 240 241 for (var i = this.length - 1; walker !== null; i--) { 242 acc = fn(acc, walker.value, i) 243 walker = walker.prev 244 } 245 246 return acc 247} 248 249Yallist.prototype.toArray = function () { 250 var arr = new Array(this.length) 251 for (var i = 0, walker = this.head; walker !== null; i++) { 252 arr[i] = walker.value 253 walker = walker.next 254 } 255 return arr 256} 257 258Yallist.prototype.toArrayReverse = function () { 259 var arr = new Array(this.length) 260 for (var i = 0, walker = this.tail; walker !== null; i++) { 261 arr[i] = walker.value 262 walker = walker.prev 263 } 264 return arr 265} 266 267Yallist.prototype.slice = function (from, to) { 268 to = to || this.length 269 if (to < 0) { 270 to += this.length 271 } 272 from = from || 0 273 if (from < 0) { 274 from += this.length 275 } 276 var ret = new Yallist() 277 if (to < from || to < 0) { 278 return ret 279 } 280 if (from < 0) { 281 from = 0 282 } 283 if (to > this.length) { 284 to = this.length 285 } 286 for (var i = 0, walker = this.head; walker !== null && i < from; i++) { 287 walker = walker.next 288 } 289 for (; walker !== null && i < to; i++, walker = walker.next) { 290 ret.push(walker.value) 291 } 292 return ret 293} 294 295Yallist.prototype.sliceReverse = function (from, to) { 296 to = to || this.length 297 if (to < 0) { 298 to += this.length 299 } 300 from = from || 0 301 if (from < 0) { 302 from += this.length 303 } 304 var ret = new Yallist() 305 if (to < from || to < 0) { 306 return ret 307 } 308 if (from < 0) { 309 from = 0 310 } 311 if (to > this.length) { 312 to = this.length 313 } 314 for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) { 315 walker = walker.prev 316 } 317 for (; walker !== null && i > from; i--, walker = walker.prev) { 318 ret.push(walker.value) 319 } 320 return ret 321} 322 323Yallist.prototype.splice = function (start, deleteCount, ...nodes) { 324 if (start > this.length) { 325 start = this.length - 1 326 } 327 if (start < 0) { 328 start = this.length + start; 329 } 330 331 for (var i = 0, walker = this.head; walker !== null && i < start; i++) { 332 walker = walker.next 333 } 334 335 var ret = [] 336 for (var i = 0; walker && i < deleteCount; i++) { 337 ret.push(walker.value) 338 walker = this.removeNode(walker) 339 } 340 if (walker === null) { 341 walker = this.tail 342 } 343 344 if (walker !== this.head && walker !== this.tail) { 345 walker = walker.prev 346 } 347 348 for (var i = 0; i < nodes.length; i++) { 349 walker = insert(this, walker, nodes[i]) 350 } 351 return ret; 352} 353 354Yallist.prototype.reverse = function () { 355 var head = this.head 356 var tail = this.tail 357 for (var walker = head; walker !== null; walker = walker.prev) { 358 var p = walker.prev 359 walker.prev = walker.next 360 walker.next = p 361 } 362 this.head = tail 363 this.tail = head 364 return this 365} 366 367function insert (self, node, value) { 368 var inserted = node === self.head ? 369 new Node(value, null, node, self) : 370 new Node(value, node, node.next, self) 371 372 if (inserted.next === null) { 373 self.tail = inserted 374 } 375 if (inserted.prev === null) { 376 self.head = inserted 377 } 378 379 self.length++ 380 381 return inserted 382} 383 384function push (self, item) { 385 self.tail = new Node(item, self.tail, null, self) 386 if (!self.head) { 387 self.head = self.tail 388 } 389 self.length++ 390} 391 392function unshift (self, item) { 393 self.head = new Node(item, null, self.head, self) 394 if (!self.tail) { 395 self.tail = self.head 396 } 397 self.length++ 398} 399 400function Node (value, prev, next, list) { 401 if (!(this instanceof Node)) { 402 return new Node(value, prev, next, list) 403 } 404 405 this.list = list 406 this.value = value 407 408 if (prev) { 409 prev.next = this 410 this.prev = prev 411 } else { 412 this.prev = null 413 } 414 415 if (next) { 416 next.prev = this 417 this.next = next 418 } else { 419 this.next = null 420 } 421} 422 423try { 424 // add if support for Symbol.iterator is present 425 require('./iterator.js')(Yallist) 426} catch (er) {} 427