1/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import {assertTrue} from './assert_utils';
17
18class StringUtils {
19  static parseBigIntStrippingUnit(s: string): bigint {
20    const match = s.match(/^\s*(-?\d+)\D*.*$/);
21    if (!match) {
22      throw new Error(`Cannot parse '${s}' as bigint`);
23    }
24    return BigInt(match[1]);
25  }
26
27  static convertCamelToSnakeCase(s: string): string {
28    const result: string[] = [];
29
30    let prevChar: string | undefined;
31    for (const currChar of s) {
32      const prevCharCouldBeWordEnd =
33        prevChar &&
34        (StringUtils.isDigit(prevChar) || StringUtils.isLowerCase(prevChar));
35      const currCharCouldBeWordStart = StringUtils.isUpperCase(currChar);
36      if (prevCharCouldBeWordEnd && currCharCouldBeWordStart) {
37        result.push('_');
38        result.push(currChar.toLowerCase());
39      } else {
40        result.push(currChar);
41      }
42      prevChar = currChar;
43    }
44
45    return result.join('');
46  }
47
48  static convertSnakeToCamelCase(s: string): string {
49    const tokens = s.split('_').filter((token) => token.length > 0);
50    const tokensCapitalized = tokens.map((token) => {
51      return StringUtils.capitalizeFirstCharIfAlpha(token);
52    });
53
54    const inputStartsWithUnderscore = s[0] === '_';
55    let result = inputStartsWithUnderscore ? '_' : '';
56    result += tokens[0];
57    for (const token of tokensCapitalized.slice(1)) {
58      if (!StringUtils.isAlpha(token[0])) {
59        result += '_';
60      }
61      result += token;
62    }
63
64    return result;
65  }
66
67  static isAlpha(char: string): boolean {
68    assertTrue(char.length === 1, () => 'Input must be a single character');
69    return char[0].toLowerCase() !== char[0].toUpperCase();
70  }
71
72  static isDigit(char: string): boolean {
73    assertTrue(char.length === 1, () => 'Input must be a single character');
74    return char >= '0' && char <= '9';
75  }
76
77  static isLowerCase(char: string): boolean {
78    assertTrue(char.length === 1, () => 'Input must be a single character');
79    return StringUtils.isAlpha(char) && char === char.toLowerCase();
80  }
81
82  static isUpperCase(char: string): boolean {
83    assertTrue(char.length === 1, () => 'Input must be a single character');
84    return StringUtils.isAlpha(char) && char === char.toUpperCase();
85  }
86
87  static isBlank(str: string): boolean {
88    return str.replace(/\s/g, '').length === 0;
89  }
90
91  static isNumeric(str: string): boolean {
92    return Number(str).toString() === str;
93  }
94
95  private static capitalizeFirstCharIfAlpha(word: string): string {
96    if (word.length === 0) {
97      return word;
98    }
99
100    if (!StringUtils.isAlpha(word[0])) {
101      return word;
102    }
103    return word[0].toUpperCase() + word.slice(1);
104  }
105}
106
107export {StringUtils};
108