@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.
- package/LICENSE +661 -0
- package/README.md +10 -0
- package/dist/cjs/detokeniser/detokeniser.js +1135 -0
- package/dist/cjs/index.js +14 -0
- package/dist/cjs/jsonUtils/jsonUtils.js +460 -0
- package/dist/cjs/logger/logger.js +863 -0
- package/dist/cjs/logger/logger.spec.js +875 -0
- package/dist/cjs/logger/types.js +2 -0
- package/dist/cjs/stringUtils/stringUtils.js +294 -0
- package/dist/cjs/utils/utils.js +1050 -0
- package/dist/esm/detokeniser/detokeniser.js +1131 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/jsonUtils/jsonUtils.js +420 -0
- package/dist/esm/logger/logger.js +859 -0
- package/dist/esm/logger/logger.spec.js +873 -0
- package/dist/esm/logger/types.js +1 -0
- package/dist/esm/stringUtils/stringUtils.js +290 -0
- package/dist/esm/utils/utils.js +1043 -0
- package/dist/types/detokeniser/detokeniser.d.ts +402 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/jsonUtils/jsonUtils.d.ts +196 -0
- package/dist/types/logger/logger.d.ts +388 -0
- package/dist/types/logger/logger.spec.d.ts +1 -0
- package/dist/types/logger/types.d.ts +235 -0
- package/dist/types/stringUtils/stringUtils.d.ts +129 -0
- package/dist/types/utils/utils.d.ts +450 -0
- package/package.json +110 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* General String related test-related utilities.
|
|
3
|
+
* @note
|
|
4
|
+
* Originally written as String extensions, re-written as static functions for broader compatibility.
|
|
5
|
+
*/
|
|
6
|
+
export declare class StringUtils {
|
|
7
|
+
/**
|
|
8
|
+
* Removes leading and trailing instances of given character from a string
|
|
9
|
+
* @param originalString
|
|
10
|
+
* String to be trimmed
|
|
11
|
+
* @param characterToTrim
|
|
12
|
+
* Character to be removed from start and end of string, if present
|
|
13
|
+
*/
|
|
14
|
+
static trimChar(originalString: string, characterToTrim: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Trims single or double quotes from string if string starts AND ends in same quote character
|
|
17
|
+
* @param originalString
|
|
18
|
+
* String to be trimmed
|
|
19
|
+
*/
|
|
20
|
+
static trimQuotes(originalString: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Checks if character at index is an Alpha character
|
|
23
|
+
* @param stringToCheck
|
|
24
|
+
* String containing character to check
|
|
25
|
+
* @param indexZeroBased - default 0
|
|
26
|
+
* Index of character to check
|
|
27
|
+
* @returns
|
|
28
|
+
* Boolean true is alpha, otherwise false
|
|
29
|
+
*/
|
|
30
|
+
static isAlpha(stringToCheck: string, indexZeroBased?: number): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Set first character of string to Capital (if Alpha)
|
|
33
|
+
* @param originalString
|
|
34
|
+
* String to set first character
|
|
35
|
+
* @returns
|
|
36
|
+
* originalString with first character capitalised
|
|
37
|
+
*/
|
|
38
|
+
static capitaliseFirstCharacter(originalString: string, searchFirstAlpha?: boolean): string;
|
|
39
|
+
/**
|
|
40
|
+
* Splits a string upto substrings a maximum number of times using the specified separator and return then as an array
|
|
41
|
+
* @param originalString
|
|
42
|
+
* String to be split
|
|
43
|
+
* @param separator
|
|
44
|
+
* Character to use as seperator. If more than one character, function will error.
|
|
45
|
+
* @param limit
|
|
46
|
+
* A value used to limit the number of elements returned in the array. Last element contains rest of string.
|
|
47
|
+
*/
|
|
48
|
+
static splitRemaining(originalString: string, separator: string, limit: number, doNotSeparateInQuotes?: boolean): string[];
|
|
49
|
+
/**
|
|
50
|
+
* Splits a string upto substrings a maximum number of times using the specified separator and return then as an array
|
|
51
|
+
* @param originalString
|
|
52
|
+
* String to be split
|
|
53
|
+
* @param separator
|
|
54
|
+
* A string that identifies character or characters to use in separating the string.
|
|
55
|
+
* @param limit
|
|
56
|
+
* A value used to limit the number of elements returned in the array. First element contains start of string.
|
|
57
|
+
*/
|
|
58
|
+
static splitLeading(originalString: string, separator: string, limit: number, doNotSeparateInQuotes?: boolean): string[];
|
|
59
|
+
/**
|
|
60
|
+
* Splits a string into parts, optionally ignoring slips with quotes
|
|
61
|
+
* @param originalString
|
|
62
|
+
* String to be split
|
|
63
|
+
* @param separator
|
|
64
|
+
* Character to use as seperator. If more than one character, function will error.
|
|
65
|
+
* @param doNotSeparateInQuotes (default true)
|
|
66
|
+
* If true, separator char is ignored within single or double quotes (matching)
|
|
67
|
+
* @returns
|
|
68
|
+
* Array of original string
|
|
69
|
+
*/
|
|
70
|
+
static split(originalString: string, separator: string, doNotSeparateInQuotes?: boolean): Array<string>;
|
|
71
|
+
/**
|
|
72
|
+
* Splits a string into verb and paremeters. Parameters are part enclosed in trailing brackets.
|
|
73
|
+
* @param rawCommand
|
|
74
|
+
* String containing command verb and, optionally, braces enclosing parameters
|
|
75
|
+
* @returns
|
|
76
|
+
* Object with verb and parameters properties
|
|
77
|
+
* @example
|
|
78
|
+
* "hello"
|
|
79
|
+
* results in verb: "hello", parameters: ''
|
|
80
|
+
* "hello(this is, good)"
|
|
81
|
+
* results in verb: "hello", parameters: 'this is, good'
|
|
82
|
+
* @throws
|
|
83
|
+
* Error if badly formed (no trailing close braces etc....)
|
|
84
|
+
*/
|
|
85
|
+
static splitVerbAndParameters(rawCommand: string): {
|
|
86
|
+
verb: string;
|
|
87
|
+
parameters: string;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Removes all non-alphanumerics from string
|
|
91
|
+
* @param originalString
|
|
92
|
+
* String to remove non-alphanumerics from
|
|
93
|
+
*/
|
|
94
|
+
static removeNonAlphaNumeric(originalString: string): string;
|
|
95
|
+
/**
|
|
96
|
+
* Removes all whitespace from string
|
|
97
|
+
* @param originalString
|
|
98
|
+
* String to remove whitespace from
|
|
99
|
+
*/
|
|
100
|
+
static removeWhitespace(originalString: string): string;
|
|
101
|
+
/**
|
|
102
|
+
* Encode given string to enable use within HTML
|
|
103
|
+
* @param originalString
|
|
104
|
+
* Non-encoded string to be HTML encoded
|
|
105
|
+
* @returns
|
|
106
|
+
* Original string HTML encoded.
|
|
107
|
+
*/
|
|
108
|
+
static encodeHTML(originalString: string): string;
|
|
109
|
+
/**
|
|
110
|
+
* Replace all matching instances with replacement
|
|
111
|
+
* @param original
|
|
112
|
+
* String to replace values in
|
|
113
|
+
* @param searchValue
|
|
114
|
+
* Value to replace
|
|
115
|
+
* @param replaceValue
|
|
116
|
+
* Value to replace mathes with
|
|
117
|
+
* @returns
|
|
118
|
+
* Original string with all matching occuranced replaced
|
|
119
|
+
*/
|
|
120
|
+
static replaceAll(original: string, searchValue: string, replaceValue: string): string;
|
|
121
|
+
/**
|
|
122
|
+
* Checks if a string is blank
|
|
123
|
+
* @param text
|
|
124
|
+
* String to be verified for blank
|
|
125
|
+
* @returns
|
|
126
|
+
* Boolean true is empty or with blankspaces, otherwise false
|
|
127
|
+
*/
|
|
128
|
+
static isBlank(text: string): boolean;
|
|
129
|
+
}
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { ChildProcessWithoutNullStreams, SpawnOptionsWithoutStdio } from 'child_process';
|
|
2
|
+
import { LogLevel } from "../index";
|
|
3
|
+
/**
|
|
4
|
+
* What action to perform if a file already exists when {@link Utils.writeTextToFile} is called.
|
|
5
|
+
*/
|
|
6
|
+
export declare enum ExistingFileWriteActions {
|
|
7
|
+
/** Overwrite existing file */
|
|
8
|
+
Overwrite = 0,
|
|
9
|
+
/** Create a new file using an incrementing index in the file name */
|
|
10
|
+
AddIndex = 1,
|
|
11
|
+
/** Append data to the existing file contents */
|
|
12
|
+
Append = 2,
|
|
13
|
+
/** Throw an error indicating the file already exists */
|
|
14
|
+
ThrowError = 3
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Maps `typeof` string literals to their corresponding TypeScript types.
|
|
18
|
+
* Used by {@link Utils.assertType} to provide type narrowing after assertion.
|
|
19
|
+
*/
|
|
20
|
+
export interface AssertTypeMap {
|
|
21
|
+
string: string;
|
|
22
|
+
number: number;
|
|
23
|
+
boolean: boolean;
|
|
24
|
+
object: object;
|
|
25
|
+
bigint: bigint;
|
|
26
|
+
symbol: symbol;
|
|
27
|
+
function: (...args: unknown[]) => unknown;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* General testing-related utilities. All methods are static — no instantiation required.
|
|
31
|
+
*/
|
|
32
|
+
export declare class Utils {
|
|
33
|
+
private static _promiseCount;
|
|
34
|
+
private static _defaultPromiseTimeout;
|
|
35
|
+
/**
|
|
36
|
+
* Number of currently outstanding promises wrapped by {@link timeoutPromise}.
|
|
37
|
+
* Check this at the end of a test to verify all promises have settled.
|
|
38
|
+
* @see {@link resetPromiseCount}
|
|
39
|
+
*/
|
|
40
|
+
static get promiseCount(): number;
|
|
41
|
+
/**
|
|
42
|
+
* Resets the outstanding promise count to zero.
|
|
43
|
+
* @see {@link promiseCount}
|
|
44
|
+
*/
|
|
45
|
+
static resetPromiseCount(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Sets the default timeout in milliseconds applied by {@link timeoutPromise}
|
|
48
|
+
* when no per-call `timeoutMS` is supplied.
|
|
49
|
+
* @param timeoutMs - Timeout in milliseconds. Must be greater than zero.
|
|
50
|
+
*/
|
|
51
|
+
static set defaultPromiseTimeout(timeoutMs: number);
|
|
52
|
+
/**
|
|
53
|
+
* Asserts that a value is of the expected type, throwing a logged error if not.
|
|
54
|
+
* After a successful call, TypeScript narrows `value` to the corresponding type.
|
|
55
|
+
*
|
|
56
|
+
* @param value - Value to check.
|
|
57
|
+
* @param expectedType - Expected `typeof` string (e.g. `"string"`, `"number"`).
|
|
58
|
+
* @param funcName - Name of the calling function, used in the error message.
|
|
59
|
+
* @param paramName - Name of the parameter being checked, used in the error message.
|
|
60
|
+
* @throws {Error} If `typeof value` does not match `expectedType`.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* Utils.assertType(name, "string", "greet", "name");
|
|
64
|
+
* // name is now narrowed to string
|
|
65
|
+
*/
|
|
66
|
+
static assertType<K extends keyof AssertTypeMap>(value: unknown, expectedType: K, funcName: string, paramName: string): asserts value is AssertTypeMap[K];
|
|
67
|
+
/**
|
|
68
|
+
* Safely checks if a value is `null` or `undefined`.
|
|
69
|
+
*
|
|
70
|
+
* @param obj - Value to check.
|
|
71
|
+
* @returns `true` if `null` or `undefined`, otherwise `false`.
|
|
72
|
+
*/
|
|
73
|
+
static isNullOrUndefined(obj?: unknown): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Safely checks if a value is `null`.
|
|
76
|
+
*
|
|
77
|
+
* @param obj - Value to check.
|
|
78
|
+
* @returns `true` if `null`, otherwise `false`.
|
|
79
|
+
*/
|
|
80
|
+
static isNull(obj?: unknown): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Safely checks if a value is `undefined`.
|
|
83
|
+
*
|
|
84
|
+
* @param obj - Value to check.
|
|
85
|
+
* @returns `true` if `undefined`, otherwise `false`.
|
|
86
|
+
*/
|
|
87
|
+
static isUndefined(obj?: unknown): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Checks whether a value evaluates to `true` according to common conventions.
|
|
90
|
+
*
|
|
91
|
+
* Returns `true` for:
|
|
92
|
+
* - A boolean `true`
|
|
93
|
+
* - The strings `"y"`, `"1"`, `"yes"`, `"positive"`, or `"true"` (case-insensitive, trimmed)
|
|
94
|
+
* - A number greater than zero
|
|
95
|
+
*
|
|
96
|
+
* @param valueToCheck - Value to evaluate.
|
|
97
|
+
* @returns `true` if the value is considered truthy, otherwise `false`.
|
|
98
|
+
*/
|
|
99
|
+
static isTrue(valueToCheck: boolean | string | number | undefined): boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Verifies whether a value is a valid `Date` object.
|
|
102
|
+
*
|
|
103
|
+
* @param dateToCheck - Value to validate.
|
|
104
|
+
* @returns `true` if the value is a `Date` instance with a valid time, otherwise `false`.
|
|
105
|
+
*/
|
|
106
|
+
static isValidDate(dateToCheck: unknown): dateToCheck is Date;
|
|
107
|
+
/**
|
|
108
|
+
* Pads a number or string with leading zeros to reach a required minimum length.
|
|
109
|
+
*
|
|
110
|
+
* @param num - The number or string to pad.
|
|
111
|
+
* @param requiredMinimumLength - The minimum length of the returned string.
|
|
112
|
+
* @returns The value as a string, left-padded with `"0"` to at least `requiredMinimumLength` characters.
|
|
113
|
+
* @note If the value is already longer than `requiredMinimumLength`, no truncation occurs.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* Utils.pad(7, 3); // => "007"
|
|
117
|
+
* Utils.pad("42", 5); // => "00042"
|
|
118
|
+
*/
|
|
119
|
+
static pad(num: number | string, requiredMinimumLength: number): string;
|
|
120
|
+
/**
|
|
121
|
+
* Converts a millisecond duration to a `HH:MM:SS.t` formatted string,
|
|
122
|
+
* where `t` is tenths of a second.
|
|
123
|
+
*
|
|
124
|
+
* @param milliSeconds - Duration in milliseconds.
|
|
125
|
+
* @returns Time string formatted as `HH:MM:SS.t`.
|
|
126
|
+
* @note Durations above 359,999,000 ms (99h 59m 59s) will give unexpected results.
|
|
127
|
+
*/
|
|
128
|
+
static msToHMS(milliSeconds: number): string;
|
|
129
|
+
/**
|
|
130
|
+
* Returns a random integer between `min` and `max` inclusive.
|
|
131
|
+
* If `max` is less than `min`, the values are swapped.
|
|
132
|
+
*
|
|
133
|
+
* @param min - Lower bound.
|
|
134
|
+
* @param max - Upper bound.
|
|
135
|
+
* @returns A random integer inclusively between `min` and `max`.
|
|
136
|
+
*/
|
|
137
|
+
static getRandomInt(min: number, max: number): number;
|
|
138
|
+
/**
|
|
139
|
+
* Returns a random float between `min` and `max`.
|
|
140
|
+
*
|
|
141
|
+
* @param min - Lower bound.
|
|
142
|
+
* @param max - Upper bound.
|
|
143
|
+
* @returns A random float between `min` and `max`.
|
|
144
|
+
*/
|
|
145
|
+
static getRandomFloat(min: number, max: number): number;
|
|
146
|
+
/**
|
|
147
|
+
* Writes data to a file, with configurable behaviour when the file already exists.
|
|
148
|
+
*
|
|
149
|
+
* Data is serialised before writing:
|
|
150
|
+
* - JSON strings are normalised (parsed then re-stringified).
|
|
151
|
+
* - Non-JSON strings are written as-is.
|
|
152
|
+
* - Objects are written as pretty-printed JSON.
|
|
153
|
+
*
|
|
154
|
+
* @param filePath - Directory path where the file should be created.
|
|
155
|
+
* @param fileName - Name of the file to write.
|
|
156
|
+
* @param data - Content to write — a string or an object.
|
|
157
|
+
* @param ifExistsAction - Action to take if the file already exists (default: `AddIndex`).
|
|
158
|
+
* @see {@link ExistingFileWriteActions}
|
|
159
|
+
* @throws {Error} If the write fails, or if `ThrowError` is specified and the file exists.
|
|
160
|
+
*/
|
|
161
|
+
static writeTextToFile(filePath: string, fileName: string, data: string | object, ifExistsAction?: ExistingFileWriteActions): void;
|
|
162
|
+
/**
|
|
163
|
+
* Returns the entire contents of a file as a string.
|
|
164
|
+
*
|
|
165
|
+
* @param path - Path to the file.
|
|
166
|
+
* @param options - Optional settings:
|
|
167
|
+
* - `encoding` — File encoding (default: `"utf-8"`).
|
|
168
|
+
* - `detokeniseFileContents` — When `true`, passes contents through the detokeniser before returning (default: `false`).
|
|
169
|
+
* @returns Contents of the file as a string.
|
|
170
|
+
* @throws {Error} If the file cannot be read.
|
|
171
|
+
*/
|
|
172
|
+
static getFileContents(filePath: string, options?: {
|
|
173
|
+
encoding?: BufferEncoding;
|
|
174
|
+
detokeniseFileContents?: boolean;
|
|
175
|
+
}): string;
|
|
176
|
+
/**
|
|
177
|
+
* Returns the entire contents of a file as a `Buffer`.
|
|
178
|
+
*
|
|
179
|
+
* @param path - Path to the file.
|
|
180
|
+
* @returns Raw file contents as a `Buffer`.
|
|
181
|
+
* @throws {Error} If the file cannot be read.
|
|
182
|
+
*/
|
|
183
|
+
static getFileContentsBuffer(filePath: string): Buffer;
|
|
184
|
+
/**
|
|
185
|
+
* Resolves a setting value from, in priority order:
|
|
186
|
+
* 1. A process environment variable
|
|
187
|
+
* 2. An npm package config variable
|
|
188
|
+
* 3. A named property within `contextParameters`
|
|
189
|
+
* 4. A supplied default value
|
|
190
|
+
*
|
|
191
|
+
* @param logLevel - Log level used when reporting where the setting was found.
|
|
192
|
+
* @param settingName - Human-readable name for the setting, used in log messages.
|
|
193
|
+
* @param sources - Named sources to check:
|
|
194
|
+
* - `processEnvName` — Environment variable name.
|
|
195
|
+
* - `npmPackageConfigName` — npm package config key.
|
|
196
|
+
* - `profileParameterName` — JSONPath into `contextParameters`.
|
|
197
|
+
* - `defaultValue` — Fallback if no other source resolves.
|
|
198
|
+
* @param contextParameters - Optional context parameters used to resolve `profileParameterName`.
|
|
199
|
+
* @returns The resolved setting value, or `undefined` if no source resolved.
|
|
200
|
+
* @throws {Error} If `profileParameterName` is given but `contextParameters` is null.
|
|
201
|
+
*/
|
|
202
|
+
static getSetting<returnType>(logLevel: LogLevel, settingName: string, sources: {
|
|
203
|
+
processEnvName?: string | undefined;
|
|
204
|
+
npmPackageConfigName?: string | undefined;
|
|
205
|
+
profileParameterName?: string | undefined;
|
|
206
|
+
defaultValue?: returnType | undefined;
|
|
207
|
+
}, contextParameters?: Record<string, unknown>): returnType | undefined;
|
|
208
|
+
/**
|
|
209
|
+
* Sets a process environment variable and saves its original value for later restoration.
|
|
210
|
+
*
|
|
211
|
+
* The first time a variable is set, its original value is saved under a prefixed key.
|
|
212
|
+
* Subsequent sets to the same variable do not overwrite the saved original.
|
|
213
|
+
* Call {@link resetProcessEnvs} to restore all modified variables.
|
|
214
|
+
*
|
|
215
|
+
* @param varName - Name of the environment variable to set.
|
|
216
|
+
* @param requiredValue - Value to assign.
|
|
217
|
+
* @note If the variable did not previously exist, it is stored as `"_undefined"` so that
|
|
218
|
+
* {@link resetProcessEnvs} knows to delete it rather than restore a blank value.
|
|
219
|
+
*/
|
|
220
|
+
static setProcessEnv(varName: string, requiredValue: string): void;
|
|
221
|
+
/**
|
|
222
|
+
* Restores all process environment variables that were modified by {@link setProcessEnv}
|
|
223
|
+
* back to their original values. Variables that did not previously exist are deleted.
|
|
224
|
+
*
|
|
225
|
+
* @see {@link setProcessEnv}
|
|
226
|
+
* @throws {Error} If an error occurs while resetting variables.
|
|
227
|
+
*/
|
|
228
|
+
static resetProcessEnvs(): void;
|
|
229
|
+
/**
|
|
230
|
+
* Returns a deep clone of an object or JSON string.
|
|
231
|
+
* Uses JSON parse/stringify — only JSON-serialisable values are supported.
|
|
232
|
+
*
|
|
233
|
+
* @param original - The object or JSON5 string to clone.
|
|
234
|
+
* @returns A deep clone of `original`.
|
|
235
|
+
* @throws {Error} If `original` is not valid JSON (JSON5 allowed).
|
|
236
|
+
*/
|
|
237
|
+
static clone(original: object | string): object;
|
|
238
|
+
/**
|
|
239
|
+
* Converts a URL glob pattern to an equivalent `RegExp`.
|
|
240
|
+
*
|
|
241
|
+
* Supported glob syntax:
|
|
242
|
+
* - `*` — matches any sequence of non-`/` characters
|
|
243
|
+
* - `**` — matches any path segment sequence (including `/`)
|
|
244
|
+
* - `?` — matches any single character
|
|
245
|
+
* - `{a,b}` — matches either `a` or `b`
|
|
246
|
+
* - `[...]` — character class, passed through as-is
|
|
247
|
+
*
|
|
248
|
+
* @param glob - The glob pattern to convert.
|
|
249
|
+
* @param options - Optional anchoring flags:
|
|
250
|
+
* - `startOfLine` — Anchors the pattern to the start of the string (default: `true`).
|
|
251
|
+
* - `endOfLine` — Anchors the pattern to the end of the string (default: `true`).
|
|
252
|
+
* @returns A `RegExp` equivalent to the given glob.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* Utils.globToRegex("src/**\/*.ts").test("src/foo/bar.ts"); // true
|
|
256
|
+
*/
|
|
257
|
+
static globToRegex(glob: string, options?: {
|
|
258
|
+
startOfLine: boolean;
|
|
259
|
+
endOfLine: boolean;
|
|
260
|
+
}): RegExp;
|
|
261
|
+
/**
|
|
262
|
+
* Decodes HTML entities in a string back to their corresponding characters.
|
|
263
|
+
*
|
|
264
|
+
* - Named entities (e.g. `&`, `©`) and numeric entities (`©`, `👍`) are decoded.
|
|
265
|
+
* - Non-breaking space characters (U+00A0) are replaced with regular spaces.
|
|
266
|
+
* - Literal apostrophes (`'`) are replaced with `'` before decoding for consistent handling.
|
|
267
|
+
*
|
|
268
|
+
* @param str - The HTML-encoded string to decode.
|
|
269
|
+
* @returns The decoded string.
|
|
270
|
+
* @throws {Error} If `str` is not a string.
|
|
271
|
+
*/
|
|
272
|
+
static unescapeHTML(str: string): string;
|
|
273
|
+
/**
|
|
274
|
+
* Creates a signed JWT token.
|
|
275
|
+
*
|
|
276
|
+
* @param payloadData - The JWT payload as an object or JSON string.
|
|
277
|
+
* @param signature - The signing secret or private key.
|
|
278
|
+
* @param options - Signing options: either a partial options object with an optional
|
|
279
|
+
* `algorithm` (default `"HS256"`), or a raw JSON string for the JWT header.
|
|
280
|
+
* @returns A signed Base64 JWT token string.
|
|
281
|
+
* @throws {Error} If signing fails.
|
|
282
|
+
*/
|
|
283
|
+
static createJWT(payloadData: string | object, signature: string, options?: Partial<{
|
|
284
|
+
algorithm?: string;
|
|
285
|
+
}> | string): string;
|
|
286
|
+
/**
|
|
287
|
+
* Checks whether a string is a structurally valid JWT token.
|
|
288
|
+
*
|
|
289
|
+
* @param jwtToken - The token string to validate.
|
|
290
|
+
* @returns `true` if the token can be decoded, `false` otherwise.
|
|
291
|
+
*/
|
|
292
|
+
static isValidJWT(jwtToken: string): boolean;
|
|
293
|
+
/**
|
|
294
|
+
* Decodes and returns the payload of a JWT token as an object.
|
|
295
|
+
*
|
|
296
|
+
* @param jwtToken - A valid JWT token string.
|
|
297
|
+
* @returns The decoded payload as an object.
|
|
298
|
+
* @throws {Error} If the token cannot be decoded or the payload is not an object.
|
|
299
|
+
*/
|
|
300
|
+
static getJWTPayload(jwtToken: string): object;
|
|
301
|
+
/**
|
|
302
|
+
* Spawns a command as a background process.
|
|
303
|
+
*
|
|
304
|
+
* @param command - The command to execute.
|
|
305
|
+
* @param args - Arguments to pass to the command.
|
|
306
|
+
* @param options - Optional settings:
|
|
307
|
+
* - `logStdout` — Logs stdout at `TestInformation` level (default: `false`).
|
|
308
|
+
* - `logStderr` — Logs stderr and process errors at `Error` level (default: `false`).
|
|
309
|
+
* - `spawnOptions` — Additional options passed to `child_process.spawn`.
|
|
310
|
+
* @returns The spawned `ChildProcess`.
|
|
311
|
+
* @throws {Error} If the process fails to start (PID is `undefined`).
|
|
312
|
+
*/
|
|
313
|
+
static spawnBackgroundProcess(command: string, args: string[], { logStdout, logStderr, spawnOptions }?: {
|
|
314
|
+
logStdout?: boolean;
|
|
315
|
+
logStderr?: boolean;
|
|
316
|
+
spawnOptions?: SpawnOptionsWithoutStdio;
|
|
317
|
+
}): ChildProcessWithoutNullStreams;
|
|
318
|
+
/**
|
|
319
|
+
* Spawns a command as a background process and waits for it to exit, with a timeout.
|
|
320
|
+
*
|
|
321
|
+
* @param command - The command to execute.
|
|
322
|
+
* @param args - Arguments to pass to the command.
|
|
323
|
+
* @param timeoutSeconds - Maximum time in seconds to wait before forcibly terminating the process.
|
|
324
|
+
* @param options - Optional settings (same as {@link spawnBackgroundProcess}).
|
|
325
|
+
* @returns A promise resolving to the process exit code, or `-1` on timeout or error.
|
|
326
|
+
*/
|
|
327
|
+
static spawnBackgroundProcessWithTimeout(command: string, args: string[], timeoutSeconds: number, { logStdout, logStderr, spawnOptions }?: {
|
|
328
|
+
logStdout?: boolean;
|
|
329
|
+
logStderr?: boolean;
|
|
330
|
+
spawnOptions?: SpawnOptionsWithoutStdio;
|
|
331
|
+
}): Promise<number>;
|
|
332
|
+
/**
|
|
333
|
+
* Executes a shell command and returns its stdout output.
|
|
334
|
+
*
|
|
335
|
+
* @param command - The shell command to run.
|
|
336
|
+
* @returns A promise resolving to the stdout string.
|
|
337
|
+
* @throws The error or stderr string if the command fails.
|
|
338
|
+
*/
|
|
339
|
+
static execCommand(command: string): Promise<string>;
|
|
340
|
+
/**
|
|
341
|
+
* Checks whether a process with the given PID is currently running.
|
|
342
|
+
*
|
|
343
|
+
* @param pid - The process ID to check.
|
|
344
|
+
* @returns `true` if the process is running (or exists but cannot be signalled), `false` if it does not exist.
|
|
345
|
+
* @throws Any unexpected error from `process.kill`.
|
|
346
|
+
*/
|
|
347
|
+
static isProcessRunning(pid: number): boolean;
|
|
348
|
+
/**
|
|
349
|
+
* Sends a signal to a process and all of its descendants, leaf-first (post-order traversal).
|
|
350
|
+
*
|
|
351
|
+
* @param rootPid - PID of the root process to terminate.
|
|
352
|
+
* @param signal - Signal to send (default: `"SIGKILL"`).
|
|
353
|
+
*/
|
|
354
|
+
static killProcessAndDescendants(rootPid: number, signal?: NodeJS.Signals): Promise<void>;
|
|
355
|
+
/**
|
|
356
|
+
* Terminates a background process and all its descendants, waiting for the process to close.
|
|
357
|
+
*
|
|
358
|
+
* @param backgroundProcess - The process to terminate.
|
|
359
|
+
* @param options - Optional settings:
|
|
360
|
+
* - `signal` — Signal to use (default: `"SIGKILL"`).
|
|
361
|
+
* @returns A promise resolving to `true` once the process closes, or `false` if no valid process was provided.
|
|
362
|
+
*/
|
|
363
|
+
static terminateBackgroundProcess(backgroundProcess: ChildProcessWithoutNullStreams, options?: {
|
|
364
|
+
signal?: string | number;
|
|
365
|
+
}): Promise<boolean>;
|
|
366
|
+
/**
|
|
367
|
+
* Pauses execution for the given number of milliseconds.
|
|
368
|
+
*
|
|
369
|
+
* @param periodMS - Duration to wait in milliseconds.
|
|
370
|
+
* @param logIt - When `true`, logs the sleep duration at `FrameworkDebug` level (default: `false`).
|
|
371
|
+
* @returns A promise that resolves after the given duration.
|
|
372
|
+
*/
|
|
373
|
+
static sleep(periodMS: number, logIt?: boolean): Promise<unknown>;
|
|
374
|
+
/**
|
|
375
|
+
* Pauses Node.js execution until a keyboard key is pressed, while keeping the event loop running.
|
|
376
|
+
*
|
|
377
|
+
* @param logOutput - Optional message to write to the log before pausing.
|
|
378
|
+
* @returns A promise that resolves when a key is pressed.
|
|
379
|
+
* @warning This hangs indefinitely in non-TTY environments (e.g. CI pipelines).
|
|
380
|
+
* In such cases the call is logged and returns immediately.
|
|
381
|
+
*/
|
|
382
|
+
static pause(logOutput?: string): Promise<void>;
|
|
383
|
+
/**
|
|
384
|
+
* Wraps a promise with a timeout and tracks it in the outstanding promise count.
|
|
385
|
+
*
|
|
386
|
+
* The count is accessible via {@link promiseCount} and can be checked at the end of a
|
|
387
|
+
* test to verify all promises have settled. Use {@link resetPromiseCount} to clear
|
|
388
|
+
* the count between tests.
|
|
389
|
+
*
|
|
390
|
+
* @param promise - The promise to wrap.
|
|
391
|
+
* @param options - Optional settings:
|
|
392
|
+
* - `timeoutMS` — Timeout in milliseconds. Falls back to {@link defaultPromiseTimeout} if not given.
|
|
393
|
+
* - `friendlyName` — Name shown in the timeout error message (defaults to the caller's function name).
|
|
394
|
+
* @returns A promise that resolves/rejects with the original result, or rejects with a timeout error.
|
|
395
|
+
* @throws {Error} If no timeout is configured (neither `timeoutMS` nor `defaultPromiseTimeout` is set).
|
|
396
|
+
* @throws {Error} If `timeoutMS` is negative.
|
|
397
|
+
*/
|
|
398
|
+
static timeoutPromise<T>(promise: Promise<T>, options?: {
|
|
399
|
+
timeoutMS?: number;
|
|
400
|
+
friendlyName?: string;
|
|
401
|
+
}): Promise<T>;
|
|
402
|
+
/**
|
|
403
|
+
* @deprecated Use {@link timeoutPromise} instead.
|
|
404
|
+
*/
|
|
405
|
+
static withTimeoutTracked<T>(promise: Promise<T>, timeoutMs: number): Promise<T>;
|
|
406
|
+
/**
|
|
407
|
+
* Parses a raw action string into a verb and a parameter map.
|
|
408
|
+
*
|
|
409
|
+
* The expected format is `actionName(param1: value1, param2: value2)` where the
|
|
410
|
+
* parameter block is valid JSON5 without the outer braces. If no parentheses are
|
|
411
|
+
* present, `parameters` will be an empty map.
|
|
412
|
+
*
|
|
413
|
+
* @param rawAction - The raw action string to parse.
|
|
414
|
+
* @returns A {@link Utils.ActionAndParams} object with `action`, `normalizedAction`, and `parameters`.
|
|
415
|
+
* @throws {Error} If the parameter block is not valid JSON5.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* Utils.splitActionAndParameters("click(target: '#btn', force: true)");
|
|
419
|
+
* // => { action: "click", normalizedAction: "click", parameters: Map { "target" => "#btn", "force" => true } }
|
|
420
|
+
*/
|
|
421
|
+
static splitActionAndParameters(rawAction: string): ActionAndParams;
|
|
422
|
+
/**
|
|
423
|
+
* Checks whether a value exists as a member of the given enum.
|
|
424
|
+
*
|
|
425
|
+
* @param enumType - The enum object to check against.
|
|
426
|
+
* @param valueToCheck - The value to look for.
|
|
427
|
+
* @returns `true` if the value is a member of the enum, `false` otherwise.
|
|
428
|
+
*/
|
|
429
|
+
static checkENUMValueExists(enumType: object, valueToCheck: string): boolean;
|
|
430
|
+
/**
|
|
431
|
+
* Converts data to a string suitable for writing to a file:
|
|
432
|
+
* - JSON strings are normalised (parsed then re-stringified)
|
|
433
|
+
* - Non-JSON strings are used as-is
|
|
434
|
+
* - Objects are pretty-printed as JSON
|
|
435
|
+
*/
|
|
436
|
+
private static serialiseFileData;
|
|
437
|
+
private static withTimeout;
|
|
438
|
+
private static inferCallerFunctionName;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* The parsed result of a raw action string, as returned by {@link Utils.splitActionAndParameters}.
|
|
442
|
+
*/
|
|
443
|
+
export interface ActionAndParams {
|
|
444
|
+
/** Original non-normalized action verb */
|
|
445
|
+
action: string;
|
|
446
|
+
/** Lowercase and trimmed action verb */
|
|
447
|
+
normalizedAction: string;
|
|
448
|
+
/** All action parameters passed by the caller */
|
|
449
|
+
parameters: Map<string, unknown>;
|
|
450
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@controlium/utils",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Shared utilities for Controlium-based projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "Team Controllium contributors",
|
|
7
|
+
"contributors": [
|
|
8
|
+
"Mat Walker <v-mwalk@alexview.com>"
|
|
9
|
+
],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"main": "./dist/cjs/index.js",
|
|
12
|
+
"module": "./dist/esm/index.js",
|
|
13
|
+
"types": "./dist/types/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./dist/esm/index.js",
|
|
17
|
+
"require": "./dist/cjs/index.js",
|
|
18
|
+
"types": "./dist/types/index.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"clean": "rm -rf dist coverage",
|
|
26
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
27
|
+
"build:esm": "tsc -p tsconfig.json",
|
|
28
|
+
"build": "npm run clean && npm run build:cjs && npm run build:esm",
|
|
29
|
+
"test": "jest --silent --runInBand",
|
|
30
|
+
"test:debug": "jest --runInBand",
|
|
31
|
+
"test:coverage": "jest --silent --coverage --runInBand",
|
|
32
|
+
"lint": "eslint 'src/**/*.ts' --fix",
|
|
33
|
+
"release": "semantic-release"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"typescript",
|
|
37
|
+
"controlium",
|
|
38
|
+
"node",
|
|
39
|
+
"esm",
|
|
40
|
+
"cjs",
|
|
41
|
+
"logger",
|
|
42
|
+
"utilities"
|
|
43
|
+
],
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@types/jsonpath-plus": "^5.0.2",
|
|
46
|
+
"@types/lodash": "^4.14.195",
|
|
47
|
+
"@types/ps-tree": "^1.1.6",
|
|
48
|
+
"date-fns": "^4.1.0",
|
|
49
|
+
"date-fns-tz": "^3.2.0",
|
|
50
|
+
"entities": "^6.0.1",
|
|
51
|
+
"jsonpath-plus": "^10.3.0",
|
|
52
|
+
"jsonpointer": "^5.0.1",
|
|
53
|
+
"jsonwebtoken": "^9.0.2",
|
|
54
|
+
"lodash": "^4.17.12",
|
|
55
|
+
"ps-tree": "^1.2.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/jest": "^29.0.0",
|
|
59
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
60
|
+
"@types/node": "^24.0.0",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
62
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
63
|
+
"eslint": "^8.0.0",
|
|
64
|
+
"jest": "^29.6.0",
|
|
65
|
+
"ts-jest": "^29.4.2",
|
|
66
|
+
"typescript": "^5.9.1",
|
|
67
|
+
"semantic-release": "^24.0.0",
|
|
68
|
+
"@semantic-release/changelog": "^6.0.0",
|
|
69
|
+
"@semantic-release/commit-analyzer": "^13.0.0",
|
|
70
|
+
"@semantic-release/git": "^10.0.0",
|
|
71
|
+
"@semantic-release/npm": "^12.0.0",
|
|
72
|
+
"@semantic-release/release-notes-generator": "^14.0.0"
|
|
73
|
+
},
|
|
74
|
+
"publishConfig": {
|
|
75
|
+
"access": "public"
|
|
76
|
+
},
|
|
77
|
+
"jest": {
|
|
78
|
+
"moduleFileExtensions": [
|
|
79
|
+
"js",
|
|
80
|
+
"ts"
|
|
81
|
+
],
|
|
82
|
+
"testMatch": [
|
|
83
|
+
"**/*.spec.ts"
|
|
84
|
+
],
|
|
85
|
+
"rootDir": "src",
|
|
86
|
+
"transform": {
|
|
87
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
88
|
+
},
|
|
89
|
+
"transformIgnorePatterns": [],
|
|
90
|
+
"coverageDirectory": "../coverage",
|
|
91
|
+
"coverageReporters": [
|
|
92
|
+
"html",
|
|
93
|
+
"text",
|
|
94
|
+
"lcov",
|
|
95
|
+
"json-summary"
|
|
96
|
+
],
|
|
97
|
+
"coverageThreshold": {
|
|
98
|
+
"global": {
|
|
99
|
+
"branches": 88,
|
|
100
|
+
"functions": 90,
|
|
101
|
+
"lines": 90,
|
|
102
|
+
"statements": 90
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"testEnvironment": "node",
|
|
106
|
+
"reporters": [
|
|
107
|
+
"default"
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|