<commit_before>// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library route.client;

import 'dart:async';
import 'dart:collection';
import 'dart:html';

import 'package:logging/logging.dart';

import 'src/utils.dart';

import 'url_matcher.dart';
export 'url_matcher.dart';
import 'url_template.dart';


final _logger = new Logger('route');

typedef RoutePreEnterEventHandler(RoutePreEnterEvent path);
typedef RouteEnterEventHandler(RouteEnterEvent path);
typedef RouteLeaveEventHandler(RouteLeaveEvent path);

/**
 * A helper Router handle that scopes all route event subsriptions to it's
 * instance and provides an convinience [discard] method.
 */
class RouteHandle implements Route {
  Route _route;
  final StreamController<RoutePreEnterEvent> _onPreEnterController;
  final StreamController<RouteEnterEvent> _onEnterController;
  final StreamController<RouteLeaveEvent> _onLeaveController;

  @deprecated
  Stream<RouteEnterEvent> get onRoute => onEnter;
  Stream<RoutePreEnterEvent> get onPreEnter => _onPreEnterController.stream;
  Stream<RouteEnterEvent> get onEnter => _onEnterController.stream;
  Stream<RouteLeaveEvent> get onLeave => _onLeaveController.stream;

  StreamSubscription _onPreEnterSubscription;
  StreamSubscription _onEnterSubscription;
  StreamSubscription _onLeaveSubscription;
  List<RouteHandle> _childHandles = <RouteHandle>[];

  RouteHandle._new(Route this._route)
      : _onEnterController =
            new StreamController<RouteEnterEvent>.broadcast(sync: true),
        _onPreEnterController =
            new StreamController<RoutePreEnterEvent>.broadcast(sync: true),
        _onLeaveController =
            new StreamController<RouteLeaveEvent>.broadcast(sync: true) {
    _onEnterSubscription = _route.onEnter.listen(_onEnterController.add);
    _onPreEnterSubscription =
        _route.onPreEnter.listen(_onPreEnterController.add);
    _onLeaveSubscription = _route.onLeave.listen(_onLeaveController.add);
  }

  /// discards this handle.
  void discard() {
    _logger.finest('discarding handle for $_route');
    _onPreEnterSubscription.cancel();
    _onEnterSubscription.cancel();
    _onLeaveSubscription.cancel();
    _onEnterController.close();
    _onLeaveController.close();
    _childHandles.forEach((RouteHandle c) => c.discard());
    _childHandles.clear();
    _route = null;
  }

  /// Not supported. Overridden to throw an error.
  void addRoute({String name, Pattern path, bool defaultRoute: false,
    RouteEnterEventHandler enter, RoutePreEnterEventHandler preEnter,
    RouteLeaveEventHandler leave, mount}) =>
          throw new UnsupportedError('addRoute is not supported in handle');

  /// See [Route.getRoute]
  Route getRoute(String routePath) {
    Route r = _assertState(() => _getHost(_route).getRoute(routePath));
    if (r == null) return null;
    var handle = r.newHandle();
    if (handle != null) {
      _childHandles.add(handle);
    }
    return handle;
  }

  /**
   * Create an return a new [RouteHandle] for this route.
   */
  RouteHandle newHandle() {
    _logger.finest('newHandle for $this');
    return new RouteHandle._new(_getHost(_route));
  }

  Route _getHost(Route r) {
    _assertState();
    if (r == null) {
      throw new StateError('Oops?!');
    }
    if ((r is Route) && !(r is RouteHandle)) {
      return r;
    }
    RouteHandle rh = r;
    return rh._getHost(rh._route);
  }

  /// See [Route.reverse]
  String reverse(String tail) =>
      _assertState(() => _getHost(_route).reverse(tail));

  _assertState([f()]) {
    if (_route == null) {
      throw new StateError('This route handle is already discated.');
    }
    if (f != null)  return f();
  }

  /// See [Route.isActive]
  bool get isActive => _route.isActive;

  /// See [Route.parameters]
  Map get parameters => _route.parameters;

  /// See [Route.path]
  UrlMatcher get path => _route.path;

  /// See [Route.name]
  String get name => _route.name;

  /// See [Route.parent]
  Route get parent => _route.parent;
}

childRoute({String name, Pattern path, bool defaultRoute: false,
    RouteEnterEventHandler enter, RoutePreEnterEventHandler preEnter,
    RouteLeaveEventHandler leave, mount}) => (Route route) =>
        route.addRoute(name: name, path: path, defaultRoute: defaultRoute,
            enter: enter, preEnter: preEnter, leave: leave, mount: leave);

/**
 * Route is a node in the tree of routes. The edge leading to the route is
 * defined by path.
 */
class Route {
  final String name;
  final Map<String, Route> _routes = new LinkedHashMap<String, Route>();
  final UrlMatcher path;
  final StreamController<RouteEnterEvent> _onEnterController;
  final StreamController<RoutePreEnterEvent> _onPreEnterController;
  final StreamController<RouteLeaveEvent> _onLeaveController;
  final Route parent;
  Route _defaultRoute;
  Route _currentRoute;
  RouteEvent _lastEvent;

