Line data Source code
1 : // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 2 : // for details. All rights reserved. Use of this source code is governed by a 3 : // BSD-style license that can be found in the LICENSE file. 4 : 5 : import '../characters.dart' as chars; 6 : import '../internal_style.dart'; 7 : import '../utils.dart'; 8 : 9 : /// The style for URL paths. 10 : class UrlStyle extends InternalStyle { 11 11 : UrlStyle(); 12 : 13 : @override 14 : final name = 'url'; 15 : @override 16 : final separator = '/'; 17 : final separators = const ['/']; 18 : 19 : // Deprecated properties. 20 : 21 : @override 22 : final separatorPattern = RegExp(r'/'); 23 : @override 24 : final needsSeparatorPattern = RegExp(r'(^[a-zA-Z][-+.a-zA-Z\d]*://|[^/])$'); 25 : @override 26 : final rootPattern = RegExp(r'[a-zA-Z][-+.a-zA-Z\d]*://[^/]*'); 27 : @override 28 : final relativeRootPattern = RegExp(r'^/'); 29 : 30 0 : @override 31 0 : bool containsSeparator(String path) => path.contains('/'); 32 : 33 0 : @override 34 0 : bool isSeparator(int codeUnit) => codeUnit == chars.slash; 35 : 36 0 : @override 37 : bool needsSeparator(String path) { 38 0 : if (path.isEmpty) return false; 39 : 40 : // A URL that doesn't end in "/" always needs a separator. 41 0 : if (!isSeparator(path.codeUnitAt(path.length - 1))) return true; 42 : 43 : // A URI that's just "scheme://" needs an extra separator, despite ending 44 : // with "/". 45 0 : return path.endsWith('://') && rootLength(path) == path.length; 46 : } 47 : 48 0 : @override 49 : int rootLength(String path, {bool withDrive = false}) { 50 0 : if (path.isEmpty) return 0; 51 0 : if (isSeparator(path.codeUnitAt(0))) return 1; 52 : 53 0 : for (var i = 0; i < path.length; i++) { 54 0 : final codeUnit = path.codeUnitAt(i); 55 0 : if (isSeparator(codeUnit)) return 0; 56 0 : if (codeUnit == chars.colon) { 57 0 : if (i == 0) return 0; 58 : 59 : // The root part is up until the next '/', or the full path. Skip ':' 60 : // (and '//' if it exists) and search for '/' after that. 61 0 : if (path.startsWith('//', i + 1)) i += 3; 62 0 : final index = path.indexOf('/', i); 63 0 : if (index <= 0) return path.length; 64 : 65 : // file: URLs sometimes consider Windows drive letters part of the root. 66 : // See https://url.spec.whatwg.org/#file-slash-state. 67 0 : if (!withDrive || path.length < index + 3) return index; 68 0 : if (!path.startsWith('file://')) return index; 69 0 : if (!isDriveLetter(path, index + 1)) return index; 70 0 : return path.length == index + 3 ? index + 3 : index + 4; 71 : } 72 : } 73 : 74 : return 0; 75 : } 76 : 77 0 : @override 78 : bool isRootRelative(String path) => 79 0 : path.isNotEmpty && isSeparator(path.codeUnitAt(0)); 80 : 81 0 : @override 82 0 : String? getRelativeRoot(String path) => isRootRelative(path) ? '/' : null; 83 : 84 0 : @override 85 0 : String pathFromUri(Uri uri) => uri.toString(); 86 : 87 0 : @override 88 0 : Uri relativePathToUri(String path) => Uri.parse(path); 89 0 : @override 90 0 : Uri absolutePathToUri(String path) => Uri.parse(path); 91 : }