Line data Source code
1 : import 'dart:collection'; 2 : 3 : import 'package:flutter/widgets.dart'; 4 : import 'package:get/src/routes/get_route.dart'; 5 : 6 : class GetPageMatch { 7 1 : GetPageMatch(this.route); 8 : 9 : GetPage route; 10 : Map<String, String> parameters = <String, String>{}; 11 : } 12 : 13 : class ParseRouteTree { 14 : final List<ParseRouteTreeNode> _nodes = <ParseRouteTreeNode>[]; 15 : // bool _hasDefaultRoute = false; 16 : 17 1 : void addRoute(GetPage route) { 18 1 : String path = route.name; 19 : 20 1 : if (path == Navigator.defaultRouteName) { 21 : // if (_hasDefaultRoute) { 22 : // throw ("Default route was already defined"); 23 : // } 24 1 : var node = ParseRouteTreeNode(path, ParseRouteTreeNodeType.component); 25 3 : node.routes = HashSet<GetPage>()..add(route); 26 2 : _nodes.add(node); 27 : // _hasDefaultRoute = true; 28 : return; 29 : } 30 1 : if (path.startsWith("/")) { 31 1 : path = path.substring(1); 32 : } 33 1 : List<String> pathComponents = path.split('/'); 34 : ParseRouteTreeNode parent; 35 3 : for (int i = 0; i < pathComponents.length; i++) { 36 1 : String component = pathComponents[i]; 37 1 : ParseRouteTreeNode node = _nodeForComponent(component, parent); 38 : if (node == null) { 39 1 : ParseRouteTreeNodeType type = _typeForComponent(component); 40 1 : node = ParseRouteTreeNode(component, type); 41 1 : node.parent = parent; 42 : if (parent == null) { 43 2 : _nodes.add(node); 44 : } else { 45 0 : parent.nodes.add(node); 46 : } 47 : } 48 3 : if (i == pathComponents.length - 1) { 49 1 : if (node.routes == null) { 50 0 : node.routes = HashSet<GetPage>()..add(route); 51 : } else { 52 2 : node.routes.add(route); 53 : } 54 : } 55 : parent = node; 56 : } 57 : } 58 : 59 1 : GetPageMatch matchRoute(String path) { 60 : String usePath = path; 61 1 : if (usePath.startsWith("/")) { 62 1 : usePath = path.substring(1); 63 : } 64 1 : List<String> components = usePath.split("/"); 65 1 : if (path == Navigator.defaultRouteName) { 66 1 : components = ["/"]; 67 : } 68 : 69 : Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> nodeMatches = 70 1 : <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{}; 71 1 : List<ParseRouteTreeNode> nodesToCheck = _nodes; 72 2 : for (String checkComponent in components) { 73 : Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> currentMatches = 74 1 : <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{}; 75 1 : List<ParseRouteTreeNode> nextNodes = <ParseRouteTreeNode>[]; 76 2 : for (ParseRouteTreeNode node in nodesToCheck) { 77 : String pathPart = checkComponent; 78 1 : Map<String, String> queryMap = {}; 79 : 80 1 : if (checkComponent.contains("?") && !checkComponent.contains("=")) { 81 0 : var splitParam = checkComponent.split("?"); 82 0 : pathPart = splitParam[0]; 83 0 : queryMap = {pathPart: splitParam[1]}; 84 1 : } else if (checkComponent.contains("?")) { 85 0 : var splitParam = checkComponent.split("?"); 86 0 : var splitParam2 = splitParam[1].split("="); 87 0 : if (!splitParam2[1].contains("&")) { 88 0 : pathPart = splitParam[0]; 89 0 : queryMap = {splitParam2[0]: splitParam2[1]}; 90 : } else { 91 0 : pathPart = splitParam[0]; 92 0 : final segunda = splitParam[1]; 93 0 : var other = segunda.split(RegExp(r"[&,=]")); 94 0 : for (var i = 0; i < (other.length - 1); i++) { 95 0 : bool impar = (i % 2 == 0); 96 : if (impar) { 97 0 : queryMap.addAll({other[0 + i]: other[1 + i]}); 98 : } 99 : } 100 : } 101 : } 102 : 103 3 : bool isMatch = (node.part == pathPart || node.isParameter()); 104 : if (isMatch) { 105 2 : ParseRouteTreeNodeMatch parentMatch = nodeMatches[node.parent]; 106 : ParseRouteTreeNodeMatch match = 107 1 : ParseRouteTreeNodeMatch.fromMatch(parentMatch, node); 108 1 : if (node.isParameter()) { 109 0 : String paramKey = node.part.substring(1); 110 0 : match.parameters[paramKey] = pathPart; 111 : } 112 : if (queryMap != null) { 113 2 : match.parameters.addAll(queryMap); 114 : } 115 : 116 1 : currentMatches[node] = match; 117 1 : if (node.nodes != null) { 118 2 : nextNodes.addAll(node.nodes); 119 : } 120 : } 121 : } 122 : nodeMatches = currentMatches; 123 : nodesToCheck = nextNodes; 124 3 : if (currentMatches.values.length == 0) { 125 : return null; 126 : } 127 : } 128 2 : List<ParseRouteTreeNodeMatch> matches = nodeMatches.values.toList(); 129 2 : if (matches.length > 0) { 130 1 : ParseRouteTreeNodeMatch match = matches.first; 131 1 : ParseRouteTreeNode nodeToUse = match.node; 132 : 133 : if (nodeToUse != null && 134 1 : nodeToUse.routes != null && 135 3 : nodeToUse.routes.length > 0) { 136 1 : HashSet<GetPage> routes = nodeToUse.routes; 137 2 : GetPageMatch routeMatch = GetPageMatch(routes.first); 138 : 139 2 : routeMatch.parameters = match.parameters; 140 : 141 : return routeMatch; 142 : } 143 : } 144 : return null; 145 : } 146 : 147 1 : ParseRouteTreeNode _nodeForComponent( 148 : String component, ParseRouteTreeNode parent) { 149 1 : List<ParseRouteTreeNode> nodes = _nodes; 150 : if (parent != null) { 151 0 : nodes = parent.nodes; 152 : } 153 2 : for (ParseRouteTreeNode node in nodes) { 154 2 : if (node.part == component) { 155 : return node; 156 : } 157 : } 158 : return null; 159 : } 160 : 161 1 : ParseRouteTreeNodeType _typeForComponent(String component) { 162 : ParseRouteTreeNodeType type = ParseRouteTreeNodeType.component; 163 1 : if (_isParameterComponent(component)) { 164 : type = ParseRouteTreeNodeType.parameter; 165 : } 166 : return type; 167 : } 168 : 169 1 : bool _isParameterComponent(String component) { 170 1 : return component.startsWith(":"); 171 : } 172 : 173 0 : Map<String, String> parseQueryString(String query) { 174 0 : var search = RegExp('([^&=]+)=?([^&]*)'); 175 0 : var params = Map<String, String>(); 176 0 : if (query.startsWith('?')) query = query.substring(1); 177 0 : decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' ')); 178 0 : for (Match match in search.allMatches(query)) { 179 0 : String key = decode(match.group(1)); 180 0 : String value = decode(match.group(2)); 181 0 : params[key] = value; 182 : } 183 : return params; 184 : } 185 : } 186 : 187 : class ParseRouteTreeNodeMatch { 188 0 : ParseRouteTreeNodeMatch(this.node); 189 : 190 1 : ParseRouteTreeNodeMatch.fromMatch(ParseRouteTreeNodeMatch match, this.node) { 191 2 : parameters = <String, String>{}; 192 : if (match != null) { 193 0 : parameters.addAll(match.parameters); 194 : } 195 : } 196 : 197 : ParseRouteTreeNode node; 198 : Map<String, String> parameters = <String, String>{}; 199 : } 200 : 201 : class ParseRouteTreeNode { 202 1 : ParseRouteTreeNode(this.part, this.type); 203 : 204 : String part; 205 : ParseRouteTreeNodeType type; 206 : HashSet<GetPage> routes = HashSet<GetPage>(); 207 : List<ParseRouteTreeNode> nodes = <ParseRouteTreeNode>[]; 208 : ParseRouteTreeNode parent; 209 : 210 1 : bool isParameter() { 211 2 : return type == ParseRouteTreeNodeType.parameter; 212 : } 213 : } 214 : 215 12 : enum ParseRouteTreeNodeType { 216 12 : component, 217 12 : parameter, 218 : }