/**
   * Collapses all selected directory nodes. If the selection is a single file or a single collapsed
   * directory, the selection is set to the directory's parent.
   */
  _collapseSelection(deep: boolean = false): void {
    const selectedNodes = this._store.getSelectedNodes();
    const firstSelectedNode = nullthrows(selectedNodes.first());
    if (
      selectedNodes.size === 1 &&
      !firstSelectedNode.isRoot &&
      !(firstSelectedNode.isContainer && firstSelectedNode.isExpanded)
    ) {
      /*
       * Select the parent of the selection if the following criteria are met:
       *   * Only 1 node is selected
       *   * The node is not a root
       *   * The node is not an expanded directory
      */

      const parent = nullthrows(firstSelectedNode.parent);
      this._selectAndTrackNode(parent);
    } else {
      selectedNodes.forEach(node => {
        // Only directories can be expanded. Skip non-directory nodes.
        if (!node.isContainer) {
          return;
        }

        if (deep) {
          this._actions.collapseNodeDeep(node.rootUri, node.uri);
        } else {
          this._actions.collapseNode(node.rootUri, node.uri);
        }
      });
    }
  }
      (textBlock, ii) => {
        // Make absolutely certain that our text is acceptable.
        textBlock = sanitizeDraftText(textBlock);
        var end = start + textBlock.length;
        var inlines = nullthrows(chunk).inlines.slice(start, end);
        var entities = nullthrows(chunk).entities.slice(start, end);
        var characterList = List(
          inlines.map((style, ii) => {
            var data = {style, entity: (null: ?string)};
            if (entities[ii]) {
              data.entity = entities[ii];
            }
            return CharacterMetadata.create(data);
          })
        );
        start = end + 1;

        return new ContentBlock({
          key: generateBlockKey(),
          type: nullthrows(chunk).blocks[ii].type,
          depth: nullthrows(chunk).blocks[ii].depth,
          text: textBlock,
          characterList,
        });
      }
    it('updates the tracked repos states with the new pane item state', () => {
      const updatePaneItemAction: UpdatePaneItemStateAction = {
        payload: {
          repositoryPathToEditors: new Map([
            [REPO_PATH_1, [fakeEditor1, fakeEditor2]],
            [OTHER_REPO_PARH, [fakeEditor3]],
          ]),
        },
        type: ActionType.UPDATE_PANE_ITEM_STATE,
      };
      const newState = accumulateState(oneRepoState, updatePaneItemAction);

      const oldShortHeadsToFileList = nullthrows(
        oneRepoState.repositoryPathToState.get(REPO_PATH_1),
      ).shortHeadsToFileList;
      expect(oldShortHeadsToFileList.size).toBe(2);
      expect(oldShortHeadsToFileList.get(SHOTHEAD_1_1)).toEqual([
        'c.txt',
        'd.txt',
      ]);

      // Doesn't add untracked repos.
      expect(newState.repositoryPathToState.size).toBe(1);

      const newShortHeadsToFileList = nullthrows(
        newState.repositoryPathToState.get(REPO_PATH_1),
      ).shortHeadsToFileList;
      expect(newShortHeadsToFileList.size).toBe(2);
      expect(newShortHeadsToFileList.get(SHOTHEAD_1_1)).toEqual([
        'file1.txt',
        'file2.txt',
      ]);
      expect(newShortHeadsToFileList.get(SHOTHEAD_1_2)).toEqual(['e.txt']);
    });
/**
 * Get a SelectionState for the supplied mouse event.
 */
function getSelectionForEvent(
  event: Object,
  editorState: EditorState,
): ?SelectionState {
  let node: ?Node = null;
  let offset: ?number = null;

  /* $FlowFixMe(>=0.68.0 site=www,mobile) This comment suppresses an error
   * found when Flow v0.68 was deployed. To see the error delete this comment
   * and run Flow. */
  if (typeof document.caretRangeFromPoint === 'function') {
    const dropRange = document.caretRangeFromPoint(event.x, event.y);
    node = dropRange.startContainer;
    offset = dropRange.startOffset;
  } else if (event.rangeParent) {
    node = event.rangeParent;
    offset = event.rangeOffset;
  } else {
    return null;
  }

  node = nullthrows(node);
  offset = nullthrows(offset);
  const offsetKey = nullthrows(findAncestorOffsetKey(node));

  return getUpdatedSelectionState(
    editorState,
    offsetKey,
    offset,
    offsetKey,
    offset,
  );
}
/**
 * Get a SelectionState for the supplied mouse event.
 */