  @deprecated
  Stream<RouteEvent> get onRoute => onEnter;

  Stream<RouteEvent> get onPreEnter => _onPreEnterController.stream;
  Stream<RouteEvent> get onLeave => _onLeaveController.stream;
  Stream<RouteEvent> get onEnter => _onEnterController.stream;

  Route._new({this.name, this.path, this.parent})
      : _onEnterController =
            new StreamController<RouteEnterEvent>.broadcast(sync: true),
        _onPreEnterController =
            new StreamController<RoutePreEnterEvent>.broadcast(sync: true),
        _onLeaveController =
            new StreamController<RouteLeaveEvent>.broadcast(sync: true);

  void addRoute({String name, Pattern path, bool defaultRoute: false,
      RouteEnterEventHandler enter, RoutePreEnterEventHandler preEnter,
      RouteLeaveEventHandler leave, mount}) {
    if (name == null) {
      throw new ArgumentError('name is required for all routes');
    }
    if (_routes.containsKey(name)) {
      throw new ArgumentError('Route $name already exists');
    }

    var matcher;
    if (!(path is UrlMatcher)) {
      matcher = new UrlTemplate(path.toString());
    } else {
      matcher = path;
    }
    var route = new Route._new(name: name, path: matcher, parent: this);

    if (preEnter != null) {
      route.onPreEnter.listen(preEnter);
    }
    if (enter != null) {
      route.onEnter.listen(enter);
    }
    if (leave != null) {
      route.onLeave.listen(leave);
    }

    if (mount != null) {
      if (mount is Function) {
        mount(route);
      } else if (mount is Routable) {
        mount.configureRoute(route);
      }
    }

    if (defaultRoute) {
      if (_defaultRoute != null) {
        throw new StateError('Only one default route can be added.');
      }
      _defaultRoute = route;
    }
    _routes[name] = route;
  }

