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

Generated by: LCOV version 1.14