function getSelectionForEvent(
  event: Object,
  editorState: EditorState,
): ?SelectionState {
  let node: ?Node = null;
  let offset: ?number = null;

  if (typeof document.caretRangeFromPoint === 'function') {
    var dropRange = document.caretRangeFromPoint(event.x, event.y);
    node = dropRange.startContainer;
    offset = dropRange.startOffset;
  } else if (event.rangeParent) {
    node = event.rangeParent;
    offset = event.rangeOffset;
  } else {
    return null;
  }

  node = nullthrows(node);
  offset = nullthrows(offset);
  const offsetKey = nullthrows(findAncestorOffsetKey(node));

  return getUpdatedSelectionState(
    editorState,
    offsetKey,
    offset,
    offsetKey,
    offset,
  );
}
  componentDidMount(): void {
    // Hitting enter when this panel has focus should confirm the dialog.
    this._disposables.add(
      atom.commands.add(nullthrows(this._root), 'core:confirm', event =>
        this.props.onConfirm(),
      ),
    );

    // Hitting escape should cancel the dialog.
    this._disposables.add(
      atom.commands.add('atom-workspace', 'core:cancel', event =>
        this.props.onCancel(),
      ),
    );

    nullthrows(this._password).focus();

    const raiseNativeNotification = getNotificationService();
    if (raiseNativeNotification != null) {
      const pendingNotification = raiseNativeNotification(
        'Nuclide Remote Connection',
        'Nuclide requires additional action to authenticate your remote connection',
        2000,
        false,
      );
      if (pendingNotification != null) {
        this._disposables.add(pendingNotification);
      }
    }
  }
    it('removes old cached short head data when its bookmarks are gone', () => {
      const updateBookmarksAction: UpdateRepositoryBookmarksAction = {
        payload: {
          repository: fakeRepository,
          bookmarkNames: new Set([SHOTHEAD_1_2]),
          activeShortHead: SHOTHEAD_1_2,
        },
        type: ActionType.UPDATE_REPOSITORY_BOOKMARKS,
      };
      const oldRpositoryState = oneRepoState.repositoryPathToState.get(
        REPO_PATH_1,
      );
      expect(nullthrows(oldRpositoryState).shortHeadsToFileList.size).toBe(2);
      expect(
        nullthrows(oldRpositoryState).shortHeadsToFileList.has(SHOTHEAD_1_1),
      ).toBeTruthy();

      const newState = accumulateState(oneRepoState, updateBookmarksAction);
      expect(newState.repositoryPathToState.size).toBe(1);

      const newRepositoryState: BookShelfRepositoryState = nullthrows(
        newState.repositoryPathToState.get(REPO_PATH_1),
      );
      expect(newRepositoryState.activeShortHead).toBe(SHOTHEAD_1_2);
      expect(newRepositoryState.isRestoring).toBe(false);
      expect(newRepositoryState.shortHeadsToFileList.size).toBe(1);
      expect(
        newRepositoryState.shortHeadsToFileList.has(SHOTHEAD_1_1),
      ).toBeFalsy();
      expect(newRepositoryState.shortHeadsToFileList.get(SHOTHEAD_1_2)).toEqual(
        nullthrows(oldRpositoryState).shortHeadsToFileList.get(SHOTHEAD_1_2),
      );
    });
