static push(
    editorState: EditorState,
    contentState: ContentState,
    changeType: EditorChangeType,
    forceSelection: boolean = true,
  ): EditorState {
    if (editorState.getCurrentContent() === contentState) {
      return editorState;
    }

    const directionMap = EditorBidiService.getDirectionMap(
      contentState,
      editorState.getDirectionMap(),
    );

    if (!editorState.getAllowUndo()) {
      return EditorState.set(editorState, {
        currentContent: contentState,
        directionMap,
        lastChangeType: changeType,
        selection: contentState.getSelectionAfter(),
        forceSelection,
        inlineStyleOverride: null,
      });
    }

    const selection = editorState.getSelection();
    const currentContent = editorState.getCurrentContent();
    let undoStack = editorState.getUndoStack();
    let newContent = contentState;

    if (
      selection !== currentContent.getSelectionAfter() ||
      mustBecomeBoundary(editorState, changeType)
    ) {
      undoStack = undoStack.push(currentContent);
      newContent = newContent.setSelectionBefore(selection);
    } else if (
      changeType === 'insert-characters' ||
      changeType === 'backspace-character' ||
      changeType === 'delete-character'
    ) {
      // Preserve the previous selection.
      newContent = newContent.setSelectionBefore(
        currentContent.getSelectionBefore(),
      );
    }

    let inlineStyleOverride = editorState.getInlineStyleOverride();

    // Don't discard inline style overrides for the following change types:
    const overrideChangeTypes = [
      'adjust-depth',
      'change-block-type',
      'split-block',
    ];

    if (overrideChangeTypes.indexOf(changeType) === -1) {
      inlineStyleOverride = null;
    }

    const editorStateChanges = {
      currentContent: newContent,
      directionMap,
      undoStack,
      redoStack: Stack<ContentState>(),
      lastChangeType: changeType,
      selection: contentState.getSelectionAfter(),
      forceSelection,
      inlineStyleOverride,
    };

    return EditorState.set(editorState, editorStateChanges);
  }
Push the current ContentState onto the undo stack if it should be
considered a boundary state, and set the provided ContentState as the
new current content.