Skip to content

Commit

Permalink
[refactor] further migrate to correctly handle uris
Browse files Browse the repository at this point in the history
  • Loading branch information
Bungeefan committed Mar 9, 2024
1 parent 986a633 commit c70aca7
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 87 deletions.
4 changes: 1 addition & 3 deletions package/lib/src/beam_location.dart
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,7 @@ class RoutesBeamLocation extends BeamLocation<BeamState> {

final matched = <Pattern, String>{};
var overrideNotFound = false;
final uri = routeInformation.uri.replace(
path: Utils.trimmed(routeInformation.uri.path),
);
final uri = Utils.removeTrailingSlash(routeInformation.uri);

for (final route in routes) {
if (route is String) {
Expand Down
5 changes: 2 additions & 3 deletions package/lib/src/beam_page.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import 'package:beamer/beamer.dart';
import 'package:beamer/src/utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'package:beamer/beamer.dart';

/// Types for how to route should be built.
///
/// See [BeamPage.type]
Expand Down Expand Up @@ -145,7 +144,7 @@ class BeamPage extends Page {

delegate.update(
configuration: delegate.configuration.copyWith(
location: popUri.toString(),
uri: popUri,
state: lastRouteInformation?.state,
),
data: data,
Expand Down
9 changes: 3 additions & 6 deletions package/lib/src/beam_state.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import 'dart:convert';

import 'package:flutter/widgets.dart';

import 'package:beamer/src/utils.dart';
import 'package:beamer/src/beam_location.dart';
import 'package:beamer/src/utils.dart';
import 'package:flutter/widgets.dart';

/// A class to mix with when defining a custom state for [BeamLocation].
///
Expand Down Expand Up @@ -71,10 +70,8 @@ class BeamState with RouteInformationSerializable<BeamState> {
BeamLocation? beamLocation,
Object? routeState,
}) {
uriString = Utils.trimmed(uriString);
final uri = Uri.parse(uriString);
return BeamState.fromUri(
uri,
Utils.removeTrailingSlash(Uri.parse(uriString)),
beamLocation: beamLocation,
routeState: routeState,
);
Expand Down
7 changes: 4 additions & 3 deletions package/lib/src/beamer_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -803,8 +803,9 @@ class BeamerDelegate extends RouterDelegate<RouteInformation>
configuration = currentBeamLocation.state.routeInformation;
} else if (uri.path == '/') {
configuration = RouteInformation(
uri: Uri.parse(
initialPath + (uri.query.isNotEmpty ? '?${uri.query}' : ''),
uri: uri.replace(
path: initialPath,
query: uri.hasQuery ? uri.query : null,
),
);
}
Expand All @@ -815,7 +816,7 @@ class BeamerDelegate extends RouterDelegate<RouteInformation>
@override
SynchronousFuture<void> setNewRoutePath(RouteInformation configuration) {
if (configuration.uri.path == '/' && initialPath != '/') {
configuration = configuration.copyWith(location: initialPath);
configuration = configuration.copyWith(uri: Uri.parse(initialPath));

Check warning on line 819 in package/lib/src/beamer_delegate.dart

View check run for this annotation

Codecov / codecov/patch

package/lib/src/beamer_delegate.dart#L819

Added line #L819 was not covered by tests
}
update(configuration: configuration);
return SynchronousFuture(null);
Expand Down
66 changes: 31 additions & 35 deletions package/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -231,71 +231,67 @@ abstract class Utils {
}
}

/// Removes the trailing / in an URI String and returns the result.
/// Removes the trailing / in an URI path and returns the new URI.
///
/// If there is no trailing /, returns the input.
static String trimmed(String? uriString) {
if (uriString == null) {
return '';
/// If there is no trailing /, returns the input URI.
static Uri removeTrailingSlash(Uri uri) {
String path = uri.path;
if (path.length > 1 && path.endsWith('/')) {
return uri.replace(path: path.substring(0, path.length - 1));
}
if (uriString.length > 1 && uriString.endsWith('/')) {
return uriString.substring(0, uriString.length - 1);
return uri;
}

/// If [incoming] is a relative URI append it to [current].
/// Else, return incoming URI.
static Uri maybeAppend(Uri current, Uri incoming) {
if (!incoming.hasAbsolutePath && !incoming.hasEmptyPath) {
String currentPath =
current.path.endsWith('/') ? current.path : '${current.path}/';
return current.replace(
path: currentPath + incoming.path,
query: incoming.hasQuery ? incoming.query : null,
fragment: incoming.hasFragment ? incoming.fragment : null,
);
}
return uriString;
return incoming;
}

/// If incoming RouteInformation doesn't start with slash,
/// append it to the current RouteInformation.location.
/// Merges the URIs of the RouteInformation's.
///
/// Else, return incoming RouteInformation
static RouteInformation maybeAppend(
/// See [maybeAppend] and [removeTrailingSlash].
static RouteInformation mergeConfiguration(
RouteInformation current,
RouteInformation incoming,
) {
if (!incoming.uri.hasAbsolutePath && !incoming.uri.hasEmptyPath) {
String currentPath = current.uri.path.endsWith('/')
? current.uri.path
: '${current.uri.path}/';
return current.copyWith(
location: current.uri
.replace(
path: currentPath + incoming.uri.path,
query: incoming.uri.hasQuery ? incoming.uri.query : null,
fragment: incoming.uri.hasFragment ? incoming.uri.fragment : null,
)
.toString(),
state: incoming.state,
);
}
return incoming;
return incoming.copyWith(
uri: maybeAppend(current.uri, removeTrailingSlash(incoming.uri)),
);
}

/// Creates a new configuration for [BeamerDelegate.update].
///
/// Takes into consideration trimming and potentially appending
/// the incoming to current (used in relative beaming).
///
/// See [trimmed] and [maybeAppend].
/// See [removeTrailingSlash] and [maybeAppend].
static RouteInformation createNewConfiguration(
RouteInformation current,
RouteInformation incoming,
) {
incoming = incoming.copyWith(
location: trimmed(incoming.uri.toString()),
);
return maybeAppend(current, incoming);
return mergeConfiguration(current, incoming);
}
}

/// Some convenient extension methods on [RouteInformation].
extension BeamerRouteInformationExtension on RouteInformation {
/// Returns a new [RouteInformation] created from this.
RouteInformation copyWith({
String? location,
Uri? uri,
Object? state,
}) {
return RouteInformation(
uri: Uri.parse(location ?? this.uri.toString()),
uri: uri ?? this.uri,
state: state ?? this.state,
);
}
Expand Down
95 changes: 58 additions & 37 deletions package/test/utils_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,83 +125,104 @@ void main() {
});

group('Creating new configuration for BeamerDelegate', () {
test('Trimming', () {
expect(Utils.trimmed(null), '');
expect(Utils.trimmed('/'), '/');
expect(Utils.trimmed('/xxx/'), '/xxx');
test('Remove trailing slashes', () {
expect(Utils.removeTrailingSlash(Uri.parse('')), Uri.parse(''));
expect(Utils.removeTrailingSlash(Uri.parse('/')), Uri.parse('/'));
expect(Utils.removeTrailingSlash(Uri.parse('/xxx/')), Uri.parse('/xxx'));
expect(
Utils.removeTrailingSlash(Uri.parse('https://example.com/')),
Uri.parse('https://example.com/'),
);
expect(
Utils.removeTrailingSlash(Uri.parse('https://example.com/test/')),
Uri.parse('https://example.com/test'),
);
});

test('Appending without new routeState', () {
final current = RouteInformation(uri: Uri.parse('/current'));
test('Appending URIs to relative URI', () {
final current = Uri.parse('/current');
expect(
Utils.maybeAppend(current, RouteInformation(uri: Uri.parse('incoming')))
.uri
.toString(),
Utils.maybeAppend(current, Uri.parse('incoming')).toString(),
'/current/incoming',
);
expect(
Utils.maybeAppend(
current, RouteInformation(uri: Uri.parse('/incoming')))
.uri
.toString(),
Utils.maybeAppend(current, Uri.parse('/incoming')).toString(),
'/incoming',
);
expect(
Utils.maybeAppend(current, RouteInformation(uri: Uri.parse('')))
.uri
.toString(),
Utils.maybeAppend(current, Uri.parse('')).toString(),
'',
);
expect(
Utils.maybeAppend(current, RouteInformation(uri: Uri.parse('/')))
.uri
.toString(),
Utils.maybeAppend(current, Uri.parse('/')).toString(),
'/',
);
expect(
Utils.maybeAppend(current,
RouteInformation(uri: Uri.parse('example://app/incoming')))
.uri
.toString(),
Utils.maybeAppend(
current,
Uri.parse('example://app/incoming'),
).toString(),
'example://app/incoming',
);
expect(
Utils.maybeAppend(current,
RouteInformation(uri: Uri.parse('example://app/incoming')))
.uri
.toString(),
'example://app/incoming',
Utils.maybeAppend(current, Uri.parse('//app/incoming')).toString(),
'//app/incoming',
);
});

test('Appending URIs to absolute URI', () {
final current = Uri.parse('example://app/current');
expect(
Utils.maybeAppend(current, Uri.parse('incoming')).toString(),
'example://app/current/incoming',
);
expect(
Utils.maybeAppend(current, Uri.parse('/incoming')).toString(),
'/incoming',
);
expect(
Utils.maybeAppend(current, Uri.parse('')).toString(),
'',
);
expect(
Utils.maybeAppend(current, Uri.parse('/')).toString(),
'/',
);
expect(
Utils.maybeAppend(
current, RouteInformation(uri: Uri.parse('//app/incoming')))
.uri
.toString(),
current,
Uri.parse('example://app/incoming'),
).toString(),
'example://app/incoming',
);
expect(
Utils.maybeAppend(current, Uri.parse('//app/incoming')).toString(),
'//app/incoming',
);
});

test('Appending with new routeState', () {
test('Merging with new routeState', () {
final current = RouteInformation(uri: Uri.parse('/current'));
expect(
Utils.maybeAppend(current, RouteInformation(uri: Uri(), state: 42))
Utils.mergeConfiguration(
current, RouteInformation(uri: Uri(), state: 42))
.state,
42,
);
expect(
Utils.maybeAppend(current,
Utils.mergeConfiguration(current,
RouteInformation(uri: Uri.parse('incoming'), state: 42))
.state,
42,
);
expect(
Utils.maybeAppend(current,
Utils.mergeConfiguration(current,
RouteInformation(uri: Uri.parse('/incoming'), state: 42))
.state,
42,
);
expect(
Utils.maybeAppend(
Utils.mergeConfiguration(
current,
RouteInformation(
uri: Uri.parse('example://app/incoming'),
Expand All @@ -210,7 +231,7 @@ void main() {
42,
);
expect(
Utils.maybeAppend(
Utils.mergeConfiguration(
current,
RouteInformation(
uri: Uri.parse('//app/incoming'),
Expand Down

0 comments on commit c70aca7

Please sign in to comment.