333 lines
9.3 KiB
Dart
333 lines
9.3 KiB
Dart
import 'package:platform_macroable/platform_macroable.dart';
|
|
import 'package:platform_conditionable/platform_conditionable.dart';
|
|
import 'traits/dumpable.dart';
|
|
import 'traits/tappable.dart';
|
|
import 'facades/date.dart';
|
|
import 'carbon.dart';
|
|
import 'str.dart';
|
|
|
|
/// A class that provides string manipulation capabilities.
|
|
class Stringable with Macroable, Conditionable, Dumpable, Tappable {
|
|
/// The underlying string value.
|
|
String _value;
|
|
|
|
/// Create a new stringable instance.
|
|
Stringable(this._value);
|
|
|
|
/// Get the string length.
|
|
int getLength() => Str.length(_value);
|
|
|
|
/// Convert the given string to camel case.
|
|
Stringable camel() {
|
|
_value = Str.camel(_value);
|
|
return this;
|
|
}
|
|
|
|
/// Convert the given string to studly caps case.
|
|
Stringable studly() {
|
|
_value = Str.studly(_value);
|
|
return this;
|
|
}
|
|
|
|
/// Convert a string to snake case.
|
|
Stringable snake([String separator = '_']) {
|
|
if (_value.isEmpty) return this;
|
|
|
|
final result = StringBuffer();
|
|
result.write(_value[0].toLowerCase());
|
|
|
|
for (var i = 1; i < _value.length; i++) {
|
|
if (_value[i].toUpperCase() == _value[i] &&
|
|
_value[i].toLowerCase() != _value[i]) {
|
|
result.write(separator);
|
|
result.write(_value[i].toLowerCase());
|
|
} else {
|
|
result.write(_value[i]);
|
|
}
|
|
}
|
|
|
|
_value = result.toString().replaceAll('_', separator);
|
|
return this;
|
|
}
|
|
|
|
/// Convert a string to kebab case.
|
|
Stringable kebab() {
|
|
_value = snake('-').toString();
|
|
return this;
|
|
}
|
|
|
|
/// Convert the given string to title case.
|
|
Stringable title() {
|
|
_value = Str.title(_value);
|
|
return this;
|
|
}
|
|
|
|
/// Convert the given string to lower case.
|
|
Stringable lower() {
|
|
_value = Str.lower(_value);
|
|
return this;
|
|
}
|
|
|
|
/// Convert the given string to upper case.
|
|
Stringable upper() {
|
|
_value = Str.upper(_value);
|
|
return this;
|
|
}
|
|
|
|
/// Generate a URL friendly "slug" from a given string.
|
|
Stringable slug([String separator = '-']) {
|
|
_value = Str.slug(_value, separator: separator);
|
|
return this;
|
|
}
|
|
|
|
/// Convert a string to its ASCII representation.
|
|
Stringable ascii() {
|
|
_value = Str.ascii(_value);
|
|
return this;
|
|
}
|
|
|
|
/// Determine if a given string starts with a given substring.
|
|
bool startsWith(dynamic needles) => Str.startsWith(_value, needles);
|
|
|
|
/// Determine if a given string ends with a given substring.
|
|
bool endsWith(dynamic needles) => Str.endsWith(_value, needles);
|
|
|
|
/// Cap a string with a single instance of a given value.
|
|
Stringable finish(String cap) {
|
|
_value = Str.finish(_value, cap);
|
|
return this;
|
|
}
|
|
|
|
/// Begin a string with a single instance of a given value.
|
|
Stringable start(String prefix) {
|
|
_value = Str.start(_value, prefix);
|
|
return this;
|
|
}
|
|
|
|
/// Determine if a given string contains a given substring.
|
|
bool contains(dynamic needles) => Str.contains(_value, needles);
|
|
|
|
/// Limit the number of characters in a string.
|
|
Stringable limit(int limit, [String end = '...']) {
|
|
_value = Str.limit(_value, limit, end);
|
|
return this;
|
|
}
|
|
|
|
/// Convert the given string to base64.
|
|
Stringable toBase64() {
|
|
_value = Str.toBase64(_value);
|
|
return this;
|
|
}
|
|
|
|
/// Convert the given base64 string back to a normal string.
|
|
Stringable fromBase64() {
|
|
_value = Str.fromBase64(_value);
|
|
return this;
|
|
}
|
|
|
|
/// Parse a Class[@]method style callback string.
|
|
List<String>? parseCallback([String separator = '@']) =>
|
|
Str.parseCallback(_value, separator);
|
|
|
|
/// Mask a portion of a string with a repeated character.
|
|
Stringable mask(int start, [int? length, String mask = '*']) {
|
|
if (start < 0 || start >= _value.length) return this;
|
|
|
|
final maskLength = length ?? (_value.length - start);
|
|
final end = start + maskLength;
|
|
if (end > _value.length) return this;
|
|
|
|
final original = _value;
|
|
_value = original.substring(0, start) +
|
|
(length != null ? mask * length : mask * (original.length - start)) +
|
|
(length != null ? original.substring(end) : '');
|
|
return this;
|
|
}
|
|
|
|
/// Pad both sides of a string with another.
|
|
Stringable padBoth(int length, [String pad = ' ']) {
|
|
final remaining = length - _value.length;
|
|
if (remaining <= 0) return this;
|
|
|
|
final leftPad = pad * (remaining ~/ 2);
|
|
final rightPad = remaining % 2 == 0
|
|
? pad * (remaining ~/ 2)
|
|
: pad * ((remaining - leftPad.length));
|
|
_value = leftPad + _value + rightPad;
|
|
return this;
|
|
}
|
|
|
|
/// Pad the left side of a string with another.
|
|
Stringable padLeft(int length, [String pad = ' ']) {
|
|
final remaining = length - _value.length;
|
|
if (remaining <= 0) return this;
|
|
_value = pad * remaining + _value;
|
|
return this;
|
|
}
|
|
|
|
/// Pad the right side of a string with another.
|
|
Stringable padRight(int length, [String pad = ' ']) {
|
|
final remaining = length - _value.length;
|
|
if (remaining <= 0) return this;
|
|
_value = _value + pad * remaining;
|
|
return this;
|
|
}
|
|
|
|
/// Split a string by a regular expression.
|
|
List<String> split(Pattern pattern) => _value.split(pattern);
|
|
|
|
/// Get a substring of the given string.
|
|
Stringable substr(int start, [int? length]) {
|
|
if (start < 0) start = _value.length + start;
|
|
if (start < 0) start = 0;
|
|
if (start >= _value.length) return this;
|
|
|
|
final end = length != null ? start + length : _value.length;
|
|
_value = _value.substring(start, end > _value.length ? _value.length : end);
|
|
return this;
|
|
}
|
|
|
|
/// Replace all occurrences of the search string with the replacement string.
|
|
Stringable replace(Pattern from, String replace) {
|
|
_value = _value.replaceAll(from, replace);
|
|
return this;
|
|
}
|
|
|
|
/// Replace the first occurrence of the search string with the replacement string.
|
|
Stringable replaceFirst(Pattern from, String replace) {
|
|
_value = _value.replaceFirst(from, replace);
|
|
return this;
|
|
}
|
|
|
|
/// Replace the last occurrence of the search string with the replacement string.
|
|
Stringable replaceLast(Pattern from, String replace) {
|
|
final matches = from.allMatches(_value).toList();
|
|
if (matches.isNotEmpty) {
|
|
final lastMatch = matches.last;
|
|
_value = _value.substring(0, lastMatch.start) +
|
|
replace +
|
|
_value.substring(lastMatch.end);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/// Convert the string to a boolean value.
|
|
bool toBoolean() {
|
|
final lower = _value.toLowerCase();
|
|
return lower == 'true' || lower == '1' || lower == 'yes' || lower == 'on';
|
|
}
|
|
|
|
/// Trim the string of whitespace.
|
|
Stringable trim() {
|
|
_value = _value.trim();
|
|
return this;
|
|
}
|
|
|
|
/// Trim the string of the given characters.
|
|
Stringable trimChars(String chars) {
|
|
for (var i = 0; i < chars.length; i++) {
|
|
final char = chars[i];
|
|
while (_value.startsWith(char)) {
|
|
_value = _value.substring(1);
|
|
}
|
|
while (_value.endsWith(char)) {
|
|
_value = _value.substring(0, _value.length - 1);
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/// Get the string between the given start and end delimiters.
|
|
Stringable between(String start, String end) {
|
|
final startPos = _value.indexOf(start);
|
|
if (startPos != -1) {
|
|
final endPos = _value.indexOf(end, startPos + start.length);
|
|
if (endPos != -1) {
|
|
_value = _value.substring(startPos + start.length, endPos);
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/// Get the portion of a string before a given value.
|
|
Stringable before(String search) {
|
|
final pos = _value.indexOf(search);
|
|
if (pos != -1) {
|
|
_value = _value.substring(0, pos);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/// Get the portion of a string after a given value.
|
|
Stringable after(String search) {
|
|
final pos = _value.indexOf(search);
|
|
if (pos != -1) {
|
|
_value = _value.substring(pos + search.length);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/// Get the portion of a string before the last occurrence of a given value.
|
|
Stringable beforeLast(String search) {
|
|
final pos = _value.lastIndexOf(search);
|
|
if (pos != -1) {
|
|
_value = _value.substring(0, pos);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/// Get the portion of a string after the last occurrence of a given value.
|
|
Stringable afterLast(String search) {
|
|
final pos = _value.lastIndexOf(search);
|
|
if (pos != -1) {
|
|
_value = _value.substring(pos + search.length);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/// Determine if a given string matches a given pattern.
|
|
bool matches(Pattern pattern) => pattern.allMatches(_value).isNotEmpty;
|
|
|
|
/// Parse the string into a Carbon instance.
|
|
Carbon toDate() => Date.parse(_value);
|
|
|
|
/// Get the string value.
|
|
@override
|
|
String toString() => _value;
|
|
|
|
/// Compare this string with another string.
|
|
bool equals(String other) => _value == other;
|
|
|
|
/// Get the hash code for this string.
|
|
@override
|
|
int get hashCode => _value.hashCode;
|
|
|
|
/// Compare this string with another object.
|
|
@override
|
|
bool operator ==(Object other) {
|
|
if (identical(this, other)) return true;
|
|
return other is Stringable && other._value == _value;
|
|
}
|
|
|
|
/// Create a new stringable instance from a string.
|
|
static Stringable from(String value) => Stringable(value);
|
|
|
|
/// Dump the string value.
|
|
@override
|
|
T dump<T extends Object>([List<Object?>? args]) {
|
|
print(_value);
|
|
if (args != null) {
|
|
for (final arg in args) {
|
|
print(arg);
|
|
}
|
|
}
|
|
return this as T;
|
|
}
|
|
|
|
/// Dump the string value and die.
|
|
@override
|
|
Never dd([List<Object?>? args]) {
|
|
dump(args);
|
|
throw Exception('Dump and die');
|
|
}
|
|
}
|