@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,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. `&amp;`, `&copy;`) and numeric entities (`&#169;`, `&#x1F44D;`) are decoded.
265
+ * - Non-breaking space characters (U+00A0) are replaced with regular spaces.
266
+ * - Literal apostrophes (`'`) are replaced with `&apos;` 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
+ }