blob: 35a03aa9c6037e83099a02750ce69300b35a7919 [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 'package:flutter/foundation.dart';
import 'go_route.dart';
import 'go_route_information_parser.dart';
import 'path_parser.dart';
/// Each GoRouteMatch instance represents an instance of a GoRoute for a
/// specific portion of a location.
class GoRouteMatch {
/// Constructor for GoRouteMatch, each instance represents an instance of a
/// GoRoute for a specific portion of a location.
GoRouteMatch({
required this.route,
required this.subloc,
required this.fullpath,
required this.encodedParams,
required this.queryParams,
required this.extra,
required this.error,
this.pageKey,
}) : fullUriString = _addQueryParams(subloc, queryParams),
assert(subloc.startsWith('/')),
assert(Uri.parse(subloc).queryParameters.isEmpty),
assert(fullpath.startsWith('/')),
assert(Uri.parse(fullpath).queryParameters.isEmpty),
assert(() {
for (final MapEntry<String, String> p in encodedParams.entries) {
assert(p.value == Uri.encodeComponent(Uri.decodeComponent(p.value)),
'encodedParams[${p.key}] is not encoded properly: "${p.value}"');
}
return true;
}());
// ignore: public_member_api_docs
static GoRouteMatch? match({
required GoRoute route,
required String restLoc, // e.g. person/p1
required String parentSubloc, // e.g. /family/f2
required String fullpath, // e.g. /family/:fid/person/:pid
required Map<String, String> queryParams,
required Object? extra,
}) {
assert(!route.path.contains('//'));
final RegExpMatch? match = route.matchPatternAsPrefix(restLoc);
if (match == null) {
return null;
}
final Map<String, String> encodedParams = route.extractPathParams(match);
final String pathLoc = patternToPath(route.path, encodedParams);
final String subloc =
GoRouteInformationParser.concatenatePaths(parentSubloc, pathLoc);
return GoRouteMatch(
route: route,
subloc: subloc,
fullpath: fullpath,
encodedParams: encodedParams,
queryParams: queryParams,
extra: extra,
error: null,
);
}
/// The matched route.
final GoRoute route;
/// Matched sub-location.
final String subloc; // e.g. /family/f2
/// Matched full path.
final String fullpath; // e.g. /family/:fid
/// Parameters for the matched route, URI-encoded.
final Map<String, String> encodedParams;
/// Query parameters for the matched route.
final Map<String, String> queryParams;
/// An extra object to pass along with the navigation.
final Object? extra;
/// An exception if there was an error during matching.
final Exception? error;
/// Optional value key of type string, to hold a unique reference to a page.
final ValueKey<String>? pageKey;
/// The full uri string
final String fullUriString; // e.g. /family/12?query=14
static String _addQueryParams(String loc, Map<String, String> queryParams) {
final Uri uri = Uri.parse(loc);
assert(uri.queryParameters.isEmpty);
return Uri(
path: uri.path,
queryParameters: queryParams.isEmpty ? null : queryParams)
.toString();
}
/// Parameters for the matched route, URI-decoded.
Map<String, String> get decodedParams => <String, String>{
for (final MapEntry<String, String> param in encodedParams.entries)
param.key: Uri.decodeComponent(param.value)
};
/// for use by the Router architecture as part of the GoRouteMatch
@override
String toString() => 'GoRouteMatch($fullpath, $encodedParams)';
}