  /**
   * Returns a route node at the end of the given route path. Route path
   * dot delimited string of route names.
   */
  Route getRoute(String routePath) {
    var routeName = routePath.split('.').first;
    if (!_routes.containsKey(routeName)) {
      _logger.warning('Invalid route name: $routeName $_routes');<commit_msg>feat: name cannot contain dot.<commit_after>// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library route.client;

import 'dart:async';
import 'dart:collection';
import 'dart:html';

import 'package:logging/logging.dart';

import 'src/utils.dart';

import 'url_matcher.dart';
export 'url_matcher.dart';
import 'url_template.dart';


final _logger = new Logger('route');
final _pathSeparator = '.';

typedef RoutePreEnterEventHandler(RoutePreEnterEvent path);
typedef RouteEnterEventHandler(RouteEnterEvent path);
typedef RouteLeaveEventHandler(RouteLeaveEvent path);

/**
 * A helper Router handle that scopes all route event subsriptions to it's
 * instance and provides an convinience [discard] method.
 */
class RouteHandle implements Route {
  Route _route;
  final StreamController<RoutePreEnterEvent> _onPreEnterController;
  final StreamController<RouteEnterEvent> _onEnterController;
  final StreamController<RouteLeaveEvent> _onLeaveController;

  @deprecated
  Stream<RouteEnterEvent> get onRoute => onEnter;
  Stream<RoutePreEnterEvent> get onPreEnter => _onPreEnterController.stream;
  Stream<RouteEnterEvent> get onEnter => _onEnterController.stream;
  Stream<RouteLeaveEvent> get onLeave => _onLeaveController.stream;

  StreamSubscription _onPreEnterSubscription;
  StreamSubscription _onEnterSubscription;
  StreamSubscription _onLeaveSubscription;
  List<RouteHandle> _childHandles = <RouteHandle>[];

  RouteHandle._new(Route this._route)
      : _onEnterController =
            new StreamController<RouteEnterEvent>.broadcast(sync: true),
        _onPreEnterController =
            new StreamController<RoutePreEnterEvent>.broadcast(sync: true),
        _onLeaveController =
            new StreamController<RouteLeaveEvent>.broadcast(sync: true) {
    _onEnterSubscription = _route.onEnter.listen(_onEnterController.add);
    _onPreEnterSubscription =
        _route.onPreEnter.listen(_onPreEnterController.add);
    _onLeaveSubscription = _route.onLeave.listen(_onLeaveController.add);
  }

  /// discards this handle.
  void discard() {
    _logger.finest('discarding handle for $_route');
    _onPreEnterSubscription.cancel();
    _onEnterSubscription.cancel();
    _onLeaveSubscription.cancel();
    _onEnterController.close();
    _onLeaveController.close();
    _childHandles.forEach((RouteHandle c) => c.discard());
    _childHandles.clear();
    _route = null;
  }

  /// Not supported. Overridden to throw an error.
  void addRoute({String name, Pattern path, bool defaultRoute: false,
    RouteEnterEventHandler enter, RoutePreEnterEventHandler preEnter,
    RouteLeaveEventHandler leave, mount}) =>
          throw new UnsupportedError('addRoute is not supported in handle');

  /// See [Route.getRoute]
  Route getRoute(String routePath) {
    Route r = _assertState(() => _getHost(_route).getRoute(routePath));
    if (r == null) return null;
    var handle = r.newHandle();
    if (handle != null) {
      _childHandles.add(handle);
    }
    return handle;
  }

  /**
   * Create an return a new [RouteHandle] for this route.
   */
  RouteHandle newHandle() {
    _logger.finest('newHandle for $this');
    return new RouteHandle._new(_getHost(_route));
  }

  Route _getHost(Route r) {
    _assertState();
    if (r == null) {
      throw new StateError('Oops?!');
    }
    if ((r is Route) && !(r is RouteHandle)) {
      return r;
    }
    RouteHandle rh = r;
    return rh._getHost(rh._route);
  }

  /// See [Route.reverse]
  String reverse(String tail) =>
      _assertState(() => _getHost(_route).reverse(tail));

  _assertState([f()]) {
    if (_route == null) {
      throw new StateError('This route handle is already discated.');
    }
    if (f != null)  return f();
  }

  /// See [Route.isActive]
  bool get isActive => _route.isActive;

  /// See [Route.parameters]
  Map get parameters => _route.parameters;

  /// See [Route.path]
  UrlMatcher get path => _route.path;

  /// See [Route.name]
  String get name => _route.name;

  /// See [Route.parent]
  Route get parent => _route.parent;
}

childRoute({String name, Pattern path, bool defaultRoute: false,
    RouteEnterEventHandler enter, RoutePreEnterEventHandler preEnter,
    RouteLeaveEventHandler leave, mount}) => (Route route) =>
        route.addRoute(name: name, path: path, defaultRoute: defaultRoute,
            enter: enter, preEnter: preEnter, leave: leave, mount: leave);

/**
 * Route is a node in the tree of routes. The edge leading to the route is
 * defined by path.
 */
class Route {
  final String name;
  final Map<String, Route> _routes = new LinkedHashMap<String, Route>();
  final UrlMatcher path;
  final StreamController<RouteEnterEvent> _onEnterController;
  final StreamController<RoutePreEnterEvent> _onPreEnterController;
  final StreamController<RouteLeaveEvent> _onLeaveController;
  final Route parent;
  Route _defaultRoute;
  Route _currentRoute;
  RouteEvent _lastEvent;

  @deprecated
  Stream<RouteEvent> get onRoute => onEnter;

  Stream<RouteEvent> get onPreEnter => _onPreEnterController.stream;
  Stream<RouteEvent> get onLeave => _onLeaveController.stream;
  Stream<RouteEvent> get onEnter => _onEnterController.stream;

  Route._new({this.name, this.path, this.parent})
      : _onEnterController =
            new StreamController<RouteEnterEvent>.broadcast(sync: true),
        _onPreEnterController =
            new StreamController<RoutePreEnterEvent>.broadcast(sync: true),
        _onLeaveController =
            new StreamController<RouteLeaveEvent>.broadcast(sync: true);

  void addRoute({String name, Pattern path, bool defaultRoute: false,
      RouteEnterEventHandler enter, RoutePreEnterEventHandler preEnter,
      RouteLeaveEventHandler leave, mount}) {
    if (name == null) {
      throw new ArgumentError('name is required for all routes');
    }
    if (name.contains(_pathSeparator)) {
      throw new ArgumentError('name cannot contain dot.');
    }
    if (_routes.containsKey(name)) {
      throw new ArgumentError('Route $name already exists');
    }

    var matcher;
    if (!(path is UrlMatcher)) {
      matcher = new UrlTemplate(path.toString());
    } else {
      matcher = path;
    }
    var route = new Route._new(name: name, path: matcher, parent: this);

    if (preEnter != null) {
      route.onPreEnter.listen(preEnter);
    }
    if (enter != null) {
      route.onEnter.listen(enter);
    }
    if (leave != null) {
      route.onLeave.listen(leave);
    }

    if (mount != null) {
      if (mount is Function) {
        mount(route);
      } else if (mount is Routable) {
        mount.configureRoute(route);
      }
    }

    if (defaultRoute) {
      if (_defaultRoute != null) {
        throw new StateError('Only one default route can be added.');
      }
      _defaultRoute = route;
    }
    _routes[name] = route;
  }

  /**
   * Returns a route node at the end of the given route path. Route path
   * dot delimited string of route names.
   */
  Route getRoute(String routePath) {
    var routeName = routePath.split(_pathSeparator).first;
    if (!_routes.containsKey(routeName)) {
      _logger.warning('Invalid route name: $routeName $_routes');
{'fraction_non_alphanumeric': 0.10714778529046502, 'fraction_numerical': 0.0005519525320822409, 'mean_word_length': 3.648813341885824, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 91, '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': '4462754', 'n_tokens_mistral': 4196, 'n_tokens_neox': 4186, 'n_words': 1139}