You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.6 KiB
139 lines
3.6 KiB
1 year ago
|
import 'package:built_collection/built_collection.dart';
|
||
|
import 'package:collection/collection.dart';
|
||
|
import 'package:meta/meta.dart';
|
||
|
|
||
|
/// A `Uri` like object that is specialized in file path handling.
|
||
|
@immutable
|
||
|
class PathUri {
|
||
|
/// Creates a new path URI.
|
||
|
const PathUri({
|
||
|
required this.isAbsolute,
|
||
|
required this.isDirectory,
|
||
|
required this.pathSegments,
|
||
|
});
|
||
|
|
||
|
/// Creates a new `PathUri` object by parsing a [path] string.
|
||
|
///
|
||
|
/// An empty [path] is considered to be the current working directory.
|
||
|
factory PathUri.parse(final String path) {
|
||
|
final parts = path.split('/');
|
||
|
if (parts.length == 1 && parts.single.isEmpty) {
|
||
|
return PathUri(
|
||
|
isAbsolute: false,
|
||
|
isDirectory: true,
|
||
|
pathSegments: BuiltList(),
|
||
|
);
|
||
|
}
|
||
|
return PathUri(
|
||
|
isAbsolute: parts.first.isEmpty,
|
||
|
isDirectory: parts.last.isEmpty,
|
||
|
pathSegments: BuiltList(parts.where((final element) => element.isNotEmpty)),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/// Creates a new empty path URI representing the current working directory.
|
||
|
factory PathUri.cwd() => PathUri(
|
||
|
isAbsolute: false,
|
||
|
isDirectory: true,
|
||
|
pathSegments: BuiltList(),
|
||
|
);
|
||
|
|
||
|
/// Whether the path is an absolute path.
|
||
|
///
|
||
|
/// If `true` [path] will start with a slash.
|
||
|
final bool isAbsolute;
|
||
|
|
||
|
/// Whether the path is a directory.
|
||
|
///
|
||
|
/// If `true` [path] will end with a slash.
|
||
|
final bool isDirectory;
|
||
|
|
||
|
/// Returns the path as a list of its segments.
|
||
|
///
|
||
|
/// See [path] for getting the path as a string.
|
||
|
final BuiltList<String> pathSegments;
|
||
|
|
||
|
/// Returns the path as a string.
|
||
|
///
|
||
|
/// See [pathSegments] for getting the path as a list of its segments.
|
||
|
String get path {
|
||
|
final buffer = StringBuffer();
|
||
|
if (isAbsolute) {
|
||
|
buffer.write('/');
|
||
|
}
|
||
|
buffer.writeAll(pathSegments, '/');
|
||
|
if (isDirectory && pathSegments.isNotEmpty) {
|
||
|
buffer.write('/');
|
||
|
}
|
||
|
return buffer.toString();
|
||
|
}
|
||
|
|
||
|
/// Returns the name of the last element in path.
|
||
|
String get name => pathSegments.lastOrNull ?? '';
|
||
|
|
||
|
/// Returns the parent of the path.
|
||
|
PathUri? get parent {
|
||
|
if (pathSegments.isNotEmpty) {
|
||
|
return PathUri(
|
||
|
isAbsolute: isAbsolute,
|
||
|
isDirectory: true,
|
||
|
pathSegments: pathSegments.rebuild((final b) => b.removeLast()),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/// Joins the current path with another [path].
|
||
|
///
|
||
|
/// If the current path is not a directory a [StateError] will be thrown.
|
||
|
/// See [isDirectory] for checking if the current path is a directory.
|
||
|
PathUri join(final PathUri other) {
|
||
|
if (!isDirectory) {
|
||
|
throw StateError('$this is not a directory.');
|
||
|
}
|
||
|
|
||
|
return PathUri(
|
||
|
isAbsolute: isAbsolute,
|
||
|
isDirectory: other.isDirectory,
|
||
|
pathSegments: pathSegments.rebuild((final b) => b.addAll(other.pathSegments)),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/// Renames the last path segment and returns a new path URI.
|
||
|
PathUri rename(final String name) {
|
||
|
if (name.contains('/')) {
|
||
|
throw Exception('Path names must not contain /');
|
||
|
}
|
||
|
|
||
|
return PathUri(
|
||
|
isAbsolute: isAbsolute,
|
||
|
isDirectory: isDirectory,
|
||
|
pathSegments: pathSegments.isNotEmpty
|
||
|
? pathSegments.rebuild(
|
||
|
(final b) => b
|
||
|
..removeLast()
|
||
|
..add(name),
|
||
|
)
|
||
|
: BuiltList(),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
bool operator ==(final Object other) =>
|
||
|
other is PathUri &&
|
||
|
isAbsolute == other.isAbsolute &&
|
||
|
isDirectory == other.isDirectory &&
|
||
|
pathSegments == other.pathSegments;
|
||
|
|
||
|
@override
|
||
|
int get hashCode => Object.hashAll([
|
||
|
isAbsolute,
|
||
|
isDirectory,
|
||
|
pathSegments,
|
||
|
]);
|
||
|
|
||
|
@override
|
||
|
String toString() => path;
|
||
|
}
|