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();
}