UNPKG

7.4 kBJavaScriptView Raw
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) {}