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-12-12 20:09:16 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:beamer/beamer.dart';
       2             : import 'package:flutter/material.dart';
       3             : 
       4             : /// Some useful methods for beaming process configuration.
       5             : abstract class Utils {
       6             :   /// Traverses [beamLocations] and returns the one whose one of
       7             :   /// `pathPatterns` contains the [uri], ignoring concrete path parameters.
       8             :   ///
       9             :   /// Upon finding such [BeamLocation], configures it with
      10             :   /// `pathParameters` and `queryParameters` from [uri].
      11             :   ///
      12             :   /// If [beamLocations] don't contain a match, [NotFound] will be returned
      13             :   /// configured with [uri].
      14           3 :   static BeamLocation chooseBeamLocation(
      15             :     Uri uri,
      16             :     List<BeamLocation> beamLocations, {
      17             :     Object? data,
      18             :     Object? routeState,
      19             :   }) {
      20           6 :     for (final beamLocation in beamLocations) {
      21           3 :       if (canBeamLocationHandleUri(beamLocation, uri)) {
      22           3 :         final routeInformation = RouteInformation(
      23           3 :           location: uri.toString(),
      24             :           state: routeState,
      25             :         );
      26           3 :         return beamLocation..create(routeInformation);
      27             :       }
      28             :     }
      29           4 :     return NotFound(path: uri.path);
      30             :   }
      31             : 
      32             :   /// Can a [beamLocation], depending on its `pathPatterns`, 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.pathPatterns) {
      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 (var 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          10 :   static BeamState createBeamState(
      78             :     Uri uri, {
      79             :     BeamLocation? beamLocation,
      80             :     Object? routeState,
      81             :   }) {
      82             :     if (beamLocation != null) {
      83             :       // TODO: abstract this and reuse in canBeamLocationHandleUri
      84          20 :       for (final pathBlueprint in beamLocation.pathPatterns) {
      85          10 :         if (pathBlueprint is String) {
      86          30 :           if (pathBlueprint == uri.path || pathBlueprint == '/*') {
      87           8 :             BeamState(
      88           8 :               pathPatternSegments: uri.pathSegments,
      89           8 :               queryParameters: uri.queryParameters,
      90             :               routeState: routeState,
      91             :             );
      92             :           }
      93          20 :           final uriPathSegments = uri.pathSegments.toList();
      94          40 :           if (uriPathSegments.length > 1 && uriPathSegments.last == '') {
      95           1 :             uriPathSegments.removeLast();
      96             :           }
      97             :           final beamLocationPathBlueprintSegments =
      98          20 :               Uri.parse(pathBlueprint).pathSegments;
      99          10 :           var pathSegments = <String>[];
     100          10 :           final pathParameters = <String, String>{};
     101          20 :           if (uriPathSegments.length >
     102          10 :                   beamLocationPathBlueprintSegments.length &&
     103           6 :               !beamLocationPathBlueprintSegments.contains('*')) {
     104             :             continue;
     105             :           }
     106             :           var checksPassed = true;
     107          30 :           for (var i = 0; i < uriPathSegments.length; i++) {
     108          20 :             if (beamLocationPathBlueprintSegments[i] == '*') {
     109           5 :               pathSegments = uriPathSegments.toList();
     110             :               checksPassed = true;
     111             :               break;
     112             :             }
     113          30 :             if (uriPathSegments[i] != beamLocationPathBlueprintSegments[i] &&
     114          27 :                 beamLocationPathBlueprintSegments[i][0] != ':') {
     115             :               checksPassed = false;
     116             :               break;
     117          30 :             } else if (beamLocationPathBlueprintSegments[i][0] == ':') {
     118          14 :               pathParameters[beamLocationPathBlueprintSegments[i]
     119          14 :                   .substring(1)] = uriPathSegments[i];
     120          14 :               pathSegments.add(beamLocationPathBlueprintSegments[i]);
     121             :             } else {
     122          20 :               pathSegments.add(uriPathSegments[i]);
     123             :             }
     124             :           }
     125             :           if (checksPassed) {
     126          10 :             return BeamState(
     127             :               pathPatternSegments: pathSegments,
     128             :               pathParameters: pathParameters,
     129          10 :               queryParameters: uri.queryParameters,
     130             :               routeState: routeState,
     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 :               pathPatternSegments: uri.pathSegments,
     146             :               pathParameters: pathParameters,
     147           2 :               queryParameters: uri.queryParameters,
     148             :               routeState: routeState,
     149             :             );
     150             :           }
     151             :         }
     152             :       }
     153             :     }
     154          10 :     return BeamState(
     155          10 :       pathPatternSegments: uri.pathSegments,
     156          10 :       queryParameters: uri.queryParameters,
     157             :       routeState: routeState,
     158             :     );
     159             :   }
     160             : 
     161             :   /// Whether the [pattern] can match the [exact] URI.
     162           6 :   static bool urisMatch(Pattern pattern, Uri exact) {
     163           6 :     if (pattern is String) {
     164           6 :       final uriPattern = Uri.parse(pattern);
     165           6 :       final patternSegments = uriPattern.pathSegments;
     166           6 :       final exactSegment = exact.pathSegments;
     167          18 :       if (patternSegments.length != exactSegment.length) {
     168             :         return false;
     169             :       }
     170          18 :       for (var i = 0; i < patternSegments.length; i++) {
     171          12 :         if (patternSegments[i].startsWith(':')) {
     172             :           continue;
     173             :         }
     174          18 :         if (patternSegments[i] != exactSegment[i]) {
     175             :           return false;
     176             :         }
     177             :       }
     178             :       return true;
     179             :     } else {
     180           1 :       final regExpPattern = tryCastToRegExp(pattern);
     181           2 :       return regExpPattern.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           9 :   static String trimmed(String? uri) {
     204             :     if (uri == null) {
     205             :       return '/';
     206             :     }
     207          27 :     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