@controlium/utils 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,290 @@
1
+ import { JsonUtils, Log, LogLevels } from "../index";
2
+ import { Utils } from "../utils/utils";
3
+ /**
4
+ * General String related test-related utilities.
5
+ * @note
6
+ * Originally written as String extensions, re-written as static functions for broader compatibility.
7
+ */
8
+ export class StringUtils {
9
+ /**
10
+ * Removes leading and trailing instances of given character from a string
11
+ * @param originalString
12
+ * String to be trimmed
13
+ * @param characterToTrim
14
+ * Character to be removed from start and end of string, if present
15
+ */
16
+ static trimChar(originalString, characterToTrim) {
17
+ Utils.assertType(originalString, "string", "trimChar", "originalString");
18
+ Utils.assertType(characterToTrim, "string", "trimChar", "characterToTrim");
19
+ // Check we have only been given a single char to trim. Bomb if not.
20
+ if (characterToTrim.length !== 1) {
21
+ const error = `characterToTrim (${characterToTrim}) must be a single character!`;
22
+ Log.writeLine(LogLevels.Error, ` ${error}`);
23
+ throw new Error(error);
24
+ }
25
+ let normalizedCharToTrim = characterToTrim === "]" ? "\\]" : characterToTrim;
26
+ normalizedCharToTrim = normalizedCharToTrim === "^" ? "\\^" : normalizedCharToTrim;
27
+ normalizedCharToTrim = normalizedCharToTrim === "\\" ? "\\\\" : normalizedCharToTrim;
28
+ return originalString.replace(new RegExp("^[" + normalizedCharToTrim + "]+|[" + normalizedCharToTrim + "]+$", "g"), "");
29
+ }
30
+ /**
31
+ * Trims single or double quotes from string if string starts AND ends in same quote character
32
+ * @param originalString
33
+ * String to be trimmed
34
+ */
35
+ static trimQuotes(originalString) {
36
+ Utils.assertType(originalString, "string", "trimQuotes", "originalString");
37
+ let trimmedString = originalString;
38
+ if ((trimmedString.startsWith("'") && trimmedString.endsWith("'")) || (trimmedString.startsWith('"') && trimmedString.endsWith('"'))) {
39
+ trimmedString = trimmedString.substring(1, trimmedString.length - 1);
40
+ }
41
+ return trimmedString;
42
+ }
43
+ /**
44
+ * Checks if character at index is an Alpha character
45
+ * @param stringToCheck
46
+ * String containing character to check
47
+ * @param indexZeroBased - default 0
48
+ * Index of character to check
49
+ * @returns
50
+ * Boolean true is alpha, otherwise false
51
+ */
52
+ static isAlpha(stringToCheck, indexZeroBased = 0) {
53
+ Utils.assertType(stringToCheck, "string", "isAlpha", "stringToCheck");
54
+ Utils.assertType(indexZeroBased, "number", "isAlpha", "indexZeroBased");
55
+ if (stringToCheck.length - 1 < indexZeroBased) {
56
+ const errorText = `Cannot check if char [${indexZeroBased} (Zero based)] isAlpha as length of stringToCheck is only ${stringToCheck.length} characters long!`;
57
+ Log.writeLine(LogLevels.Error, errorText);
58
+ throw new Error(errorText);
59
+ }
60
+ return stringToCheck.charAt(indexZeroBased).toLowerCase() !== stringToCheck.charAt(indexZeroBased).toUpperCase();
61
+ }
62
+ /**
63
+ * Set first character of string to Capital (if Alpha)
64
+ * @param originalString
65
+ * String to set first character
66
+ * @returns
67
+ * originalString with first character capitalised
68
+ */
69
+ static capitaliseFirstCharacter(originalString, searchFirstAlpha = false) {
70
+ Utils.assertType(originalString, "string", "capitaliseFirstCharacter", "originalString");
71
+ if (searchFirstAlpha) {
72
+ const asArray = originalString.split("");
73
+ asArray.find((item, index) => {
74
+ if (this.isAlpha(item)) {
75
+ asArray[index] = item.toUpperCase();
76
+ return true;
77
+ }
78
+ else {
79
+ return false;
80
+ }
81
+ });
82
+ return asArray.join("");
83
+ }
84
+ else {
85
+ return originalString.charAt(0).toUpperCase() + originalString.slice(1);
86
+ }
87
+ }
88
+ /**
89
+ * Splits a string upto substrings a maximum number of times using the specified separator and return then as an array
90
+ * @param originalString
91
+ * String to be split
92
+ * @param separator
93
+ * Character to use as seperator. If more than one character, function will error.
94
+ * @param limit
95
+ * A value used to limit the number of elements returned in the array. Last element contains rest of string.
96
+ */
97
+ static splitRemaining(originalString, separator, limit, doNotSeparateInQuotes = false) {
98
+ Utils.assertType(originalString, "string", "splitRemaining", "originalString");
99
+ Utils.assertType(separator, "string", "splitRemaining", "separator");
100
+ Utils.assertType(limit, "number", "splitRemaining", "limit");
101
+ if (separator.length === 1 && limit > 0) {
102
+ const allParts = StringUtils.split(originalString, separator, doNotSeparateInQuotes);
103
+ const partsToMax = allParts.slice(0, limit - 1);
104
+ const partsAfterMax = allParts.slice(limit - 1);
105
+ return partsAfterMax.length > 0 ? partsToMax.concat([partsAfterMax.join(separator)]) : partsToMax;
106
+ }
107
+ else {
108
+ const error = `Seperator [Length was ${separator.length}] must be single character and limit [Limit was ${limit}] greater than 0.`;
109
+ Log.writeLine(LogLevels.Error, error);
110
+ throw new Error(error);
111
+ }
112
+ }
113
+ /**
114
+ * Splits a string upto substrings a maximum number of times using the specified separator and return then as an array
115
+ * @param originalString
116
+ * String to be split
117
+ * @param separator
118
+ * A string that identifies character or characters to use in separating the string.
119
+ * @param limit
120
+ * A value used to limit the number of elements returned in the array. First element contains start of string.
121
+ */
122
+ static splitLeading(originalString, separator, limit, doNotSeparateInQuotes = false) {
123
+ Utils.assertType(originalString, "string", "splitLeading", "originalString");
124
+ Utils.assertType(separator, "string", "splitLeading", "separator");
125
+ Utils.assertType(limit, "number", "splitLeading", "limit");
126
+ const realLimit = limit > originalString.length ? originalString.length : limit;
127
+ if (separator.length === 1 && limit > 0) {
128
+ const allParts = StringUtils.split(originalString, separator, doNotSeparateInQuotes);
129
+ const partsToMax = allParts.slice(0, allParts.length - realLimit + 1);
130
+ const partsAfterMax = allParts.slice(allParts.length - realLimit + 1, allParts.length);
131
+ return partsToMax.length > 0 ? [partsToMax.join(separator)].concat(partsAfterMax) : partsAfterMax;
132
+ }
133
+ else {
134
+ const error = `Seperator [Length was ${separator.length}] must be single character and limit [Limit was ${limit}] greater than 0.`;
135
+ Log.writeLine(LogLevels.Error, error);
136
+ throw new Error(error);
137
+ }
138
+ }
139
+ /**
140
+ * Splits a string into parts, optionally ignoring slips with quotes
141
+ * @param originalString
142
+ * String to be split
143
+ * @param separator
144
+ * Character to use as seperator. If more than one character, function will error.
145
+ * @param doNotSeparateInQuotes (default true)
146
+ * If true, separator char is ignored within single or double quotes (matching)
147
+ * @returns
148
+ * Array of original string
149
+ */
150
+ static split(originalString, separator, doNotSeparateInQuotes = true) {
151
+ Utils.assertType(originalString, "string", "split", "originalString");
152
+ Utils.assertType(separator, "string", "split", "separator");
153
+ if (separator.length === 1) {
154
+ if (doNotSeparateInQuotes) {
155
+ const result = originalString.match(/\\?.|^$/g)?.reduce((workingObject, currentChar) => {
156
+ if (['"', "'"].includes(currentChar)) {
157
+ if (workingObject.inQuote === "") {
158
+ workingObject.inQuote = currentChar;
159
+ }
160
+ else if (workingObject.inQuote === currentChar) {
161
+ workingObject.inQuote = "";
162
+ }
163
+ }
164
+ if (workingObject.inQuote === "" && currentChar === separator) {
165
+ workingObject.array[workingObject.array.length - 1] = StringUtils.trimQuotes(workingObject.array[workingObject.array.length - 1]);
166
+ workingObject.array.push("");
167
+ }
168
+ else {
169
+ workingObject.array[workingObject.array.length - 1] += currentChar.replace(/\\(.)/, "$1");
170
+ }
171
+ return workingObject;
172
+ }, { array: [""], inQuote: "" }).array ?? [originalString];
173
+ result[result.length - 1] = StringUtils.trimQuotes(result[result.length - 1]);
174
+ return result;
175
+ }
176
+ else {
177
+ return originalString.split(separator);
178
+ }
179
+ }
180
+ else {
181
+ const error = `Seperator [Length was ${separator.length}] must be single character.`;
182
+ Log.writeLine(LogLevels.Error, error);
183
+ throw new Error(error);
184
+ }
185
+ }
186
+ /**
187
+ * Splits a string into verb and paremeters. Parameters are part enclosed in trailing brackets.
188
+ * @param rawCommand
189
+ * String containing command verb and, optionally, braces enclosing parameters
190
+ * @returns
191
+ * Object with verb and parameters properties
192
+ * @example
193
+ * "hello"
194
+ * results in verb: "hello", parameters: ''
195
+ * "hello(this is, good)"
196
+ * results in verb: "hello", parameters: 'this is, good'
197
+ * @throws
198
+ * Error if badly formed (no trailing close braces etc....)
199
+ */
200
+ static splitVerbAndParameters(rawCommand) {
201
+ Log.writeLine(LogLevels.FrameworkDebug, `Got string [${rawCommand}]`);
202
+ if (rawCommand.includes("(")) {
203
+ if (rawCommand.endsWith(")")) {
204
+ let paramsPart = StringUtils.splitRemaining(rawCommand, '(', 2)[1];
205
+ paramsPart = paramsPart.substring(0, paramsPart.length - 1);
206
+ Log.writeLine(LogLevels.FrameworkDebug, `Parameters are: [${paramsPart}]`);
207
+ return {
208
+ verb: rawCommand.split("(")[0],
209
+ parameters: paramsPart,
210
+ };
211
+ }
212
+ else {
213
+ const errText = `Object <${rawCommand}> has no closing brackets! If has opening brackets then must have closing brackets`;
214
+ Log.writeLine(LogLevels.Error, errText);
215
+ throw new Error(errText);
216
+ }
217
+ }
218
+ else {
219
+ return {
220
+ verb: rawCommand,
221
+ parameters: "",
222
+ };
223
+ }
224
+ }
225
+ /**
226
+ * Removes all non-alphanumerics from string
227
+ * @param originalString
228
+ * String to remove non-alphanumerics from
229
+ */
230
+ static removeNonAlphaNumeric(originalString) {
231
+ Utils.assertType(originalString, "string", "removeNonAlphaNumeric", "originalString");
232
+ return originalString.replace(/[^a-zA-Z0-9]+/g, "");
233
+ }
234
+ /**
235
+ * Removes all whitespace from string
236
+ * @param originalString
237
+ * String to remove whitespace from
238
+ */
239
+ static removeWhitespace(originalString) {
240
+ Utils.assertType(originalString, "string", "removeWhitespace", "originalString");
241
+ return originalString.replace(/\s+/g, "");
242
+ }
243
+ /**
244
+ * Encode given string to enable use within HTML
245
+ * @param originalString
246
+ * Non-encoded string to be HTML encoded
247
+ * @returns
248
+ * Original string HTML encoded.
249
+ */
250
+ static encodeHTML(originalString) {
251
+ Utils.assertType(originalString, "string", "encodeHTML", "originalString");
252
+ return originalString.replace(/[&<>'"]/g, (tag) => ({
253
+ "&": "&amp;",
254
+ "<": "&lt;",
255
+ ">": "&gt;",
256
+ "'": "&#39;",
257
+ '"': "&quot;",
258
+ }[tag] ?? ""));
259
+ }
260
+ /**
261
+ * Replace all matching instances with replacement
262
+ * @param original
263
+ * String to replace values in
264
+ * @param searchValue
265
+ * Value to replace
266
+ * @param replaceValue
267
+ * Value to replace mathes with
268
+ * @returns
269
+ * Original string with all matching occuranced replaced
270
+ */
271
+ static replaceAll(original, searchValue, replaceValue) {
272
+ if (Utils.isNullOrUndefined(original)) {
273
+ const errText = `Cannot replace [${searchValue}] with [${replaceValue}] Original is null or undefined!`;
274
+ Log.writeLine(LogLevels.Error, errText);
275
+ throw new Error(errText);
276
+ }
277
+ const escapedRegExp = new RegExp(JsonUtils.escapeRegExp(searchValue), 'g');
278
+ return original.replace(escapedRegExp, replaceValue);
279
+ }
280
+ /**
281
+ * Checks if a string is blank
282
+ * @param text
283
+ * String to be verified for blank
284
+ * @returns
285
+ * Boolean true is empty or with blankspaces, otherwise false
286
+ */
287
+ static isBlank(text) {
288
+ return Utils.isNullOrUndefined(text) || text.trim().length === 0;
289
+ }
290
+ }