Total Complexity | 137 |
Complexity/F | 3.19 |
Lines of Code | 652 |
Function Count | 43 |
Duplicated Lines | 8 |
Ratio | 1.23 % |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like node_modules/readable-stream/lib/_stream_writable.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | // Copyright Joyent, Inc. and other Node contributors. |
||
26 | 'use strict'; |
||
27 | |||
28 | /*<replacement>*/ |
||
29 | |||
30 | var pna = require('process-nextick-args'); |
||
31 | /*</replacement>*/ |
||
32 | |||
33 | module.exports = Writable; |
||
34 | |||
35 | /* <replacement> */ |
||
36 | function WriteReq(chunk, encoding, cb) { |
||
37 | this.chunk = chunk; |
||
38 | this.encoding = encoding; |
||
39 | this.callback = cb; |
||
40 | this.next = null; |
||
41 | } |
||
42 | |||
43 | // It seems a linked list but it is not |
||
44 | // there will be only 2 of these for each stream |
||
45 | function CorkedRequest(state) { |
||
46 | var _this = this; |
||
47 | |||
48 | this.next = null; |
||
49 | this.entry = null; |
||
50 | this.finish = function () { |
||
51 | onCorkedFinish(_this, state); |
||
52 | }; |
||
53 | } |
||
54 | /* </replacement> */ |
||
55 | |||
56 | /*<replacement>*/ |
||
57 | var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick; |
||
|
|||
58 | /*</replacement>*/ |
||
59 | |||
60 | /*<replacement>*/ |
||
61 | var Duplex; |
||
62 | /*</replacement>*/ |
||
63 | |||
64 | Writable.WritableState = WritableState; |
||
65 | |||
66 | /*<replacement>*/ |
||
67 | var util = require('core-util-is'); |
||
68 | util.inherits = require('inherits'); |
||
69 | /*</replacement>*/ |
||
70 | |||
71 | /*<replacement>*/ |
||
72 | var internalUtil = { |
||
73 | deprecate: require('util-deprecate') |
||
74 | }; |
||
75 | /*</replacement>*/ |
||
76 | |||
77 | /*<replacement>*/ |
||
78 | var Stream = require('./internal/streams/stream'); |
||
79 | /*</replacement>*/ |
||
80 | |||
81 | /*<replacement>*/ |
||
82 | |||
83 | var Buffer = require('safe-buffer').Buffer; |
||
84 | var OurUint8Array = global.Uint8Array || function () {}; |
||
85 | function _uint8ArrayToBuffer(chunk) { |
||
86 | return Buffer.from(chunk); |
||
87 | } |
||
88 | function _isUint8Array(obj) { |
||
89 | return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; |
||
90 | } |
||
91 | |||
92 | /*</replacement>*/ |
||
93 | |||
94 | var destroyImpl = require('./internal/streams/destroy'); |
||
95 | |||
96 | util.inherits(Writable, Stream); |
||
97 | |||
98 | function nop() {} |
||
99 | |||
100 | View Code Duplication | function WritableState(options, stream) { |
|
101 | Duplex = Duplex || require('./_stream_duplex'); |
||
102 | |||
103 | options = options || {}; |
||
104 | |||
105 | // Duplex streams are both readable and writable, but share |
||
106 | // the same options object. |
||
107 | // However, some cases require setting options to different |
||
108 | // values for the readable and the writable sides of the duplex stream. |
||
109 | // These options can be provided separately as readableXXX and writableXXX. |
||
110 | var isDuplex = stream instanceof Duplex; |
||
111 | |||
112 | // object stream flag to indicate whether or not this stream |
||
113 | // contains buffers or objects. |
||
114 | this.objectMode = !!options.objectMode; |
||
115 | |||
116 | if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; |
||
117 | |||
118 | // the point at which write() starts returning false |
||
119 | // Note: 0 is a valid value, means that we always return false if |
||
120 | // the entire buffer is not flushed immediately on write() |
||
121 | var hwm = options.highWaterMark; |
||
122 | var writableHwm = options.writableHighWaterMark; |
||
123 | var defaultHwm = this.objectMode ? 16 : 16 * 1024; |
||
124 | |||
125 | if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm; |
||
126 | |||
127 | // cast to ints. |
||
128 | this.highWaterMark = Math.floor(this.highWaterMark); |
||
129 | |||
130 | // if _final has been called |
||
131 | this.finalCalled = false; |
||
132 | |||
133 | // drain event flag. |
||
134 | this.needDrain = false; |
||
135 | // at the start of calling end() |
||
136 | this.ending = false; |
||
137 | // when end() has been called, and returned |
||
138 | this.ended = false; |
||
139 | // when 'finish' is emitted |
||
140 | this.finished = false; |
||
141 | |||
142 | // has it been destroyed |
||
143 | this.destroyed = false; |
||
144 | |||
145 | // should we decode strings into buffers before passing to _write? |
||
146 | // this is here so that some node-core streams can optimize string |
||
147 | // handling at a lower level. |
||
148 | var noDecode = options.decodeStrings === false; |
||
149 | this.decodeStrings = !noDecode; |
||
150 | |||
151 | // Crypto is kind of old and crusty. Historically, its default string |
||
152 | // encoding is 'binary' so we have to make this configurable. |
||
153 | // Everything else in the universe uses 'utf8', though. |
||
154 | this.defaultEncoding = options.defaultEncoding || 'utf8'; |
||
155 | |||
156 | // not an actual buffer we keep track of, but a measurement |
||
157 | // of how much we're waiting to get pushed to some underlying |
||
158 | // socket or file. |
||
159 | this.length = 0; |
||
160 | |||
161 | // a flag to see when we're in the middle of a write. |
||
162 | this.writing = false; |
||
163 | |||
164 | // when true all writes will be buffered until .uncork() call |
||
165 | this.corked = 0; |
||
166 | |||
167 | // a flag to be able to tell if the onwrite cb is called immediately, |
||
168 | // or on a later tick. We set this to true at first, because any |
||
169 | // actions that shouldn't happen until "later" should generally also |
||
170 | // not happen before the first write call. |
||
171 | this.sync = true; |
||
172 | |||
173 | // a flag to know if we're processing previously buffered items, which |
||
174 | // may call the _write() callback in the same tick, so that we don't |
||
175 | // end up in an overlapped onwrite situation. |
||
176 | this.bufferProcessing = false; |
||
177 | |||
178 | // the callback that's passed to _write(chunk,cb) |
||
179 | this.onwrite = function (er) { |
||
180 | onwrite(stream, er); |
||
181 | }; |
||
182 | |||
183 | // the callback that the user supplies to write(chunk,encoding,cb) |
||
184 | this.writecb = null; |
||
185 | |||
186 | // the amount that is being written when _write is called. |
||
187 | this.writelen = 0; |
||
188 | |||
189 | this.bufferedRequest = null; |
||
190 | this.lastBufferedRequest = null; |
||
191 | |||
192 | // number of pending user-supplied write callbacks |
||
193 | // this must be 0 before 'finish' can be emitted |
||
194 | this.pendingcb = 0; |
||
195 | |||
196 | // emit prefinish if the only thing we're waiting for is _write cbs |
||
197 | // This is relevant for synchronous Transform streams |
||
198 | this.prefinished = false; |
||
199 | |||
200 | // True if the error was already emitted and should not be thrown again |
||
201 | this.errorEmitted = false; |
||
202 | |||
203 | // count buffered requests |
||
204 | this.bufferedRequestCount = 0; |
||
205 | |||
206 | // allocate the first CorkedRequest, there is always |
||
207 | // one allocated and free to use, and we maintain at most two |
||
208 | this.corkedRequestsFree = new CorkedRequest(this); |
||
209 | } |
||
210 | |||
211 | WritableState.prototype.getBuffer = function getBuffer() { |
||
212 | var current = this.bufferedRequest; |
||
213 | var out = []; |
||
214 | while (current) { |
||
215 | out.push(current); |
||
216 | current = current.next; |
||
217 | } |
||
218 | return out; |
||
219 | }; |
||
220 | |||
221 | (function () { |
||
222 | try { |
||
223 | Object.defineProperty(WritableState.prototype, 'buffer', { |
||
224 | get: internalUtil.deprecate(function () { |
||
225 | return this.getBuffer(); |
||
226 | }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') |
||
227 | }); |
||
228 | } catch (_) {} |
||
229 | })(); |
||
230 | |||
231 | // Test _writableState for inheritance to account for Duplex streams, |
||
232 | // whose prototype chain only points to Readable. |
||
233 | var realHasInstance; |
||
234 | View Code Duplication | if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { |
|
235 | realHasInstance = Function.prototype[Symbol.hasInstance]; |
||
236 | Object.defineProperty(Writable, Symbol.hasInstance, { |
||
237 | value: function (object) { |
||
238 | if (realHasInstance.call(this, object)) return true; |
||
239 | if (this !== Writable) return false; |
||
240 | |||
241 | return object && object._writableState instanceof WritableState; |
||
242 | } |
||
243 | }); |
||
244 | } else { |
||
245 | realHasInstance = function (object) { |
||
246 | return object instanceof this; |
||
247 | }; |
||
248 | } |
||
249 | |||
250 | View Code Duplication | function Writable(options) { |
|
251 | Duplex = Duplex || require('./_stream_duplex'); |
||
252 | |||
253 | // Writable ctor is applied to Duplexes, too. |
||
254 | // `realHasInstance` is necessary because using plain `instanceof` |
||
255 | // would return false, as no `_writableState` property is attached. |
||
256 | |||
257 | // Trying to use the custom `instanceof` for Writable here will also break the |
||
258 | // Node.js LazyTransform implementation, which has a non-trivial getter for |
||
259 | // `_writableState` that would lead to infinite recursion. |
||
260 | if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { |
||
261 | return new Writable(options); |
||
262 | } |
||
263 | |||
264 | this._writableState = new WritableState(options, this); |
||
265 | |||
266 | // legacy. |
||
267 | this.writable = true; |
||
268 | |||
269 | if (options) { |
||
270 | if (typeof options.write === 'function') this._write = options.write; |
||
271 | |||
272 | if (typeof options.writev === 'function') this._writev = options.writev; |
||
273 | |||
274 | if (typeof options.destroy === 'function') this._destroy = options.destroy; |
||
275 | |||
276 | if (typeof options.final === 'function') this._final = options.final; |
||
277 | } |
||
278 | |||
279 | Stream.call(this); |
||
280 | } |
||
281 | |||
282 | // Otherwise people can pipe Writable streams, which is just wrong. |
||
283 | Writable.prototype.pipe = function () { |
||
284 | this.emit('error', new Error('Cannot pipe, not readable')); |
||
285 | }; |
||
286 | |||
287 | function writeAfterEnd(stream, cb) { |
||
288 | var er = new Error('write after end'); |
||
289 | // TODO: defer error events consistently everywhere, not just the cb |
||
290 | stream.emit('error', er); |
||
291 | pna.nextTick(cb, er); |
||
292 | } |
||
293 | |||
294 | // Checks that a user-supplied chunk is valid, especially for the particular |
||
295 | // mode the stream is in. Currently this means that `null` is never accepted |
||
296 | // and undefined/non-string values are only allowed in object mode. |
||
297 | function validChunk(stream, state, chunk, cb) { |
||
298 | var valid = true; |
||
299 | var er = false; |
||
300 | |||
301 | if (chunk === null) { |
||
302 | er = new TypeError('May not write null values to stream'); |
||
303 | } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { |
||
304 | er = new TypeError('Invalid non-string/buffer chunk'); |
||
305 | } |
||
306 | if (er) { |
||
307 | stream.emit('error', er); |
||
308 | pna.nextTick(cb, er); |
||
309 | valid = false; |
||
310 | } |
||
311 | return valid; |
||
312 | } |
||
313 | |||
314 | View Code Duplication | Writable.prototype.write = function (chunk, encoding, cb) { |
|
315 | var state = this._writableState; |
||
316 | var ret = false; |
||
317 | var isBuf = !state.objectMode && _isUint8Array(chunk); |
||
318 | |||
319 | if (isBuf && !Buffer.isBuffer(chunk)) { |
||
320 | chunk = _uint8ArrayToBuffer(chunk); |
||
321 | } |
||
322 | |||
323 | if (typeof encoding === 'function') { |
||
324 | cb = encoding; |
||
325 | encoding = null; |
||
326 | } |
||
327 | |||
328 | if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; |
||
329 | |||
330 | if (typeof cb !== 'function') cb = nop; |
||
331 | |||
332 | if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { |
||
333 | state.pendingcb++; |
||
334 | ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); |
||
335 | } |
||
336 | |||
337 | return ret; |
||
338 | }; |
||
339 | |||
340 | Writable.prototype.cork = function () { |
||
341 | var state = this._writableState; |
||
342 | |||
343 | state.corked++; |
||
344 | }; |
||
345 | |||
346 | Writable.prototype.uncork = function () { |
||
347 | var state = this._writableState; |
||
348 | |||
349 | if (state.corked) { |
||
350 | state.corked--; |
||
351 | |||
352 | if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); |
||
353 | } |
||
354 | }; |
||
355 | |||
356 | View Code Duplication | Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { |
|
357 | // node::ParseEncoding() requires lower case. |
||
358 | if (typeof encoding === 'string') encoding = encoding.toLowerCase(); |
||
359 | if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); |
||
360 | this._writableState.defaultEncoding = encoding; |
||
361 | return this; |
||
362 | }; |
||
363 | |||
364 | function decodeChunk(state, chunk, encoding) { |
||
365 | if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { |
||
366 | chunk = Buffer.from(chunk, encoding); |
||
367 | } |
||
368 | return chunk; |
||
369 | } |
||
370 | |||
371 | // if we're already writing something, then just put this |
||
372 | // in the queue, and wait our turn. Otherwise, call _write |
||
373 | // If we return false, then we need a drain event, so set that flag. |
||
374 | View Code Duplication | function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { |
|
375 | if (!isBuf) { |
||
376 | var newChunk = decodeChunk(state, chunk, encoding); |
||
377 | if (chunk !== newChunk) { |
||
378 | isBuf = true; |
||
379 | encoding = 'buffer'; |
||
380 | chunk = newChunk; |
||
381 | } |
||
382 | } |
||
383 | var len = state.objectMode ? 1 : chunk.length; |
||
384 | |||
385 | state.length += len; |
||
386 | |||
387 | var ret = state.length < state.highWaterMark; |
||
388 | // we must ensure that previous needDrain will not be reset to false. |
||
389 | if (!ret) state.needDrain = true; |
||
390 | |||
391 | if (state.writing || state.corked) { |
||
392 | var last = state.lastBufferedRequest; |
||
393 | state.lastBufferedRequest = { |
||
394 | chunk: chunk, |
||
395 | encoding: encoding, |
||
396 | isBuf: isBuf, |
||
397 | callback: cb, |
||
398 | next: null |
||
399 | }; |
||
400 | if (last) { |
||
401 | last.next = state.lastBufferedRequest; |
||
402 | } else { |
||
403 | state.bufferedRequest = state.lastBufferedRequest; |
||
404 | } |
||
405 | state.bufferedRequestCount += 1; |
||
406 | } else { |
||
407 | doWrite(stream, state, false, len, chunk, encoding, cb); |
||
408 | } |
||
409 | |||
410 | return ret; |
||
411 | } |
||
412 | |||
413 | function doWrite(stream, state, writev, len, chunk, encoding, cb) { |
||
414 | state.writelen = len; |
||
415 | state.writecb = cb; |
||
416 | state.writing = true; |
||
417 | state.sync = true; |
||
418 | if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); |
||
419 | state.sync = false; |
||
420 | } |
||
421 | |||
422 | function onwriteError(stream, state, sync, er, cb) { |
||
423 | --state.pendingcb; |
||
424 | |||
425 | if (sync) { |
||
426 | // defer the callback if we are being called synchronously |
||
427 | // to avoid piling up things on the stack |
||
428 | pna.nextTick(cb, er); |
||
429 | // this can emit finish, and it will always happen |
||
430 | // after error |
||
431 | pna.nextTick(finishMaybe, stream, state); |
||
432 | stream._writableState.errorEmitted = true; |
||
433 | stream.emit('error', er); |
||
434 | } else { |
||
435 | // the caller expect this to happen before if |
||
436 | // it is async |
||
437 | cb(er); |
||
438 | stream._writableState.errorEmitted = true; |
||
439 | stream.emit('error', er); |
||
440 | // this can emit finish, but finish must |
||
441 | // always follow error |
||
442 | finishMaybe(stream, state); |
||
443 | } |
||
444 | } |
||
445 | |||
446 | function onwriteStateUpdate(state) { |
||
447 | state.writing = false; |
||
448 | state.writecb = null; |
||
449 | state.length -= state.writelen; |
||
450 | state.writelen = 0; |
||
451 | } |
||
452 | |||
453 | function onwrite(stream, er) { |
||
454 | var state = stream._writableState; |
||
455 | var sync = state.sync; |
||
456 | var cb = state.writecb; |
||
457 | |||
458 | onwriteStateUpdate(state); |
||
459 | |||
460 | if (er) onwriteError(stream, state, sync, er, cb);else { |
||
461 | // Check if we're actually ready to finish, but don't emit yet |
||
462 | var finished = needFinish(state); |
||
463 | |||
464 | if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { |
||
465 | clearBuffer(stream, state); |
||
466 | } |
||
467 | |||
468 | if (sync) { |
||
469 | /*<replacement>*/ |
||
470 | asyncWrite(afterWrite, stream, state, finished, cb); |
||
471 | /*</replacement>*/ |
||
472 | } else { |
||
473 | afterWrite(stream, state, finished, cb); |
||
474 | } |
||
475 | } |
||
476 | } |
||
477 | |||
478 | function afterWrite(stream, state, finished, cb) { |
||
479 | if (!finished) onwriteDrain(stream, state); |
||
480 | state.pendingcb--; |
||
481 | cb(); |
||
482 | finishMaybe(stream, state); |
||
483 | } |
||
484 | |||
485 | // Must force callback to be called on nextTick, so that we don't |
||
486 | // emit 'drain' before the write() consumer gets the 'false' return |
||
487 | // value, and has a chance to attach a 'drain' listener. |
||
488 | function onwriteDrain(stream, state) { |
||
489 | if (state.length === 0 && state.needDrain) { |
||
490 | state.needDrain = false; |
||
491 | stream.emit('drain'); |
||
492 | } |
||
493 | } |
||
494 | |||
495 | // if there's something in the buffer waiting, then process it |
||
496 | View Code Duplication | function clearBuffer(stream, state) { |
|
497 | state.bufferProcessing = true; |
||
498 | var entry = state.bufferedRequest; |
||
499 | |||
500 | if (stream._writev && entry && entry.next) { |
||
501 | // Fast case, write everything using _writev() |
||
502 | var l = state.bufferedRequestCount; |
||
503 | var buffer = new Array(l); |
||
504 | var holder = state.corkedRequestsFree; |
||
505 | holder.entry = entry; |
||
506 | |||
507 | var count = 0; |
||
508 | var allBuffers = true; |
||
509 | while (entry) { |
||
510 | buffer[count] = entry; |
||
511 | if (!entry.isBuf) allBuffers = false; |
||
512 | entry = entry.next; |
||
513 | count += 1; |
||
514 | } |
||
515 | buffer.allBuffers = allBuffers; |
||
516 | |||
517 | doWrite(stream, state, true, state.length, buffer, '', holder.finish); |
||
518 | |||
519 | // doWrite is almost always async, defer these to save a bit of time |
||
520 | // as the hot path ends with doWrite |
||
521 | state.pendingcb++; |
||
522 | state.lastBufferedRequest = null; |
||
523 | if (holder.next) { |
||
524 | state.corkedRequestsFree = holder.next; |
||
525 | holder.next = null; |
||
526 | } else { |
||
527 | state.corkedRequestsFree = new CorkedRequest(state); |
||
528 | } |
||
529 | state.bufferedRequestCount = 0; |
||
530 | } else { |
||
531 | // Slow case, write chunks one-by-one |
||
532 | while (entry) { |
||
533 | var chunk = entry.chunk; |
||
534 | var encoding = entry.encoding; |
||
535 | var cb = entry.callback; |
||
536 | var len = state.objectMode ? 1 : chunk.length; |
||
537 | |||
538 | doWrite(stream, state, false, len, chunk, encoding, cb); |
||
539 | entry = entry.next; |
||
540 | state.bufferedRequestCount--; |
||
541 | // if we didn't call the onwrite immediately, then |
||
542 | // it means that we need to wait until it does. |
||
543 | // also, that means that the chunk and cb are currently |
||
544 | // being processed, so move the buffer counter past them. |
||
545 | if (state.writing) { |
||
546 | break; |
||
547 | } |
||
548 | } |
||
549 | |||
550 | if (entry === null) state.lastBufferedRequest = null; |
||
551 | } |
||
552 | |||
553 | state.bufferedRequest = entry; |
||
554 | state.bufferProcessing = false; |
||
555 | } |
||
556 | |||
557 | Writable.prototype._write = function (chunk, encoding, cb) { |
||
558 | cb(new Error('_write() is not implemented')); |
||
559 | }; |
||
560 | |||
561 | Writable.prototype._writev = null; |
||
562 | |||
563 | View Code Duplication | Writable.prototype.end = function (chunk, encoding, cb) { |
|
564 | var state = this._writableState; |
||
565 | |||
566 | if (typeof chunk === 'function') { |
||
567 | cb = chunk; |
||
568 | chunk = null; |
||
569 | encoding = null; |
||
570 | } else if (typeof encoding === 'function') { |
||
571 | cb = encoding; |
||
572 | encoding = null; |
||
573 | } |
||
574 | |||
575 | if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); |
||
576 | |||
577 | // .end() fully uncorks |
||
578 | if (state.corked) { |
||
579 | state.corked = 1; |
||
580 | this.uncork(); |
||
581 | } |
||
582 | |||
583 | // ignore unnecessary end() calls. |
||
584 | if (!state.ending && !state.finished) endWritable(this, state, cb); |
||
585 | }; |
||
586 | |||
587 | function needFinish(state) { |
||
588 | return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; |
||
589 | } |
||
590 | function callFinal(stream, state) { |
||
591 | stream._final(function (err) { |
||
592 | state.pendingcb--; |
||
593 | if (err) { |
||
594 | stream.emit('error', err); |
||
595 | } |
||
596 | state.prefinished = true; |
||
597 | stream.emit('prefinish'); |
||
598 | finishMaybe(stream, state); |
||
599 | }); |
||
600 | } |
||
601 | function prefinish(stream, state) { |
||
602 | if (!state.prefinished && !state.finalCalled) { |
||
603 | if (typeof stream._final === 'function') { |
||
604 | state.pendingcb++; |
||
605 | state.finalCalled = true; |
||
606 | pna.nextTick(callFinal, stream, state); |
||
607 | } else { |
||
608 | state.prefinished = true; |
||
609 | stream.emit('prefinish'); |
||
610 | } |
||
611 | } |
||
612 | } |
||
613 | |||
614 | function finishMaybe(stream, state) { |
||
615 | var need = needFinish(state); |
||
616 | if (need) { |
||
617 | prefinish(stream, state); |
||
618 | if (state.pendingcb === 0) { |
||
619 | state.finished = true; |
||
620 | stream.emit('finish'); |
||
621 | } |
||
622 | } |
||
623 | return need; |
||
624 | } |
||
625 | |||
626 | function endWritable(stream, state, cb) { |
||
627 | state.ending = true; |
||
628 | finishMaybe(stream, state); |
||
629 | if (cb) { |
||
630 | if (state.finished) pna.nextTick(cb);else stream.once('finish', cb); |
||
631 | } |
||
632 | state.ended = true; |
||
633 | stream.writable = false; |
||
634 | } |
||
635 | |||
636 | function onCorkedFinish(corkReq, state, err) { |
||
637 | var entry = corkReq.entry; |
||
638 | corkReq.entry = null; |
||
639 | while (entry) { |
||
640 | var cb = entry.callback; |
||
641 | state.pendingcb--; |
||
642 | cb(err); |
||
643 | entry = entry.next; |
||
644 | } |
||
645 | if (state.corkedRequestsFree) { |
||
646 | state.corkedRequestsFree.next = corkReq; |
||
647 | } else { |
||
648 | state.corkedRequestsFree = corkReq; |
||
649 | } |
||
650 | } |
||
651 | |||
652 | Object.defineProperty(Writable.prototype, 'destroyed', { |
||
653 | get: function () { |
||
654 | if (this._writableState === undefined) { |
||
655 | return false; |
||
656 | } |
||
657 | return this._writableState.destroyed; |
||
658 | }, |
||
659 | set: function (value) { |
||
660 | // we ignore the value if the stream |
||
661 | // has not been initialized yet |
||
662 | if (!this._writableState) { |
||
663 | return; |
||
664 | } |
||
665 | |||
666 | // backward compatibility, the user is explicitly |
||
667 | // managing destroyed |
||
668 | this._writableState.destroyed = value; |
||
669 | } |
||
670 | }); |
||
671 | |||
672 | Writable.prototype.destroy = destroyImpl.destroy; |
||
673 | Writable.prototype._undestroy = destroyImpl.undestroy; |
||
674 | Writable.prototype._destroy = function (err, cb) { |
||
675 | this.end(); |
||
676 | cb(err); |
||
677 | }; |
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.
To learn more about declaring variables in Javascript, see the MDN.