From 1af4d1a40a0fa27047b400388f57ec3da8ece3c8 Mon Sep 17 00:00:00 2001 From: Valentin Vignal <32538273+ValentinVignal@users.noreply.github.com> Date: Sat, 22 Jul 2023 00:07:51 +0800 Subject: [PATCH] [go_router_builder] Removes `path_to_regexp` from the dependencies (#4524) Fixes https://github.com/flutter/flutter/issues/130817 Relates to https://github.com/flutter/flutter/issues/122713 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- packages/go_router_builder/CHANGELOG.md | 4 ++ .../go_router_builder/lib/src/path_utils.dart | 46 +++++++++++++++++++ .../lib/src/route_config.dart | 34 ++++++-------- packages/go_router_builder/pubspec.yaml | 3 +- .../test/path_utils_test.dart | 40 ++++++++++++++++ script/configs/allowed_unpinned_deps.yaml | 1 - 6 files changed, 104 insertions(+), 24 deletions(-) create mode 100644 packages/go_router_builder/lib/src/path_utils.dart create mode 100644 packages/go_router_builder/test/path_utils_test.dart diff --git a/packages/go_router_builder/CHANGELOG.md b/packages/go_router_builder/CHANGELOG.md index 7e474dd530..74665333fc 100644 --- a/packages/go_router_builder/CHANGELOG.md +++ b/packages/go_router_builder/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.3 + +* Removes `path_to_regexp` from the dependencies. + ## 2.2.2 * Bumps example go_router version and migrate example code. diff --git a/packages/go_router_builder/lib/src/path_utils.dart b/packages/go_router_builder/lib/src/path_utils.dart new file mode 100644 index 0000000000..c47a96f89e --- /dev/null +++ b/packages/go_router_builder/lib/src/path_utils.dart @@ -0,0 +1,46 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +final RegExp _parameterRegExp = RegExp(r':(\w+)(\((?:\\.|[^\\()])+\))?'); + +/// Extracts the path parameters from a [pattern] such as `/user/:id`. +/// +/// The path parameters can be specified by prefixing them with `:`. +/// +/// For example: +/// +/// ```dart +/// final pattern = '/user/:id/book/:bookId'; +/// final pathParameters = pathParametersFromPattern(pattern); // {'id', 'bookId'} +/// ``` +Set pathParametersFromPattern(String pattern) => { + for (final RegExpMatch match in _parameterRegExp.allMatches(pattern)) + match[1]!, + }; + +/// Reconstructs the full path from a [pattern] and path parameters. +/// +/// For example: +/// +/// ```dart +/// final pattern = '/family/:id'; +/// final path = patternToPath(pattern, {'id': 'family-id'}); // '/family/family-id' +/// ``` +String patternToPath(String pattern, Map pathParameters) { + final StringBuffer buffer = StringBuffer(); + int start = 0; + for (final RegExpMatch match in _parameterRegExp.allMatches(pattern)) { + if (match.start > start) { + buffer.write(pattern.substring(start, match.start)); + } + final String name = match[1]!; + buffer.write(pathParameters[name]); + start = match.end; + } + + if (start < pattern.length) { + buffer.write(pattern.substring(start)); + } + return buffer.toString(); +} diff --git a/packages/go_router_builder/lib/src/route_config.dart b/packages/go_router_builder/lib/src/route_config.dart index c009b12c79..ef3b82edfb 100644 --- a/packages/go_router_builder/lib/src/route_config.dart +++ b/packages/go_router_builder/lib/src/route_config.dart @@ -11,10 +11,10 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:collection/collection.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; -import 'package:path_to_regexp/path_to_regexp.dart'; import 'package:source_gen/source_gen.dart'; import 'package:source_helper/source_helper.dart'; +import 'path_utils.dart'; import 'type_helpers.dart'; /// Custom [Iterable] implementation with extra info. @@ -79,12 +79,8 @@ class GoRouteConfig extends RouteBaseConfig { /// The name of the GoRoute to be created by this configuration. final String? name; - late final Set _pathParams = Set.unmodifiable(_parsedPath - .whereType() - .map((ParameterToken e) => e.name)); - - late final List _parsedPath = - List.unmodifiable(parse(_rawJoinedPath)); + late final Set _pathParams = + pathParametersFromPattern(_rawJoinedPath); String get _rawJoinedPath { final List pathSegments = []; @@ -103,22 +99,18 @@ class GoRouteConfig extends RouteBaseConfig { // construct path bits using parent bits // if there are any queryParam objects, add in the `queryParam` bits String get _locationArgs { - final Iterable pathItems = _parsedPath.map((Token e) { - if (e is ParameterToken) { + final Map pathParameters = Map.fromEntries( + _pathParams.map((String pathParameter) { // Enum types are encoded using a map, so we need a nullability check // here to ensure it matches Uri.encodeComponent nullability - final DartType? type = _field(e.name)?.returnType; - return '\${Uri.encodeComponent(${_encodeFor(e.name)}${type?.isEnum ?? false ? '!' : ''})}'; - } - if (e is PathToken) { - return e.value; - } - throw UnsupportedError( - '$likelyIssueMessage ' - 'Token ($e) of type ${e.runtimeType} is not supported.', - ); - }); - return "'${pathItems.join()}'"; + final DartType? type = _field(pathParameter)?.returnType; + final String value = + '\${Uri.encodeComponent(${_encodeFor(pathParameter)}${type?.isEnum ?? false ? '!' : ''})}'; + return MapEntry(pathParameter, value); + }), + ); + final String location = patternToPath(_rawJoinedPath, pathParameters); + return "'$location'"; } ParameterElement? get _extraParam => _ctor.parameters diff --git a/packages/go_router_builder/pubspec.yaml b/packages/go_router_builder/pubspec.yaml index 81b6d54b23..374bcdca08 100644 --- a/packages/go_router_builder/pubspec.yaml +++ b/packages/go_router_builder/pubspec.yaml @@ -2,7 +2,7 @@ name: go_router_builder description: >- A builder that supports generated strongly-typed route helpers for package:go_router -version: 2.2.2 +version: 2.2.3 repository: https://github.com/flutter/packages/tree/main/packages/go_router_builder issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router_builder%22 @@ -17,7 +17,6 @@ dependencies: collection: ^1.14.0 meta: ^1.7.0 path: ^1.8.0 - path_to_regexp: ^0.4.0 source_gen: ^1.0.0 source_helper: ^1.3.0 diff --git a/packages/go_router_builder/test/path_utils_test.dart b/packages/go_router_builder/test/path_utils_test.dart new file mode 100644 index 0000000000..fdd62bac0f --- /dev/null +++ b/packages/go_router_builder/test/path_utils_test.dart @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:go_router_builder/src/path_utils.dart'; +import 'package:test/test.dart'; + +void main() { + group('pathParametersFromPattern', () { + test('It should return the parameters of the path', () { + expect(pathParametersFromPattern('/'), const {}); + expect(pathParametersFromPattern('/user'), const {}); + expect(pathParametersFromPattern('/user/:id'), const {'id'}); + expect(pathParametersFromPattern('/user/:id/book'), const {'id'}); + expect( + pathParametersFromPattern('/user/:id/book/:bookId'), + const {'id', 'bookId'}, + ); + }); + }); + + group('patternToPath', () { + test('It should replace the path parameters with their values', () { + expect(patternToPath('/', const {}), '/'); + expect(patternToPath('/user', const {}), '/user'); + expect( + patternToPath('/user/:id', const {'id': 'user-id'}), + '/user/user-id'); + expect( + patternToPath( + '/user/:id/book', const {'id': 'user-id'}), + '/user/user-id/book'); + expect( + patternToPath('/user/:id/book/:bookId', + const {'id': 'user-id', 'bookId': 'book-id'}), + '/user/user-id/book/book-id', + ); + }); + }); +} diff --git a/script/configs/allowed_unpinned_deps.yaml b/script/configs/allowed_unpinned_deps.yaml index db8043d8a3..e726f4443f 100644 --- a/script/configs/allowed_unpinned_deps.yaml +++ b/script/configs/allowed_unpinned_deps.yaml @@ -13,7 +13,6 @@ # cautious about adding to this list. - build_verify - google_maps -- path_to_regexp - win32 ## Allowed by default