LCOV - code coverage report
Current view: top level - src - utils.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 84 84 100.0 %
Date: 2021-07-18 19:09:57 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:beamer/beamer.dart';
       2             : import 'package:flutter/material.dart';
       3             : 
       4             : abstract class Utils {
       5             :   /// Traverses [beamLocations] and returns the one whose one of
       6             :   /// `pathBlueprints` contains the [uri], ignoring concrete path parameters.
       7             :   ///
       8             :   /// Upon finding such [BeamLocation], configures it with
       9             :   /// `pathParameters` and `queryParameters` from [uri].
      10             :   ///
      11             :   /// If [beamLocations] don't contain a match, [NotFound] will be returned
      12             :   /// configured with [uri].
      13           3 :   static BeamLocation chooseBeamLocation(
      14             :     Uri uri,
      15             :     List<BeamLocation> beamLocations, {
      16             :     Map<String, dynamic> data = const <String, dynamic>{},
      17             :   }) {
      18           6 :     for (final beamLocation in beamLocations) {
      19           3 :       if (canBeamLocationHandleUri(beamLocation, uri)) {
      20             :         return beamLocation
      21           6 :           ..state = beamLocation.createState(
      22           3 :             RouteInformation(
      23           3 :               location: uri.toString(),
      24             :               state: data,
      25             :             ),
      26             :           );
      27             :       }
      28             :     }
      29           4 :     return NotFound(path: uri.path);
      30             :   }
      31             : 
      32             :   /// Can a [beamLocation], depending on its `pathBlueprints`, handle the [uri].
      33             :   ///
      34             :   /// Used in [BeamLocation.canHandle] and [chooseBeamLocation].
      35           3 :   static bool canBeamLocationHandleUri(BeamLocation beamLocation, Uri uri) {
      36           6 :     for (final pathBlueprint in beamLocation.pathBlueprints) {
      37           3 :       if (pathBlueprint is String) {
      38           9 :         if (pathBlueprint == uri.path || pathBlueprint == '/*') {
      39             :           return true;
      40             :         }
      41           6 :         final uriPathSegments = uri.pathSegments.toList();
      42          12 :         if (uriPathSegments.length > 1 && uriPathSegments.last == '') {
      43           1 :           uriPathSegments.removeLast();
      44             :         }
      45             :         final beamLocationPathBlueprintSegments =
      46           6 :             Uri.parse(pathBlueprint).pathSegments;
      47           9 :         if (uriPathSegments.length > beamLocationPathBlueprintSegments.length &&
      48           1 :             !beamLocationPathBlueprintSegments.contains('*')) {
      49             :           continue;
      50             :         }
      51             :         var checksPassed = true;
      52           9 :         for (int i = 0; i < uriPathSegments.length; i++) {
      53           6 :           if (beamLocationPathBlueprintSegments[i] == '*') {
      54             :             checksPassed = true;
      55             :             break;
      56             :           }
      57           9 :           if (uriPathSegments[i] != beamLocationPathBlueprintSegments[i] &&
      58           9 :               beamLocationPathBlueprintSegments[i][0] != ':') {
      59             :             checksPassed = false;
      60             :             break;
      61             :           }
      62             :         }
      63             :         if (checksPassed) {
      64             :           return true;
      65             :         }
      66             :       } else {
      67           1 :         final regexp = tryCastToRegExp(pathBlueprint);
      68           2 :         return regexp.hasMatch(uri.toString());
      69             :       }
      70             :     }
      71             :     return false;
      72             :   }
      73             : 
      74             :   /// Creates a state for [BeamLocation] based on incoming [uri].
      75             :   ///
      76             :   /// Used in [BeamState.copyForLocation].
      77           9 :   static BeamState createBeamState(
      78             :     Uri uri, {
      79             :     BeamLocation? beamLocation,
      80             :     Map<String, dynamic> data = const <String, dynamic>{},
      81             :   }) {
      82             :     if (beamLocation != null) {
      83             :       // TODO: abstract this and reuse in canBeamLocationHandleUri
      84          18 :       for (final pathBlueprint in beamLocation.pathBlueprints) {
      85           9 :         if (pathBlueprint is String) {
      86          27 :           if (pathBlueprint == uri.path || pathBlueprint == '/*') {
      87           7 :             BeamState(
      88           7 :               pathBlueprintSegments: uri.pathSegments,
      89           7 :               queryParameters: uri.queryParameters,
      90             :               data: data,
      91             :             );
      92             :           }
      93          18 :           final uriPathSegments = uri.pathSegments.toList();
      94          34 :           if (uriPathSegments.length > 1 && uriPathSegments.last == '') {
      95           1 :             uriPathSegments.removeLast();
      96             :           }
      97             :           final beamLocationPathBlueprintSegments =
      98          18 :               Uri.parse(pathBlueprint).pathSegments;
      99           9 :           var pathSegments = <String>[];
     100           9 :           final pathParameters = <String, String>{};
     101          18 :           if (uriPathSegments.length >
     102           9 :                   beamLocationPathBlueprintSegments.length &&
     103           6 :               !beamLocationPathBlueprintSegments.contains('*')) {
     104             :             continue;
     105             :           }
     106             :           var checksPassed = true;
     107          27 :           for (int i = 0; i < uriPathSegments.length; i++) {
     108          18 :             if (beamLocationPathBlueprintSegments[i] == '*') {
     109           5 :               pathSegments = uriPathSegments.toList();
     110             :               checksPassed = true;
     111             :               break;
     112             :             }
     113          27 :             if (uriPathSegments[i] != beamLocationPathBlueprintSegments[i] &&
     114          18 :                 beamLocationPathBlueprintSegments[i][0] != ':') {
     115             :               checksPassed = false;
     116             :               break;
     117          27 :             } else if (beamLocationPathBlueprintSegments[i][0] == ':') {
     118          12 :               pathParameters[beamLocationPathBlueprintSegments[i]
     119          12 :                   .substring(1)] = uriPathSegments[i];
     120          12 :               pathSegments.add(beamLocationPathBlueprintSegments[i]);
     121             :             } else {
     122          18 :               pathSegments.add(uriPathSegments[i]);
     123             :             }
     124             :           }
     125             :           if (checksPassed) {
     126           9 :             return BeamState(
     127             :               pathBlueprintSegments: pathSegments,
     128             :               pathParameters: pathParameters,
     129           9 :               queryParameters: uri.queryParameters,
     130             :               data: data,
     131             :             );
     132             :           }
     133             :         } else {
     134           2 :           final regexp = tryCastToRegExp(pathBlueprint);
     135           2 :           final pathParameters = <String, String>{};
     136           2 :           final url = uri.toString();
     137             : 
     138           2 :           if (regexp.hasMatch(url)) {
     139           6 :             regexp.allMatches(url).forEach((match) {
     140           3 :               for (final groupName in match.groupNames) {
     141           2 :                 pathParameters[groupName] = match.namedGroup(groupName) ?? '';
     142             :               }
     143             :             });
     144           2 :             return BeamState(
     145           2 :               pathBlueprintSegments: uri.pathSegments,
     146             :               pathParameters: pathParameters,
     147           2 :               queryParameters: uri.queryParameters,
     148             :               data: data,
     149             :             );
     150             :           }
     151             :         }
     152             :       }
     153             :     }
     154           9 :     return BeamState(
     155           9 :       pathBlueprintSegments: uri.pathSegments,
     156           9 :       queryParameters: uri.queryParameters,
     157             :       data: data,
     158             :     );
     159             :   }
     160             : 
     161           6 :   static bool urisMatch(Pattern blueprint, Uri exact) {
     162           6 :     if (blueprint is String) {
     163           6 :       final uriBlueprint = Uri.parse(blueprint);
     164           6 :       final blueprintSegments = uriBlueprint.pathSegments;
     165           6 :       final exactSegment = exact.pathSegments;
     166          18 :       if (blueprintSegments.length != exactSegment.length) {
     167             :         return false;
     168             :       }
     169          18 :       for (int i = 0; i < blueprintSegments.length; i++) {
     170          12 :         if (blueprintSegments[i].startsWith(':')) {
     171             :           continue;
     172             :         }
     173          18 :         if (blueprintSegments[i] != exactSegment[i]) {
     174             :           return false;
     175             :         }
     176             :       }
     177             :       return true;
     178             :     } else {
     179           1 :       final regExpBlueprint = tryCastToRegExp(blueprint);
     180           2 :       return regExpBlueprint.hasMatch(exact.toString());
     181             :     }
     182             :   }
     183             : 
     184             :   /// Wraps the casting of pathBlueprint to RegExp inside a try-catch
     185             :   /// and throws a nice FlutterError.
     186           3 :   static RegExp tryCastToRegExp(Pattern pathBlueprint) {
     187             :     try {
     188             :       return pathBlueprint as RegExp;
     189           1 :     } on TypeError catch (_) {
     190           2 :       throw FlutterError.fromParts([
     191           1 :         DiagnosticsNode.message('Path blueprint can either be:',
     192             :             level: DiagnosticLevel.summary),
     193           1 :         DiagnosticsNode.message('1. String'),
     194           1 :         DiagnosticsNode.message('2. RegExp instance')
     195             :       ]);
     196             :     }
     197             :   }
     198             : 
     199             :   /// Removes the trailing / in an URI String and returns the result.
     200             :   ///
     201             :   /// If there is no trailing /, returns the input.
     202           7 :   static String trimmed(String? uri) {
     203             :     if (uri == null) {
     204             :       return '/';
     205             :     }
     206          21 :     if (uri.length > 1 && uri.endsWith('/')) {
     207           3 :       return uri.substring(0, uri.length - 1);
     208             :     }
     209             :     return uri;
     210             :   }
     211             : }

Generated by: LCOV version 1.14