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 59Yallist.prototype.unshiftNode = function (node) { 60 if (node === this.head) { 61 return 62 } 63 64 if (node.list) { 65 node.list.removeNode(node) 66 } 67 68 var head = this.head 69 node.list = this 70 node.next = head 71 if (head) { 72 head.prev = node 73 } 74 75 this.head = node 76 if (!this.tail) { 77 this.tail = node 78 } 79 this.length++ 80} 81 82Yallist.prototype.pushNode = function (node) { 83 if (node === this.tail) { 84 return 85 } 86 87 if (node.list) { 88 node.list.removeNode(node) 89 } 90 91 var tail = this.tail 92 node.list = this 93 node.prev = tail 94 if (tail) { 95 tail.next = node 96 } 97 98 this.tail = node 99 if (!this.head) { 100 this.head = node 101 } 102 this.length++ 103} 104 105Yallist.prototype.push = function () { 106 for (var i = 0, l = arguments.length; i < l; i++) { 107 push(this, arguments[i]) 108 } 109 return this.length 110} 111 112Yallist.prototype.unshift = function () { 113 for (var i = 0, l = arguments.length; i < l; i++) { 114 unshift(this, arguments[i]) 115 } 116 return this.length 117} 118 119Yallist.prototype.pop = function () { 120 if (!this.tail) { 121 return undefined 122 } 123 124 var res = this.tail.value 125 this.tail = this.tail.prev 126 if (this.tail) { 127 this.tail.next = null 128 } else { 129 this.head = null 130 } 131 this.length-- 132 return res 133} 134 135Yallist.prototype.shift = function () { 136 if (!this.head) { 137 return undefined 138 } 139 140 var res = this.head.value 141 this.head = this.head.next 142 if (this.head) { 143 this.head.prev = null 144 } else { 145 this.tail = null 146 } 147 this.length-- 148 return res 149} 150 151Yallist.prototype.forEach = function (fn, thisp) { 152 thisp = thisp || this 153 for (var walker = this.head, i = 0; walker !== null; i++) { 154 fn.call(thisp, walker.value, i, this) 155 walker = walker.next 156 } 157} 158 159Yallist.prototype.forEachReverse = function (fn, thisp) { 160 thisp = thisp || this 161 for (var walker = this.tail, i = this.length - 1; walker !== null; i--) { 162 fn.call(thisp, walker.value, i, this) 163 walker = walker.prev 164 } 165} 166 167Yallist.prototype.get = function (n) { 168 for (var i = 0, walker = this.head; walker !== null && i < n; i++) { 169 // abort out of the list early if we hit a cycle 170 walker = walker.next 171 } 172 if (i === n && walker !== null) { 173 return walker.value 174 } 175} 176 177Yallist.prototype.getReverse = function (n) { 178 for (var i = 0, walker = this.tail; walker !== null && i < n; i++) { 179 // abort out of the list early if we hit a cycle 180 walker = walker.prev 181 } 182 if (i === n && walker !== null) { 183 return walker.value 184 } 185} 186 187Yallist.prototype.map = function (fn, thisp) { 188 thisp = thisp || this 189 var res = new Yallist() 190 for (var walker = this.head; walker !== null;) { 191 res.push(fn.call(thisp, walker.value, this)) 192 walker = walker.next 193 } 194 return res 195} 196 197Yallist.prototype.mapReverse = function (fn, thisp) { 198 thisp = thisp || this 199 var res = new Yallist() 200 for (var walker = this.tail; walker !== null;) { 201 res.push(fn.call(thisp, walker.value, this)) 202 walker = walker.prev 203 } 204 return res 205} 206 207Yallist.prototype.reduce = function (fn, initial) { 208 var acc 209 var walker = this.head 210 if (arguments.length > 1) { 211 acc = initial 212 } else if (this.head) { 213 walker = this.head.next 214 acc = this.head.value 215 } else { 216 throw new TypeError('Reduce of empty list with no initial value') 217 } 218 219 for (var i = 0; walker !== null; i++) { 220 acc = fn(acc, walker.value, i) 221 walker = walker.next 222 } 223 224 return acc 225} 226 227Yallist.prototype.reduceReverse = function (fn, initial) { 228 var acc 229 var walker = this.tail 230 if (arguments.length > 1) { 231 acc = initial 232 } else if (this.tail) { 233 walker = this.tail.prev 234 acc = this.tail.value 235 } else { 236 throw new TypeError('Reduce of empty list with no initial value') 237 } 238 239 for (var i = this.length - 1; walker !== null; i--) { 240 acc = fn(acc, walker.value, i) 241 walker = walker.prev 242 } 243 244 return acc 245} 246 247Yallist.prototype.toArray = function () { 248 var arr = new Array(this.length) 249 for (var i = 0, walker = this.head; walker !== null; i++) { 250 arr[i] = walker.value 251 walker = walker.next 252 } 253 return arr 254} 255 256Yallist.prototype.toArrayReverse = function () { 257 var arr = new Array(this.length) 258 for (var i = 0, walker = this.tail; walker !== null; i++) { 259 arr[i] = walker.value 260 walker = walker.prev 261 } 262 return arr 263} 264 265Yallist.prototype.slice = function (from, to) { 266 to = to || this.length 267 if (to < 0) { 268 to += this.length 269 } 270 from = from || 0 271 if (from < 0) { 272 from += this.length 273 } 274 var ret = new Yallist() 275 if (to < from || to < 0) { 276 return ret 277 } 278 if (from < 0) { 279 from = 0 280 } 281 if (to > this.length) { 282 to = this.length 283 } 284 for (var i = 0, walker = this.head; walker !== null && i < from; i++) { 285 walker = walker.next 286 } 287 for (; walker !== null && i < to; i++, walker = walker.next) { 288 ret.push(walker.value) 289 } 290 return ret 291} 292 293Yallist.prototype.sliceReverse = function (from, to) { 294 to = to || this.length 295 if (to < 0) { 296 to += this.length 297 } 298 from = from || 0 299 if (from < 0) { 300 from += this.length 301 } 302 var ret = new Yallist() 303 if (to < from || to < 0) { 304 return ret 305 } 306 if (from < 0) { 307 from = 0 308 } 309 if (to > this.length) { 310 to = this.length 311 } 312 for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) { 313 walker = walker.prev 314 } 315 for (; walker !== null && i > from; i--, walker = walker.prev) { 316 ret.push(walker.value) 317 } 318 return ret 319} 320 321Yallist.prototype.reverse = function () { 322 var head = this.head 323 var tail = this.tail 324 for (var walker = head; walker !== null; walker = walker.prev) { 325 var p = walker.prev 326 walker.prev = walker.next 327 walker.next = p 328 } 329 this.head = tail 330 this.tail = head 331 return this 332} 333 334function push (self, item) { 335 self.tail = new Node(item, self.tail, null, self) 336 if (!self.head) { 337 self.head = self.tail 338 } 339 self.length++ 340} 341 342function unshift (self, item) { 343 self.head = new Node(item, null, self.head, self) 344 if (!self.tail) { 345 self.tail = self.head 346 } 347 self.length++ 348} 349 350function Node (value, prev, next, list) { 351 if (!(this instanceof Node)) { 352 return new Node(value, prev, next, list) 353 } 354 355 this.list = list 356 this.value = value 357 358 if (prev) { 359 prev.next = this 360 this.prev = prev 361 } else { 362 this.prev = null 363 } 364 365 if (next) { 366 next.prev = this 367 this.next = next 368 } else { 369 this.next = null 370 } 371} 372 373try { 374 // add if support for Symbol.iterator is present 375 require('./iterator.js')(Yallist) 376} catch (er) {} 377