function onwrite(stream, er) { var state = stream._writableState; var sync = state.sync; var cb = state.writecb; onwriteStateUpdate(state); if (er) onwriteError(stream, state, sync, er, cb); else { // Check if we're actually ready to finish, but don't emit yet var finished = needFinish(stream, state); if (!finished && !state.bufferProcessing && state.buffer.length) clearBuffer(stream, state); if (sync) { setImmediate(function() { afterWrite(stream, state, finished, cb); }); } else { afterWrite(stream, state, finished, cb); } } }
Cursor.prototype[ NS.doTimers ] = function ( forceDelay ) { const self = this , delay = self[ NS.delayTime ] , time = now() if ( self[ NS.hold ] ) return false self[ NS.clearTimers ]() const release = self.release.bind( self ) self[ NS.firstTrigger ] = self[ NS.firstTrigger ] || time const triggerAge = time - self[ NS.firstTrigger ] if ( self.delayMax && self.delayMax < triggerAge ) { release() } else if ( delayIsTimeout( delay ) ) { self[ NS.timeout ] = setTimeout( release, delay ) } else if ( delayIsImmediate( delay ) && forceDelay ) { self[ NS.immediate ] = setImmediate( release ) } else { release() } }
// at this point, the user has presumably seen the 'readable' event, // and called read() to consume some data. that may have triggered // in turn another _read(n) call, in which case reading = true if // it's in progress. // However, if we're not ended, or reading, and the length < hwm, // then go ahead and try to read some more preemptively. function maybeReadMore(stream, state) { if (!state.readingMore) { state.readingMore = true; setImmediate(function() { maybeReadMore_(stream, state); }); } }
function writeAfterEnd(stream, state, cb) { var er = new Error('write after end'); // TODO: defer error events consistently everywhere, not just the cb stream.emit('error', er); setImmediate(function() { cb(er); }); }
/** * Schedule an asynchronous update to the interaction state. */ function _scheduleUpdate() { if (!_nextUpdateHandle) { if (_deadline > 0) { _nextUpdateHandle = setTimeout(_processUpdate, 0); } else { _nextUpdateHandle = setImmediate(_processUpdate); } } }
stream.resume = function() { paused = false; if (readable) setImmediate(function() { stream.emit('readable'); }); else this.read(0); this.emit('resume'); };
function onwriteError(stream, state, sync, er, cb) { if (sync) setImmediate(function() { cb(er); }); else cb(er); stream.emit('error', er); }
function endWritable(stream, state, cb) { state.ending = true; finishMaybe(stream, state); if (cb) { if (state.finished) setImmediate(cb); else stream.once('finish', cb); } state.ended = true; }
// the no-half-open enforcer function onend() { // if we allow half-open state, or if the writable side ended, // then we're ok. if (this.allowHalfOpen || this._writableState.ended) return; // no more data can be written. // But allow more writes to happen in this tick. var self = this; setImmediate(function () { self.end(); }); }
// Don't emit readable right away in sync mode, because this can trigger // another read() call => stack overflow. This way, it might trigger // a nextTick recursion warning, but that's not so bad. function emitReadable(stream) { var state = stream._readableState; state.needReadable = false; if (state.emittedReadable) return; state.emittedReadable = true; if (state.sync) setImmediate(function() { emitReadable_(stream); }); else emitReadable_(stream); }
// If we get something that is not a buffer, string, null, or undefined, // and we're not in objectMode, then that's an error. // Otherwise stream chunks are all considered to be of length=1, and the // watermarks determine how many objects to keep in the buffer, rather than // how many bytes or characters. function validChunk(stream, state, chunk, cb) { var valid = true; if (!Buffer.isBuffer(chunk) && 'string' !== typeof chunk && chunk !== null && chunk !== undefined && !state.objectMode) { var er = new TypeError('Invalid non-string/buffer chunk'); stream.emit('error', er); setImmediate(function() { cb(er); }); valid = false; } return valid; }
function endReadable(stream) { var state = stream._readableState; // If we get here before consuming all the bytes, then that is a // bug in node. Should never happen. if (state.length > 0) throw new Error('endReadable called on non-empty stream'); if (!state.endEmitted && state.calledRead) { state.ended = true; setImmediate(function() { // Check that we didn't get one last unshift. if (!state.endEmitted && state.length === 0) { state.endEmitted = true; stream.readable = false; stream.emit('end'); } }); } }
/** * Schedule an asynchronous update to the interaction state. */ function scheduleUpdate() { if (!_nextUpdateHandle) { _nextUpdateHandle = setImmediate(processUpdate); } }
Readable.prototype.pipe = function(dest, pipeOpts) { var src = this; var state = this._readableState; switch (state.pipesCount) { case 0: state.pipes = dest; break; case 1: state.pipes = [state.pipes, dest]; break; default: state.pipes.push(dest); break; } state.pipesCount += 1; var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; var endFn = doEnd ? onend : cleanup; if (state.endEmitted) setImmediate(endFn); else src.once('end', endFn); dest.on('unpipe', onunpipe); function onunpipe(readable) { if (readable !== src) return; cleanup(); } function onend() { dest.end(); } // when the dest drains, it reduces the awaitDrain counter // on the source. This would be more elegant with a .once() // handler in flow(), but adding and removing repeatedly is // too slow. var ondrain = pipeOnDrain(src); dest.on('drain', ondrain); function cleanup() { // cleanup event handlers once the pipe is broken dest.removeListener('close', onclose); dest.removeListener('finish', onfinish); dest.removeListener('drain', ondrain); dest.removeListener('error', onerror); dest.removeListener('unpipe', onunpipe); src.removeListener('end', onend); src.removeListener('end', cleanup); // if the reader is waiting for a drain event from this // specific writer, then it would cause it to never start // flowing again. // So, if this is awaiting a drain, then we just call it now. // If we don't know, then assume that we are waiting for one. if (!dest._writableState || dest._writableState.needDrain) ondrain(); } // if the dest has an error, then stop piping into it. // however, don't suppress the throwing behavior for this. // check for listeners before emit removes one-time listeners. var errListeners = EE.listenerCount(dest, 'error'); function onerror(er) { unpipe(); if (errListeners === 0 && EE.listenerCount(dest, 'error') === 0) dest.emit('error', er); } dest.once('error', onerror); // Both close and finish should trigger unpipe, but only once. function onclose() { dest.removeListener('finish', onfinish); unpipe(); } dest.once('close', onclose); function onfinish() { dest.removeListener('close', onclose); unpipe(); } dest.once('finish', onfinish); function unpipe() { src.unpipe(dest); } // tell the dest that it's being piped to dest.emit('pipe', src); // start the flow if it hasn't been started already. if (!state.flowing) { // the handler that waits for readable events after all // the data gets sucked out in flow. // This would be easier to follow with a .once() handler // in flow(), but that is too slow. this.on('readable', pipeOnReadable); state.flowing = true; setImmediate(function() { flow(src); }); } return dest; };
/** * When `onBeforeInput` executes, the browser is attempting to insert a * character into the editor. Apply this character data to the document, * allowing native insertion if possible. * * Native insertion is encouraged in order to limit re-rendering and to * preserve spellcheck highlighting, which disappears or flashes if re-render * occurs on the relevant text nodes. */ function editOnBeforeInput(editor: DraftEditor, e: SyntheticInputEvent): void { if (editor._pendingStateFromBeforeInput !== undefined) { editor.update(editor._pendingStateFromBeforeInput); editor._pendingStateFromBeforeInput = undefined; } const editorState = editor._latestEditorState; var chars = e.data; // In some cases (ex: IE ideographic space insertion) no character data // is provided. There's nothing to do when this happens. if (!chars) { return; } // Allow the top-level component to handle the insertion manually. This is // useful when triggering interesting behaviors for a character insertion, // Simple examples: replacing a raw text ':)' with a smile emoji or image // decorator, or setting a block to be a list item after typing '- ' at the // start of the block. if ( editor.props.handleBeforeInput && isEventHandled(editor.props.handleBeforeInput(chars, editorState)) ) { e.preventDefault(); return; } // If selection is collapsed, conditionally allow native behavior. This // reduces re-renders and preserves spellcheck highlighting. If the selection // is not collapsed, we will re-render. var selection = editorState.getSelection(); var anchorKey = selection.getAnchorKey(); if (!selection.isCollapsed()) { e.preventDefault(); editor.update( replaceText( editorState, chars, editorState.getCurrentInlineStyle(), getEntityKeyForSelection( editorState.getCurrentContent(), editorState.getSelection(), ), ), ); return; } var newEditorState = replaceText( editorState, chars, editorState.getCurrentInlineStyle(), getEntityKeyForSelection( editorState.getCurrentContent(), editorState.getSelection(), ), ); // Bunch of different cases follow where we need to prevent native insertion. let mustPreventNative = false; if (!mustPreventNative) { // Browsers tend to insert text in weird places in the DOM when typing at // the start of a leaf, so we'll handle it ourselves. mustPreventNative = isSelectionAtLeafStart( editor._latestCommittedEditorState, ); } if (!mustPreventNative) { // Chrome will also split up a node into two pieces if it contains a Tab // char, for no explicable reason. Seemingly caused by this commit: // https://chromium.googlesource.com/chromium/src/+/013ac5eaf3%5E%21/ const nativeSelection = global.getSelection(); // Selection is necessarily collapsed at this point due to earlier check. if ( nativeSelection.anchorNode !== null && nativeSelection.anchorNode.nodeType === Node.TEXT_NODE ) { // See isTabHTMLSpanElement in chromium EditingUtilities.cpp. const parentNode = nativeSelection.anchorNode.parentNode; mustPreventNative = parentNode.nodeName === 'SPAN' && parentNode.firstChild.nodeType === Node.TEXT_NODE && parentNode.firstChild.nodeValue.indexOf('\t') !== -1; } } if (!mustPreventNative) { // Check the old and new "fingerprints" of the current block to determine // whether this insertion requires any addition or removal of text nodes, // in which case we would prevent the native character insertion. var originalFingerprint = BlockTree.getFingerprint( editorState.getBlockTree(anchorKey), ); var newFingerprint = BlockTree.getFingerprint( newEditorState.getBlockTree(anchorKey), ); mustPreventNative = originalFingerprint !== newFingerprint; } if (!mustPreventNative) { mustPreventNative = mustPreventDefaultForCharacter(chars); } if (!mustPreventNative) { mustPreventNative = nullthrows(newEditorState.getDirectionMap()).get(anchorKey) !== nullthrows(editorState.getDirectionMap()).get(anchorKey); } if (mustPreventNative) { e.preventDefault(); editor.update(newEditorState); return; } // We made it all the way! Let the browser do its thing and insert the char. newEditorState = EditorState.set(newEditorState, { nativelyRenderedContent: newEditorState.getCurrentContent(), }); // The native event is allowed to occur. To allow user onChange handlers to // change the inserted text, we wait until the text is actually inserted // before we actually update our state. That way when we rerender, the text // we see in the DOM will already have been inserted properly. editor._pendingStateFromBeforeInput = newEditorState; setImmediate(() => { if (editor._pendingStateFromBeforeInput !== undefined) { editor.update(editor._pendingStateFromBeforeInput); editor._pendingStateFromBeforeInput = undefined; } }); }
/** * Throws the supplied error in a new execution loop. * * @param {*} error */ function throwImmediate(error) { setImmediate(throwArg, error); }