Exemple #8
0
      it('dserializes two repository states', () => {
        const serializedState: SerializedBookShelfState = ({
          repositoryPathToState: [
            [
              REPO_PATH_1,
              {
                ...REPO_STATE_1,
                shortHeadsToFileList: Array.from(
                  REPO_STATE_1.shortHeadsToFileList.entries(),
                ),
              },
            ],
            [
              REPO_PATH_2,
              {
                ...REPO_STATE_2,
                shortHeadsToFileList: Array.from(
                  REPO_STATE_2.shortHeadsToFileList.entries(),
                ),
              },
            ],
          ],
        }: any);
        const deserialized = deserializeBookShelfState(serializedState);
        expect(deserialized.repositoryPathToState.size).toBe(2);
        const deserializedRepoState1 = nullthrows(
          deserialized.repositoryPathToState.get(REPO_PATH_1),
        );
        expect(deserializedRepoState1).not.toBeNull();
        invariant(deserializedRepoState1 != null);
        expect(deserializedRepoState1.activeShortHead).toBe(ACTIVE_SHOTHEAD_1);
        expect(deserializedRepoState1.isRestoring).toBe(false);
        expect(deserializedRepoState1.shortHeadsToFileList.size).toBe(1);
        expect(
          nullthrows(
            deserializedRepoState1.shortHeadsToFileList.get(SHOTHEAD_1_1),
          ).join(','),
        ).toBe(['a.txt', 'b.txt'].join(','));

        const deserializedRepoState2 = nullthrows(
          deserialized.repositoryPathToState.get(REPO_PATH_2),
        );
        expect(deserializedRepoState2).not.toBeNull();
        invariant(deserializedRepoState2 != null);
        expect(deserializedRepoState2.activeShortHead).toBe(ACTIVE_SHOTHEAD_2);
        expect(deserializedRepoState2.isRestoring).toBe(false);
        expect(deserializedRepoState2.shortHeadsToFileList.size).toBe(2);
        expect(
          nullthrows(
            deserializedRepoState2.shortHeadsToFileList.get(SHOTHEAD_2_1),
          ).join(','),
        ).toBe(['c.txt', 'd.txt'].join(','));
        expect(
          nullthrows(
            deserializedRepoState2.shortHeadsToFileList.get(SHOTHEAD_2_2),
          ).join(','),
        ).toBe('e.txt');
      });
Exemple #9
0
 features.sort((a, b) => {
   const aIsRepoProvider = packageIsRepositoryProvider(a.pkg);
   const bIsRepoProvider = packageIsRepositoryProvider(b.pkg);
   if (aIsRepoProvider !== bIsRepoProvider) {
     return aIsRepoProvider ? -1 : 1;
   }
   const aIndex = nullthrows(originalOrder.get(a));
   const bIndex = nullthrows(originalOrder.get(b));
   return aIndex - bIndex;
 });
Exemple #10
0
  toString(): string {
    const func = this._func;

    if (func != null) {
      if (this._path == null || this._line == null) {
        return `${func}()`;
      }
      return `${func}() [${this._path}:${this._line}]`;
    }

    return `${nullthrows(this._path)}:${nullthrows(this._line)}`;
  }
// extension must be a string starting with a '.' like '.js' or '.py'
function getActiveScriptPath(extension: string): string {
  const center = atom.workspace.getCenter
    ? atom.workspace.getCenter()
    : atom.workspace;
  const activeEditor: ?atom$TextEditor = center.getActiveTextEditor();
  if (
    activeEditor == null ||
    !activeEditor.getPath() ||
    !nullthrows(activeEditor.getPath()).endsWith(extension)
  ) {
    return '';
  }
  return nuclideUri.getPath(nullthrows(activeEditor.getPath()));
}
Exemple #12
0
  describe('getShortHeadChangesFromStateStream', () => {
    const states = new Subject();
    const shortHeadChangesStream = getShortHeadChangesFromStateStream(states);

    const shortHeadChanges: Array<RepositoryShortHeadChange> = [];
    shortHeadChangesStream.subscribe(change => shortHeadChanges.push(change));

    states.next(getDummyBookShelfState());

    const newActiveShortHead = 'foo_bar';
    const newStateWithShortHeadChange = getDummyBookShelfState();
    const newRepositoryState = newStateWithShortHeadChange.repositoryPathToState.get(
      DUMMY_REPO_PATH_1,
    );
    nullthrows(newRepositoryState).activeShortHead = newActiveShortHead;

    states.next(newStateWithShortHeadChange);
    states.complete();

    waitsFor(() => shortHeadChanges.length === 1);

    runs(() => {
      const {repositoryPath, activeShortHead} = shortHeadChanges[0];
      expect(repositoryPath).toBe(DUMMY_REPO_PATH_1);
      expect(activeShortHead).toBe(newActiveShortHead);
    });
  });
Exemple #13
0
 _handleTabChange = (selectedTabName: string) => {
   if (typeof this.props.onActiveTabChange === 'function') {
     this.props.onActiveTabChange(
       nullthrows(this.props.tabs.find(tab => tab.name === selectedTabName)),
     );
   }
 };
