blob: 61a89b8d36784915c1738e53e18dd0af2afd48a9 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'configuration.dart';
import 'information_provider.dart';
import 'logging.dart';
import 'matching.dart';
import 'redirection.dart';
/// Converts between incoming URLs and a [RouteMatchList] using [RouteMatcher].
/// Also performs redirection using [RouteRedirector].
class GoRouteInformationParser extends RouteInformationParser<RouteMatchList> {
/// Creates a [GoRouteInformationParser].
required this.configuration,
this.debugRequireGoRouteInformationProvider = false,
}) : matcher = RouteMatcher(configuration),
redirector = redirect;
/// The route configuration for the app.
final RouteConfiguration configuration;
/// The route matcher.
final RouteMatcher matcher;
/// The route redirector.
final RouteRedirector redirector;
/// A debug property to assert [GoRouteInformationProvider] is in use along
/// with this parser.
/// An assertion error will be thrown if this property set to true and the
/// [GoRouteInformationProvider] is not in use.
/// Defaults to false.
final bool debugRequireGoRouteInformationProvider;
/// The future of current route parsing.
/// This is used for testing asynchronous redirection.
Future<RouteMatchList>? debugParserFuture;
/// Called by the [Router]. The
Future<RouteMatchList> parseRouteInformationWithDependencies(
RouteInformation routeInformation,
BuildContext context,
) {
late final RouteMatchList initialMatches;
try {
initialMatches = matcher.findMatch(routeInformation.location!,
extra: routeInformation.state);
} on MatcherError {'No initial matches: ${routeInformation.location}');
// If there is a matching error for the initial location, we should
// still try to process the top-level redirects.
initialMatches = RouteMatchList.empty();
Future<RouteMatchList> processRedirectorResult(RouteMatchList matches) {
if (matches.isEmpty) {
return SynchronousFuture<RouteMatchList>(errorScreen(
MatcherError('no routes for location', routeInformation.location!)
return SynchronousFuture<RouteMatchList>(matches);
final FutureOr<RouteMatchList> redirectorResult = redirector(
extra: routeInformation.state,
if (redirectorResult is RouteMatchList) {
return processRedirectorResult(redirectorResult);
return debugParserFuture = redirectorResult.then(processRedirectorResult);
Future<RouteMatchList> parseRouteInformation(
RouteInformation routeInformation) {
throw UnimplementedError(
'use parseRouteInformationWithDependencies instead');
/// for use by the Router architecture as part of the RouteInformationParser
RouteInformation restoreRouteInformation(RouteMatchList configuration) {
return RouteInformation(
location: configuration.location.toString(),
state: configuration.extra,