LCOV - code coverage report
Current view: top level - src - utils.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 85 85 100.0 %
Date: 2021-06-08 01:09:24 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 (var beamLocation in beamLocations) {
      19           3 :       if (canBeamLocationHandleUri(beamLocation, uri)) {
      20             :         return beamLocation
      21           6 :           ..state = beamLocation.createState(
      22           3 :             BeamState(
      23           3 :               pathBlueprintSegments: uri.pathSegments,
      24           3 :               queryParameters: uri.queryParameters,
      25             :               data: data,
      26             :             ),
      27             :           );
      28             :       }
      29             :     }
      30           4 :     return NotFound(path: uri.path);
      31             :   }
      32             : 
      33             :   /// Can a [beamLocation], depending on its `pathBlueprints`, handle the [uri].
      34             :   ///
      35             :   /// Used in [BeamLocation.canHandle] and [chooseBeamLocation].
      36           3 :   static bool canBeamLocationHandleUri(BeamLocation beamLocation, Uri uri) {
      37           6 :     for (var pathBlueprint in beamLocation.pathBlueprints) {
      38           3 :       if (pathBlueprint is String) {
      39           9 :         if (pathBlueprint == uri.path || pathBlueprint == '/*') {
      40             :           return true;
      41             :         }
      42           6 :         final uriPathSegments = List.from(uri.pathSegments);
      43          10 :         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             :     Map<String, dynamic> data = const <String, dynamic>{},
      82             :   }) {
      83             :     if (beamLocation != null) {
      84             :       // TODO: abstract this and reuse in canBeamLocationHandleUri
      85          16 :       for (var pathBlueprint in beamLocation.pathBlueprints) {
      86           8 :         if (pathBlueprint is String) {
      87          23 :           if (pathBlueprint == uri.path || pathBlueprint == '/*') {
      88           8 :             BeamState(
      89           8 :               pathBlueprintSegments: uri.pathSegments,
      90           8 :               queryParameters: uri.queryParameters,
      91             :               data: data,
      92             :             );
      93             :           }
      94          16 :           final uriPathSegments = List.from(uri.pathSegments);
      95          30 :           if (uriPathSegments.length > 1 && uriPathSegments.last == '') {
      96           1 :             uriPathSegments.removeLast();
      97             :           }
      98             :           final beamLocationPathBlueprintSegments =
      99          16 :               Uri.parse(pathBlueprint).pathSegments;
     100           8 :           var pathSegments = <String>[];
     101           8 :           var pathParameters = <String, String>{};
     102          16 :           if (uriPathSegments.length >
     103           8 :                   beamLocationPathBlueprintSegments.length &&
     104           6 :               !beamLocationPathBlueprintSegments.contains('*')) {
     105             :             continue;
     106             :           }
     107             :           var checksPassed = true;
     108          24 :           for (int i = 0; i < uriPathSegments.length; i++) {
     109          16 :             if (beamLocationPathBlueprintSegments[i] == '*') {
     110           5 :               pathSegments = List<String>.from(uriPathSegments);
     111             :               checksPassed = true;
     112             :               break;
     113             :             }
     114          24 :             if (uriPathSegments[i] != beamLocationPathBlueprintSegments[i] &&
     115          12 :                 beamLocationPathBlueprintSegments[i][0] != ':') {
     116             :               checksPassed = false;
     117             :               break;
     118          24 :             } else if (beamLocationPathBlueprintSegments[i][0] == ':') {
     119          10 :               pathParameters[beamLocationPathBlueprintSegments[i]
     120          10 :                   .substring(1)] = uriPathSegments[i];
     121          10 :               pathSegments.add(beamLocationPathBlueprintSegments[i]);
     122             :             } else {
     123          16 :               pathSegments.add(uriPathSegments[i]);
     124             :             }
     125             :           }
     126             :           if (checksPassed) {
     127           8 :             return BeamState(
     128             :               pathBlueprintSegments: pathSegments,
     129             :               pathParameters: pathParameters,
     130           8 :               queryParameters: uri.queryParameters,
     131             :               data: data,
     132             :             );
     133             :           }
     134             :         } else {
     135           2 :           final regexp = tryCastToRegExp(pathBlueprint);
     136           2 :           var pathParameters = <String, String>{};
     137           2 :           final url = uri.toString();
     138             : 
     139           2 :           if (regexp.hasMatch(url)) {
     140           6 :             regexp.allMatches(url).forEach((match) {
     141           5 :               match.groupNames.forEach((groupName) {
     142           2 :                 pathParameters[groupName] = match.namedGroup(groupName) ?? '';
     143             :               });
     144             :             });
     145           2 :             return BeamState(
     146           2 :               pathBlueprintSegments: uri.pathSegments,
     147             :               pathParameters: pathParameters,
     148           2 :               queryParameters: uri.queryParameters,
     149             :               data: data,
     150             :             );
     151             :           }
     152             :         }
     153             :       }
     154             :     }
     155           9 :     return BeamState(
     156           9 :       pathBlueprintSegments: uri.pathSegments,
     157           9 :       queryParameters: uri.queryParameters,
     158             :       data: data,
     159             :     );
     160             :   }
     161             : 
     162           6 :   static bool urisMatch(dynamic blueprint, Uri exact) {
     163           6 :     if (blueprint is String) {
     164           6 :       blueprint = Uri.parse(blueprint);
     165           6 :       final blueprintSegments = blueprint.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 :       blueprint = tryCastToRegExp(blueprint);
     181           2 :       return blueprint.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(dynamic 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          27 :     if (uri.length > 1 && uri.endsWith('/')) {
     205           3 :       return uri.substring(0, uri.length - 1);
     206             :     }
     207             :     return uri;
     208             :   }
     209             : }

Generated by: LCOV version 1.14