Exemple #14
0
  cut: function(editorState: EditorState): EditorState {
    var content = editorState.getCurrentContent();
    var selection = editorState.getSelection();
    var targetRange: ?SelectionState = null;

    if (selection.isCollapsed()) {
      var anchorKey = selection.getAnchorKey();
      var blockEnd = content.getBlockForKey(anchorKey).getLength();

      if (blockEnd === selection.getAnchorOffset()) {
        return editorState;
      }

      targetRange = selection.set('focusOffset', blockEnd);
    } else {
      targetRange = selection;
    }

    targetRange = nullthrows(targetRange);
    clipboard = getContentStateFragment(content, targetRange);

    var afterRemoval = DraftModifier.removeRange(
      content,
      targetRange,
      'forward',
    );

    if (afterRemoval === content) {
      return editorState;
    }

    return EditorState.push(editorState, afterRemoval, 'remove-range');
  },
Exemple #15
0
 onChange={isChecked => {
   this.props.projectStore.setStickyCommand(
     nullthrows(this._debugTarget).getText(),
     isChecked,
   );
   this.setState({stickyScript: isChecked});
 }}
Exemple #16
0
  componentWillReceiveProps(nextProps: HunkProps): void {
    const {hunk, grammar} = nextProps;
    const changes = hunk.changes;
    const prevHunk = this.props.hunk;
    const editor = nullthrows(this.editor);

    const newText = changes.map(change => change.content.slice(1)).join('\n');
    const oldText = prevHunk.changes
      .map(change => change.content.slice(1))
      .join('\n');
    const oldGrammar = this.props.grammar;

    if (newText === oldText && grammar === oldGrammar) {
      return;
    }

    if (newText !== oldText) {
      editor.setText(newText);
    }
    if (grammar !== oldGrammar) {
      editor.setGrammar(grammar);
    }
    this._disposables.dispose();
    this._disposables = new UniversalDisposable();
    this._createLineMarkers(editor);
    this._createLineNumbers(editor);
  }
Exemple #17
0
 query.getChildren().forEach(child => {
   const field = child;
   if (!(field instanceof RelayQuery.Field) || !field.canHaveSubselections()) {
     // Only care about linked fields
     return;
   }
   // Get the concrete field from the RelayQueryField
   const concreteField = nullthrows(
     QueryBuilder.getField(field.getConcreteQueryNode()),
   );
   // Build the identifying argument for the query
   let identifyingArgName;
   let identifyingArgType;
   const identifyingArg = concreteField.calls && concreteField.calls[0];
   if (identifyingArg) {
     identifyingArgName = identifyingArg.name;
     identifyingArgType =
       identifyingArg.metadata && identifyingArg.metadata.type;
   }
   // Build the concrete query
   const concreteQuery = {
     calls: concreteField.calls,
     children: concreteField.children,
     directives: [], // @include/@skip directives are processed within getChildren()
     fieldName: concreteField.fieldName,
     isDeferred: false,
     kind: 'Query',
     metadata: {
       identifyingArgName,
       identifyingArgType,
       isAbstract: concreteField.metadata && concreteField.metadata.isAbstract,
       isPlural: concreteField.metadata && concreteField.metadata.isPlural,
     },
     name: query.getName(),
     // Note that classic queries are typed as the type of the root field, not
     // the `Query` type
     type: field.getType(),
   };
   // Construct a root query
   const root = RelayQuery.Root.create(
     concreteQuery,
     RelayMetaRoute.get('$RelayEnvironment'),
     query.getVariables(),
   );
   // Construct the payload that would have been returned had `root` been
   // used to fetch data.
   const serializationKey = field.getSerializationKey();
   const rootPayload = {};
   if (!response.hasOwnProperty(serializationKey)) {
     // Data is missing for this field. This can occur when the field is empty
     // due to a failing conditional (@include/@skip) in its subtree.
     return;
   }
   rootPayload[root.getFieldName()] = response[serializationKey];
   results.push({
     field,
     root,
     rootPayload,
   });
 });
Exemple #18
0
 pack => {
   if (featureNames.has(pack.name)) {
     onWillInitializePackageDisposable.dispose();
     const rootPackage = atom.packages.getLoadedPackage(this._pkgName);
     nullthrows(rootPackage).initializeIfNeeded();
   }
 },
Exemple #19
0
 componentDidMount() {
   this._subscriptions = new UniversalDisposable(
     atom.commands.add(nullthrows(this._scrollerNode), 'atom-ide:filter', () =>
       this.focusSearch(),
     ),
   );
 }
