LCOV - code coverage report
Current view: top level - string - stringext.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 61 61
Test Date: 2026-08-24 04:50:03 Functions: - 0 0
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright 2026 The Authors. See the AUTHORS file for details.
       2              : //
       3              : // Licensed under the Apache License, Version 2.0 (the "License");
       4              : // you may not use this file except in compliance with the License.
       5              : // You may obtain a copy of the License at
       6              : //
       7              : //      https://www.apache.org/licenses/LICENSE-2.0
       8              : //
       9              : // Unless required by applicable law or agreed to in writing, software
      10              : // distributed under the License is distributed on an "AS IS" BASIS,
      11              : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12              : // See the License for the specific language governing permissions and
      13              : // limitations under the License.
      14              : 
      15              : import 'package:characters/characters.dart';
      16              : 
      17              : extension StringExtension on String {
      18              :   // Matches a single Unicode whitespace character: tab/LF/FF/CR plus Zs category.
      19            3 :   static final _whitespaceChar = RegExp(r'^[\t\n\f\r\p{Zs}]$', unicode: true);
      20              : 
      21              :   // Matches a single Unicode punctuation or symbol character (CommonMark definition).
      22            3 :   static final _punctuationChar = RegExp(r'^[\p{P}\p{S}]$', unicode: true);
      23              : 
      24              :   /// True if all characters match the given [test].
      25            1 :   bool all(bool Function(String element) test) {
      26            2 :     for (final c in characters) {
      27            1 :       if (!test(c)) {
      28              :         return false;
      29              :       }
      30              :     }
      31              :     return true;
      32              :   }
      33              : 
      34              :   /// True if the string is entirely made up of whitespace characters, False otherwise.
      35            1 :   bool get isWhitespace =>
      36            5 :       isNotEmpty && all((s) => _whitespaceChar.hasMatch(s));
      37              : 
      38              :   /// True if the string is not entirely made up of whitespace characters, False otherwise.
      39            2 :   bool get isNotWhitespace => !isWhitespace;
      40              : 
      41              :   /// True if there is whitespace in the string, False otherwise.
      42            1 :   bool get hasWhitespace =>
      43            6 :       isNotEmpty && characters.any((s) => _whitespaceChar.hasMatch(s));
      44              : 
      45              :   /// True if there is no whitespace in the string, False otherwise.
      46            2 :   bool get hasNoWhitespace => !hasWhitespace;
      47              : 
      48              :   /// True if the string has 1 character and it's a CR or LF.
      49            1 :   bool get isEolChar {
      50            5 :     return codeUnits.length == 1 && lineEnding.contains(codeUnitAt(0));
      51              :   }
      52              : 
      53            3 :   bool get isEol => isLineFeed || isCrLf;
      54              : 
      55              :   /// True if the string has 1 character and it's a CR.
      56            3 :   bool get isCarriageReturn => codeUnitAt(0) == carriageReturn;
      57              : 
      58              :   /// True if the string has 1 character and it's a LF.
      59            3 :   bool get isLineFeed => codeUnitAt(0) == lineFeed;
      60              : 
      61            2 :   bool get isCrLf => this == '\r\n';
      62              : 
      63              :   /// True if the string has 1 character and it's an ASCII control character.
      64            1 :   bool get isAsciiControlCharacter =>
      65            1 :       isNotEmpty &&
      66            3 :       codeUnits.length == 1 &&
      67            4 :       (_between(codeUnitAt(0), 0x0000, 0x001F) || codeUnitAt(0) == 0x007F);
      68              : 
      69            1 :   bool get isAsciiPunctuationCharacter =>
      70            1 :       isNotEmpty &&
      71            3 :       codeUnits.length == 1 &&
      72            2 :       (_between(codeUnitAt(0), 0x21, 0x2F) ||
      73            2 :           _between(codeUnitAt(0), 0x3A, 0x40) ||
      74            2 :           _between(codeUnitAt(0), 0x5B, 0x60) ||
      75            2 :           _between(codeUnitAt(0), 0x7B, 0x7E));
      76              : 
      77            1 :   bool get isAsciiLetter =>
      78            1 :       isNotEmpty &&
      79            3 :       codeUnits.length == 1 &&
      80            2 :       (_between(codeUnitAt(0), 0x41, 0x5A) ||
      81            2 :           _between(codeUnitAt(0), 0x61, 0x7A));
      82              : 
      83            1 :   bool get isAsciiLetterUppercase =>
      84            1 :       isNotEmpty &&
      85            3 :       codeUnits.length == 1 &&
      86            2 :       (_between(codeUnitAt(0), 0x41, 0x5A));
      87              : 
      88            1 :   bool get isAsciiLetterLowercase =>
      89            1 :       isNotEmpty &&
      90            3 :       codeUnits.length == 1 &&
      91            2 :       (_between(codeUnitAt(0), 0x61, 0x7A));
      92              : 
      93            1 :   bool get isAsciiDigit =>
      94            1 :       isNotEmpty &&
      95            3 :       codeUnits.length == 1 &&
      96            2 :       (_between(codeUnitAt(0), 0x30, 0x39));
      97              : 
      98            1 :   bool get isUnicodePunctuationCharacter =>
      99            3 :       isNotEmpty && _punctuationChar.hasMatch(this);
     100              : 
     101            3 :   bool _between(int value, int min, int max) => value >= min && value <= max;
     102              : 
     103              :   /// cut using first instance of [separator],
     104              :   /// returning the `before` and `after` parts
     105              :   ///
     106              :   /// `found` is true if [separator] was found
     107            1 :   (String before, String after, bool found) cutFirst(String separator) {
     108            2 :     if (isEmpty || separator.isEmpty) {
     109              :       return (this, '', false);
     110              :     }
     111              : 
     112            3 :     var rng = characters.findFirst(separator.characters);
     113              : 
     114              :     if (rng == null) {
     115              :       return (this, '', false);
     116              :     }
     117            2 :     var before = rng.charactersBefore.toString();
     118            2 :     var after = rng.charactersAfter.toString();
     119              :     return (before, after, true);
     120              :   }
     121              : 
     122              :   /// Clip the [n] rightmost characters
     123            1 :   String clipRight(int n) {
     124            1 :     if (n <= 0) {
     125              :       return this;
     126              :     }
     127              : 
     128            3 :     var count = characters.length - n;
     129            1 :     if (count <= 0) {
     130              :       return '';
     131              :     }
     132              : 
     133            3 :     return characters.take(count).toString();
     134              :   }
     135              : 
     136            1 :   String toUpperCaseFirstLetter() {
     137            1 :     if (isEmpty) {
     138              :       return '';
     139              :     }
     140            6 :     return '${characters.first.toUpperCase()}${characters.getRange(1)}';
     141              :   }
     142              : }
     143              : 
     144              : /// `<control>` - LINE FEED (LF)
     145              : const lineFeed = 0x000A;
     146              : 
     147              : /// `<control>` - CARRIAGE RETURN (CR)
     148              : const carriageReturn = 0x000D;
     149              : 
     150              : const lineEnding = [lineFeed, carriageReturn];
        

Generated by: LCOV version 2.0-1