<commit_before>import React, {Component, PropTypes} from 'react';
import Matcher from 'route-parser';

// a helper to get the current location from the history object
function currentLocation(h){
  let loc;
  h.listen(location => loc = location)();
  return loc;
}

// pattern matching for urls
function matches(patterns, url){
  if (!Array.isArray(patterns)){
    patterns = [patterns];
  }

  for (let pattern of patterns){
    var matcher = new Matcher(pattern);
    let res = matcher.match(url);
    if (res){
      return res;
    }
  }
  return false;
}


// top level component. pass in a history object.
// <Router history={history}>
//   <App/>
// </Router>
// todo - use a default history singleton in browser
export class Router extends Component{
  state = {
    location: null
  };
  static propTypes = {
    history: PropTypes.object.isRequired
  };
  static childContextTypes = {
    routah: PropTypes.object
  };
  getChildContext(){
    return {
      routah: {
        history: this.props.history
      }
    };
  }
  render(){
    return this.props.children;
  }
}



export class Route extends Component{
  static propTypes = {
    match: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
    component: PropTypes.func,
    notFound: PropTypes.func,
    props: PropTypes.object,
    onLeave: PropTypes.func,
    onEnter: PropTypes.func
  };
  static defaultProps = {
    notFound: () => <noscript/>,
    props: {},
    onMount: () => {},
    onEnter: (l, cb) => cb(),
    onLeave: (l, cb) => cb(),
    onUnload: () => {}
  };
  static contextTypes = {
    routah: PropTypes.object
  };
  refresh = location => {
    let doesMatch = true, match;
    if (this.props.path){
      match = matches(this.props.path, this.context.routah.history.createHref(location));
      doesMatch = !!match;
    }

    this.setState({
      location: {
        ...location,
        params: match || {}
      },
      matches: doesMatch
    });
  };
  componentWillMount(){
    let h = this.context.routah.history;
    this.dispose = this.context.routah.history.listen(this.refresh);

    if (!this.props.path || matches(this.props.path,  h.createHref(currentLocation(h)))){
      this.props.onMount(currentLocation(h));
    }

    this.disposeBefore = this.context.routah.history.listenBefore((location, callback) => {
      if (!this.props.path || matches(this.props.path,  h.createHref(location))){
        return this.props.onEnter(location, callback);
      }
      else {
        return this.props.onLeave(location, callback);
      }
    });

    this.disposeUnload = this.context.routah.history.listenBeforeUnload(() => {
      if (!this.props.path || matches(this.props.path,  h.createHref(currentLocation(h)))){
        return this.props.onUnload(currentLocation(h));
      }
    });

  }
  componentWillReceiveProps(next){
    if (next.path !== this.props.path){
      this.refresh(currentLocation(this.context.routah.history));
    }
  }<commit_msg>fix enter/leave hooks<commit_after>import React, {Component, PropTypes} from 'react';
import Matcher from 'route-parser';

// a helper to get the current location from the history object
function currentLocation(h){
  let loc;
  h.listen(location => loc = location)();
  return loc;
}

// pattern matching for urls
function matches(patterns, url){
  if (!Array.isArray(patterns)){
    patterns = [patterns];
  }

  for (let pattern of patterns){
    var matcher = new Matcher(pattern);
    let res = matcher.match(url);
    if (res){
      return res;
    }
  }
  return false;
}


// top level component. pass in a history object.
// <Router history={history}>
//   <App/>
// </Router>
// todo - use a default history singleton in browser
export class Router extends Component{
  state = {
    location: null
  };
  static propTypes = {
    history: PropTypes.object.isRequired
  };
  static childContextTypes = {
    routah: PropTypes.object
  };
  getChildContext(){
    return {
      routah: {
        history: this.props.history
      }
    };
  }
  render(){
    return this.props.children;
  }
}



export class Route extends Component{
  static propTypes = {
    match: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
    component: PropTypes.func,
    notFound: PropTypes.func,
    props: PropTypes.object,
    onLeave: PropTypes.func,
    onEnter: PropTypes.func
  };
  static defaultProps = {
    notFound: () => <noscript/>,
    props: {},
    onMount: () => {},
    onEnter: (l, cb) => cb(),
    onLeave: (l, cb) => cb(),
    onUnload: () => {}
  };
  static contextTypes = {
    routah: PropTypes.object
  };
  refresh = location => {
    let doesMatch = true, match;
    if (this.props.path){
      match = matches(this.props.path, this.context.routah.history.createHref(location));
      doesMatch = !!match;
    }

    this.setState({
      location: {
        ...location,
        params: match || {}
      },
      matches: doesMatch
    });
  };
  componentWillMount(){
    let h = this.context.routah.history;
    this.dispose = this.context.routah.history.listen(this.refresh);

    if (!this.props.path || matches(this.props.path,  h.createHref(currentLocation(h)))){
      this.props.onMount(currentLocation(h));
    }

    this.disposeBefore = this.context.routah.history.listenBefore((location, callback) => {
      let matchesCurrent = !this.props.path || matches(this.props.path,  h.createHref(currentLocation(h)));
      let matchesNext = !this.props.path || matches(this.props.path,  h.createHref(location));
      if (!matchesCurrent && matchesNext){
        return this.props.onEnter(location, callback);
      }
      if (matchesCurrent && !matchesNext){
        return this.props.onLeave(location, callback);
      }

      return callback();
    });

    this.disposeUnload = this.context.routah.history.listenBeforeUnload(() => {
      if (!this.props.path || matches(this.props.path,  h.createHref(currentLocation(h)))){
        return this.props.onUnload(currentLocation(h));
      }
    });

  }
  componentWillReceiveProps(next){
    if (next.path !== this.props.path){
      this.refresh(currentLocation(this.context.routah.history));
    }
  }
{'fraction_non_alphanumeric': 0.14329464861379754, 'fraction_numerical': 0.0, 'mean_word_length': 2.9222503160556257, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6558911', 'n_tokens_mistral': 1931, 'n_tokens_neox': 1922, 'n_words': 415}