Exemple #20
0
 getFatQuery(): RelayQuery.Fragment {
   if (!this._fatQuery) {
     const fragment = fromGraphQL.Fragment(this.mutation.getFatQuery());
     invariant(
       fragment instanceof RelayQuery.Fragment,
       'RelayMutationQueue: Expected `getFatQuery` to return a GraphQL ' +
       'Fragment'
     );
     this._fatQuery = nullthrows(flattenRelayQuery(
       fragment,
       {
         // TODO #10341736
         // This used to be `preserveEmptyNodes: fragment.isPattern()`. We
         // discovered that products were not marking their fat queries as
         // patterns (by adding `@relay(pattern: true)`) which was causing
         // `preserveEmptyNodes` to be false. This meant that empty fields,
         // would be stripped instead of being used to produce an intersection
         // with the tracked query. Products were able to do this because the
         // Babel Relay plugin doesn't produce validation errors for empty
         // fields. It should, and we will make it do so, but for now we're
         // going to set this to `true` always, and make the plugin warn when
         // it encounters an empty field that supports subselections in a
         // non-pattern fragment. Revert this when done.
         preserveEmptyNodes: true,
         shouldRemoveFragments: true,
       }
     ));
   }
   return this._fatQuery;
 }
 .map((filePath, index) => {
   return {
     filePath,
     displayPath: displayPaths[index],
     fileStatus: nullthrows(fileStatuses.get(filePath)),
   };
 })
 _onScroll = (e: Object) => {
   const newScrollY = e.nativeEvent.contentOffset.y;
   this._isScrolling = this._scrollOffsetY !== newScrollY;
   this._scrollOffsetY = newScrollY;
   this._frameHeight = e.nativeEvent.layoutMeasurement.height;
   // We don't want to enqueue any updates if any cells are in the middle of an incremental render,
   // because it would just be wasted work.
   if (this._cellsInProgress.size === 0) {
     this._enqueueComputeRowsToRender();
   }
   if (this.props.onViewableRowsChanged && Object.keys(this._rowFrames).length) {
     const viewableRows = ViewabilityHelper.computeViewableRows(
       this.props.viewablePercentThreshold,
       this._rowFrames,
       this.props.data,
       e.nativeEvent.contentOffset.y,
       e.nativeEvent.layoutMeasurement.height
     );
     if (deepDiffer(viewableRows, this._viewableRows)) {
       this._viewableRows = viewableRows;
       nullthrows(this.props.onViewableRowsChanged)(this._viewableRows);
     }
   }
   this.props.onScroll && this.props.onScroll(e);
 };
Exemple #23
0
        ).flatMap(textEditor => {
          const buffer = textEditor.getBuffer();
          if (buffers.has(buffer)) {
            return Observable.empty();
          }
          buffers.add(buffer);

          const bufferPath = nullthrows(buffer.getPath());

          const bufferReloads = observableFromSubscribeFunction(
            buffer.onDidReload.bind(buffer),
          );
          const bufferChanges = observableFromSubscribeFunction(
            buffer.onDidChangeText.bind(buffer),
          );

          // TODO (tjfryan): handle renames `onDidChangePath`

          // This is in a flatMap, so we need to make sure this terminates
          // We can terminate, `takeUntil`, buffer is destroyed
          // And make sure to clear the cached diff for the buffer once we no
          // longer care about it
          const bufferDestroyed = observableFromSubscribeFunction(
            buffer.onDidDestroy.bind(buffer),
          ).do(() => {
            buffers.delete(buffer);
            repository.deleteDiffInfo(bufferPath);
            fileContentsAtHead.delete(bufferPath);
          });

          // recalculate on bufferReload, bufferChanges, and when we get
          // this file's data from hg cat
          return Observable.merge(
            bufferReloads,
            bufferChanges,
            fetchFileContentsAtHead.filter(fileContentsList =>
              fileContentsList.some(
                fileInfo =>
                  nuclideUri.join(
                    repository.getWorkingDirectory(),
                    fileInfo.abspath,
                  ) === bufferPath,
              ),
            ),
          )
            .let(fastDebounce(200))
            .switchMap(() => {
              const oldContents = fileContentsAtHead.get(bufferPath);
              if (oldContents == null) {
                return Observable.empty();
              }
              const newContents = buffer.getText();
              return gitDiffStrings(oldContents, newContents)
                .map(diffOutput => parseHgDiffUnifiedOutput(diffOutput))
                .do(diffInfo => {
                  repository.setDiffInfo(bufferPath, diffInfo);
                });
            })
            .takeUntil(bufferDestroyed);
        });
