RouteNode constructor

RouteNode(
  1. List<RouteSpecification?> specs, {
  2. int depth = 0,
  3. RegExp? matcher,
})

Implementation

RouteNode(List<RouteSpecification?> specs, {int depth = 0, RegExp? matcher}) {
  patternMatcher = matcher;

  final terminatedAtThisDepth =
      specs.where((spec) => spec?.segments.length == depth).toList();
  if (terminatedAtThisDepth.length > 1) {
    throw ArgumentError(
      "Router compilation failed. Cannot disambiguate from the following routes: $terminatedAtThisDepth.",
    );
  } else if (terminatedAtThisDepth.length == 1) {
    specification = terminatedAtThisDepth.first;
  }

  final remainingSpecifications = List<RouteSpecification?>.from(
    specs.where((spec) => depth != spec?.segments.length),
  );

  final Set<String> childEqualitySegments = Set.from(
    remainingSpecifications
        .where((spec) => spec?.segments[depth].isLiteralMatcher ?? false)
        .map((spec) => spec!.segments[depth].literal),
  );

  for (final childSegment in childEqualitySegments) {
    final childrenBeginningWithThisSegment = remainingSpecifications
        .where((spec) => spec?.segments[depth].literal == childSegment)
        .toList();
    equalityChildren[childSegment] =
        RouteNode(childrenBeginningWithThisSegment, depth: depth + 1);
    remainingSpecifications
        .removeWhere(childrenBeginningWithThisSegment.contains);
  }

  final takeAllSegment = remainingSpecifications.firstWhere(
    (spec) => spec?.segments[depth].isRemainingMatcher ?? false,
    orElse: () => null,
  );
  if (takeAllSegment != null) {
    takeAllChild = RouteNode.withSpecification(takeAllSegment);
    remainingSpecifications.removeWhere(
      (spec) => spec?.segments[depth].isRemainingMatcher ?? false,
    );
  }

  final Set<String?> childPatternedSegments = Set.from(
    remainingSpecifications
        .map((spec) => spec?.segments[depth].matcher?.pattern),
  );

  patternedChildren = childPatternedSegments.map((pattern) {
    final childrenWithThisPattern = remainingSpecifications
        .where((spec) => spec?.segments[depth].matcher?.pattern == pattern)
        .toList();

    if (childrenWithThisPattern
            .any((spec) => spec?.segments[depth].matcher == null) &&
        childrenWithThisPattern
            .any((spec) => spec?.segments[depth].matcher != null)) {
      throw ArgumentError(
        "Router compilation failed. Cannot disambiguate from the following routes, as one of them will match anything: $childrenWithThisPattern.",
      );
    }

    return RouteNode(
      childrenWithThisPattern,
      depth: depth + 1,
      matcher: childrenWithThisPattern.first?.segments[depth].matcher,
    );
  }).toList();
}