text: import React from "react";
  import PropTypes from "prop-types";
  import warning from "warning";
  
  import RouterContext from "./RouterContext";
  import warnAboutGettingProperty from "./utils/warnAboutGettingProperty";
  
  function getContext(props, state) {
    return {
      history: props.history,
      location: state.location,
      match: Router.computeRootMatch(state.location.pathname),
      staticContext: props.staticContext
    };
  }
  
  /**
   * The public API for putting history on context.
   */
  class Router extends React.Component {
    static computeRootMatch(pathname) {
      return { path: "/", url: "/", params: {}, isExact: pathname === "/" };
    }
  
    constructor(props) {
      super(props);
  
      this.state = {
        location: props.history.location
      };
  
      // This is a bit of a hack. We have to start listening for location
      // changes here in the constructor in case there are any <Redirect>s
      // on the initial render. If there are, they will replace/push when
      // they mount and since cDM fires in children before parents, we may
      // get a new location before the <Router> is mounted.
      this._isMounted = false;
      this._pendingLocation = null;
  
      if (!props.staticContext) {
        this.unlisten = props.history.listen(location => {
          if (this._isMounted) {
            this.setState({ location });
          } else {
            this._pendingLocation = location;
          }
        });
      }
    }
  
    componentDidMount() {
      this._isMounted = true;
  
      if (this._pendingLocation) {
        this.setState({ location: this._pendingLocation });
      }
    }
  
    componentWillUnmount() {
      if (this.unlisten) this.unlisten();
    }
  
    render() {
      const context = getContext(this.props, this.state);
  
      return (
        <RouterContext.Provider
          children={this.props.children || null}
          value={context}
        />
      );
    }
  }
  
  // TODO: Remove this in v5
  if (!React.createContext) {
    Router.childContextTypes = {
      router: PropTypes.object.isRequired
    };
  
    Router.prototype.getChildContext = function() {
      const context = getContext(this.props, this.state);
  
      if (__DEV__) {
        const contextWithoutWarnings = { ...context };
  
        Object.keys(context).forEach(key => {
          warnAboutGettingProperty(
            context,
            key,
            `You should not be using this.context.router.${key} directly. It is private API ` +
              "for internal use only and is subject to change at any time. Instead, use " +
              "a <Route> or withRouter() to access the current location, match, etc."
          );
        });
  
        context._withoutWarnings = contextWithoutWarnings;
      }
  
      return {
        router: context
      };
    };
  }
  
  if (__DEV__) {
    Router.propTypes = {
      children: PropTypes.node,
      history: PropTypes.object.isRequired,
      staticContext: PropTypes.object
    };
  
    Router.prototype.componentDidUpdate = function(prevProps) {
      warning(
        prevProps.history === this.props.history,
        "You cannot change <Router history>"
      );
    };
  }
  
  export default Router;
  