Exemple #24
0
              .flatMap(() => {
                const bufferPath = nullthrows(textEditor.getPath());
                // TODO (tjfryan): do something to handle generated files
                if (fileContentsAtHead.has(bufferPath)) {
                  return Observable.empty();
                }

                bufferedFilesToCat.push(repository.relativize(bufferPath));
                if (bufferedFilesToCat.length > 1) {
                  return Observable.empty();
                }

                // use nextTick to buffer many files being requested at once
                // (maybe should use timeout instead?)
                return Observable.fromPromise(nextTick()).switchMap(() => {
                  const filesToCat = [...bufferedFilesToCat];
                  bufferedFilesToCat.length = 0;
                  return repository
                    .fetchMultipleFilesContentAtRevision(
                      filesToCat,
                      hgConstants.HEAD_REVISION_EXPRESSION,
                    )
                    .catch(() =>
                      // hg uses errorCode 1 as "nothing went wrong but nothing was found"
                      Observable.empty(),
                    );
                });
              });
 it("keeps the existing state when it's there", () => {
   expect(oneRepoState.repositoryPathToState.size).toBe(1);
   const addRepositoryAction: AddProjectRepositoryAction = {
     payload: {
       repository: fakeRepository,
     },
     type: ActionType.ADD_PROJECT_REPOSITORY,
   };
   const newState = accumulateState(oneRepoState, addRepositoryAction);
   expect(fakeRepository.getWorkingDirectory).toHaveBeenCalled();
   expect(newState.repositoryPathToState.size).toBe(1);
   const keptRepoState: BookShelfRepositoryState = nullthrows(
     newState.repositoryPathToState.get(REPO_PATH_1),
   );
   expect(keptRepoState).toBeDefined();
   expect(keptRepoState.activeShortHead).toBe(ACTIVE_SHOTHEAD_1);
   expect(keptRepoState.isRestoring).toBeFalsy();
   expect(keptRepoState.shortHeadsToFileList.size).toBe(2);
   expect(keptRepoState.shortHeadsToFileList.get(SHOTHEAD_1_1)).toEqual([
     'c.txt',
     'd.txt',
   ]);
   expect(keptRepoState.shortHeadsToFileList.get(SHOTHEAD_1_2)).toEqual([
     'e.txt',
   ]);
 });
 _onChange = (event: CheckBoxEvent) => {
   const value = this.props.value ?? false;
   nullthrows(this._nativeRef).setNativeProps({value: value});
   // Change the props after the native props are set in case the props
   // change removes the component
   this.props.onChange && this.props.onChange(event);
   this.props.onValueChange &&
     this.props.onValueChange(event.nativeEvent.value);
 };
Exemple #27
0
function printDirectivesAndChildren(node, printerState: PrinterState): string {
  const conditionDirectives = printDirectives(node, isConditionDirective);
  const otherDirectives = printDirectives(node, isNonConditionDirective);

  return (
    otherDirectives +
    (conditionDirectives
      ? ' {' +
        newLine +
        oneIndent +
        '...' +
        conditionDirectives +
        nullthrows(printChildren(node, printerState, oneIndent)) +
        newLine +
        '}'
      : nullthrows(printChildren(node, printerState, '')))
  );
}
 getTextContentFromFiles(files, fileText => {
   fileText && editor.update(
     insertTextAtSelection(
       editorState,
       nullthrows(dropSelection), // flow wtf
       fileText,
     ),
   );
 });
Exemple #29
0
 onResponderTerminationRequest: (): boolean => {
   const {onResponderTerminationRequest} = this.props;
   if (!nullthrows(this.touchableHandleResponderTerminationRequest)()) {
     return false;
   }
   if (onResponderTerminationRequest == null) {
     return true;
   }
   return onResponderTerminationRequest();
 },
 return postOrder(process.pid, mapChildren(viewPs), (pid, children) => {
   const process = nullthrows(viewPs.get(pid));
   return {
     pid,
     command: process.command,
     cpuPercentage: process.pcpu,
     children,
     ioBytesStats: ioMap.get(pid),
   };
 });