typeshi 2.2.1 → 2.2.3
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/README.md +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/io/logging.d.ts +7 -6
- package/dist/utils/io/logging.js +21 -27
- package/dist/utils/io/reading.d.ts +2 -2
- package/dist/utils/io/reading.js +3 -3
- package/dist/utils/object.d.ts +9 -0
- package/dist/utils/object.js +32 -0
- package/dist/utils/regex/email.d.ts +27 -4
- package/dist/utils/regex/email.js +40 -8
- package/dist/utils/regex/misc.d.ts +18 -4
- package/dist/utils/regex/misc.js +35 -8
- package/dist/utils/regex/stringOperations.d.ts +5 -2
- package/dist/utils/regex/stringOperations.js +6 -3
- package/dist/utils/typeValidation.d.ts +31 -65
- package/dist/utils/typeValidation.js +71 -104
- package/dist/utils/utilityTypes.d.ts +67 -0
- package/dist/utils/utilityTypes.js +5 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Copy/paste into your project if you find something useful.
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -21,4 +21,5 @@ __exportStar(require("./io"), exports);
|
|
|
21
21
|
__exportStar(require("./regex"), exports);
|
|
22
22
|
__exportStar(require("./argumentValidation"), exports);
|
|
23
23
|
__exportStar(require("./typeValidation"), exports);
|
|
24
|
+
__exportStar(require("./utilityTypes"), exports);
|
|
24
25
|
__exportStar(require("./object"), exports);
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { ILogObj, ILogObjMeta } from "tslog";
|
|
2
2
|
/**
|
|
3
|
-
* @param
|
|
3
|
+
* @param base `string` - e.g. name of file or class
|
|
4
|
+
* - passed into `extractFileName()` if `/\\|\//.test(filename)`
|
|
4
5
|
* @param func `Function` - to get Function.name
|
|
5
6
|
* @param funcInfo `any` `(optional)` - context or params of func (converted to string)
|
|
6
7
|
* @param startLine `number` `(optional)`
|
|
7
8
|
* @param endLine `number` `(optional)`
|
|
8
9
|
* @returns **`sourceString`** `string` to use in log statements or argumentValidation calls
|
|
9
10
|
*/
|
|
10
|
-
export declare function getSourceString(
|
|
11
|
+
export declare function getSourceString(base: string, func: string | Function, funcInfo?: any, startLine?: number, endLine?: number): string;
|
|
11
12
|
/**
|
|
12
13
|
* @deprecated
|
|
13
14
|
* Auto-formats debug logs at the end of application execution.
|
|
14
15
|
* Call this function when your main application is finishing.
|
|
15
|
-
* @param
|
|
16
|
+
* @param filepaths `string[]` - optional, specific file paths to format.
|
|
16
17
|
* If not provided, will format all .txt files in the log directory.
|
|
17
18
|
* @returns `void`
|
|
18
19
|
*/
|
|
19
|
-
export declare function autoFormatLogsOnExit(
|
|
20
|
+
export declare function autoFormatLogsOnExit(filepaths?: string[]): void;
|
|
20
21
|
/**
|
|
21
22
|
* @deprecated
|
|
22
23
|
* Formats a debug log file from JSON format to a more readable text format.
|
|
@@ -31,11 +32,11 @@ export declare function formatDebugLogFile(inputPath: string, outputPath?: strin
|
|
|
31
32
|
* @deprecated
|
|
32
33
|
* Formats all debug log files in the log directory.
|
|
33
34
|
* Looks for .txt files and creates .FORMATTED.txt versions.
|
|
34
|
-
* @param
|
|
35
|
+
* @param logDir `string` - optional, path to the log directory.
|
|
35
36
|
* If not provided, uses LOCAL_LOG_DIR from setupLog.ts
|
|
36
37
|
* @returns `void`
|
|
37
38
|
*/
|
|
38
|
-
export declare function formatAllDebugLogs(
|
|
39
|
+
export declare function formatAllDebugLogs(logDir: string): void;
|
|
39
40
|
/**
|
|
40
41
|
* @deprecated
|
|
41
42
|
* reduce metadata to two entries, then return stringified `logObj`
|
package/dist/utils/io/logging.js
CHANGED
|
@@ -44,22 +44,24 @@ exports.formatLogObj = formatLogObj;
|
|
|
44
44
|
/**
|
|
45
45
|
* @file src/utils/io/logging.ts
|
|
46
46
|
*/
|
|
47
|
-
const
|
|
47
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
48
48
|
const setupLog_1 = require("../../config/setupLog");
|
|
49
49
|
const typeValidation_1 = require("../typeValidation");
|
|
50
50
|
const regex_1 = require("../regex");
|
|
51
51
|
const validate = __importStar(require("../argumentValidation"));
|
|
52
52
|
const node_path_1 = __importDefault(require("node:path"));
|
|
53
53
|
/**
|
|
54
|
-
* @param
|
|
54
|
+
* @param base `string` - e.g. name of file or class
|
|
55
|
+
* - passed into `extractFileName()` if `/\\|\//.test(filename)`
|
|
55
56
|
* @param func `Function` - to get Function.name
|
|
56
57
|
* @param funcInfo `any` `(optional)` - context or params of func (converted to string)
|
|
57
58
|
* @param startLine `number` `(optional)`
|
|
58
59
|
* @param endLine `number` `(optional)`
|
|
59
60
|
* @returns **`sourceString`** `string` to use in log statements or argumentValidation calls
|
|
60
61
|
*/
|
|
61
|
-
function getSourceString(
|
|
62
|
-
|
|
62
|
+
function getSourceString(base, func, funcInfo, startLine, endLine) {
|
|
63
|
+
if (/\\|\//.test(base))
|
|
64
|
+
base = (0, regex_1.extractFileName)(base);
|
|
63
65
|
let lineNumberText = ((0, typeValidation_1.isInteger)(startLine)
|
|
64
66
|
? `:${startLine}`
|
|
65
67
|
: '');
|
|
@@ -68,30 +70,23 @@ function getSourceString(fileName, func, funcInfo, startLine, endLine) {
|
|
|
68
70
|
? lineNumberText + `-${endLine}`
|
|
69
71
|
: '');
|
|
70
72
|
let funcName = typeof func === 'string' ? func : func.name;
|
|
71
|
-
return `[${
|
|
73
|
+
return `[${base}.${funcName}(${(0, typeValidation_1.isNonEmptyString)(funcInfo) ? ` ${funcInfo} ` : ''})${lineNumberText}]`;
|
|
72
74
|
}
|
|
73
75
|
/**
|
|
74
76
|
* @deprecated
|
|
75
77
|
* Auto-formats debug logs at the end of application execution.
|
|
76
78
|
* Call this function when your main application is finishing.
|
|
77
|
-
* @param
|
|
79
|
+
* @param filepaths `string[]` - optional, specific file paths to format.
|
|
78
80
|
* If not provided, will format all .txt files in the log directory.
|
|
79
81
|
* @returns `void`
|
|
80
82
|
*/
|
|
81
|
-
function autoFormatLogsOnExit(
|
|
82
|
-
const source = getSourceString(__filename, autoFormatLogsOnExit.name, `Array<string>(${(
|
|
83
|
-
if (!(0, typeValidation_1.isStringArray)(filePaths)) {
|
|
84
|
-
setupLog_1.typeshiLogger.warn([`${source} Invalid param 'filePaths'`,
|
|
85
|
-
`Expected: string[] (array of filePaths)`,
|
|
86
|
-
`Received: ${typeof filePaths} = '${JSON.stringify(filePaths)}'`
|
|
87
|
-
].join(setupLog_1.INDENT_LOG_LINE));
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
83
|
+
function autoFormatLogsOnExit(filepaths) {
|
|
84
|
+
const source = getSourceString(__filename, autoFormatLogsOnExit.name, `Array<string>(${(filepaths ?? []).length})`);
|
|
90
85
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
validate.arrayArgument(source, { filepaths, isStringArray: typeValidation_1.isStringArray });
|
|
87
|
+
for (const filePath of filepaths ?? []) {
|
|
88
|
+
if (node_fs_1.default.existsSync(filePath))
|
|
93
89
|
formatDebugLogFile(filePath);
|
|
94
|
-
}
|
|
95
90
|
}
|
|
96
91
|
}
|
|
97
92
|
catch (error) {
|
|
@@ -116,10 +111,10 @@ function formatDebugLogFile(inputPath, outputPath) {
|
|
|
116
111
|
const parsedPath = node_path_1.default.parse(inputPath);
|
|
117
112
|
outputPath = node_path_1.default.join(parsedPath.dir, `${parsedPath.name}.FORMATTED${parsedPath.ext}`);
|
|
118
113
|
}
|
|
119
|
-
const fileContent =
|
|
114
|
+
const fileContent = node_fs_1.default.readFileSync(inputPath, 'utf-8');
|
|
120
115
|
const formattedContent = formatLogContent(fileContent);
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
node_fs_1.default.writeFileSync(outputPath, formattedContent, { encoding: 'utf-8' });
|
|
117
|
+
setupLog_1.typeshiHiddenLogger.info(`[formatDebugLogFile()] Formatted log file saved to '${outputPath}'`);
|
|
123
118
|
}
|
|
124
119
|
catch (error) {
|
|
125
120
|
setupLog_1.typeshiLogger.error(`${source} Error formatting log file:'`, error);
|
|
@@ -216,18 +211,17 @@ function formatSingleLogEntry(logObj) {
|
|
|
216
211
|
* @deprecated
|
|
217
212
|
* Formats all debug log files in the log directory.
|
|
218
213
|
* Looks for .txt files and creates .FORMATTED.txt versions.
|
|
219
|
-
* @param
|
|
214
|
+
* @param logDir `string` - optional, path to the log directory.
|
|
220
215
|
* If not provided, uses LOCAL_LOG_DIR from setupLog.ts
|
|
221
216
|
* @returns `void`
|
|
222
217
|
*/
|
|
223
|
-
function formatAllDebugLogs(
|
|
224
|
-
|
|
225
|
-
if (!fs.existsSync(logDir)) {
|
|
218
|
+
function formatAllDebugLogs(logDir) {
|
|
219
|
+
if (!node_fs_1.default.existsSync(logDir)) {
|
|
226
220
|
setupLog_1.typeshiLogger.warn(`[formatAllDebugLogs()] Log directory does not exist: ${logDir}`);
|
|
227
221
|
return;
|
|
228
222
|
}
|
|
229
223
|
try {
|
|
230
|
-
const files =
|
|
224
|
+
const files = node_fs_1.default.readdirSync(logDir);
|
|
231
225
|
const txtFiles = files.filter(file => file.endsWith('.txt') && !file.includes('.FORMATTED.'));
|
|
232
226
|
if (txtFiles.length === 0) {
|
|
233
227
|
setupLog_1.typeshiLogger.warn(`[formatAllDebugLogs()] No .txt log files found in ${logDir}`);
|
|
@@ -237,7 +231,7 @@ function formatAllDebugLogs(logDirectory) {
|
|
|
237
231
|
const inputPath = node_path_1.default.join(logDir, txtFile);
|
|
238
232
|
try {
|
|
239
233
|
formatDebugLogFile(inputPath);
|
|
240
|
-
|
|
234
|
+
setupLog_1.typeshiHiddenLogger.info(`[formatAllDebugLogs()] Formatted: ${txtFile}`);
|
|
241
235
|
}
|
|
242
236
|
catch (error) {
|
|
243
237
|
setupLog_1.typeshiLogger.error(`[formatAllDebugLogs()] Failed to format ${txtFile}:`, error);
|
|
@@ -2,9 +2,9 @@ import { StringCleanOptions } from "../regex";
|
|
|
2
2
|
import { DirectoryFileOptions, FileData, FileExtension } from "./types/Io";
|
|
3
3
|
import { DelimiterCharacterEnum } from "./types";
|
|
4
4
|
/** checks if `pathString (value)` points to an existing directory */
|
|
5
|
-
export declare function isDirectory(value: any):
|
|
5
|
+
export declare function isDirectory(value: any): boolean;
|
|
6
6
|
/** checks if `pathString (value)` points to an existing file */
|
|
7
|
-
export declare function isFile(value: string):
|
|
7
|
+
export declare function isFile(value: string): boolean;
|
|
8
8
|
/**
|
|
9
9
|
* Determines the proper delimiter based on file type or extension
|
|
10
10
|
* @param filePath `string` Path to the file
|
package/dist/utils/io/reading.js
CHANGED
|
@@ -472,8 +472,8 @@ async function getOneToOneDictionary(arg1, keyColumn, valueColumn, keyOptions, v
|
|
|
472
472
|
*/
|
|
473
473
|
async function getColumnValues(arg1, columnName, cleaner, allowDuplicates = false) {
|
|
474
474
|
const source = (0, logging_1.getSourceString)(__filename, getColumnValues.name);
|
|
475
|
-
validate.stringArgument(source, {
|
|
476
|
-
validate.booleanArgument(source, {
|
|
475
|
+
// validate.stringArgument(source, {columnName});
|
|
476
|
+
// validate.booleanArgument(source, {allowDuplicates});
|
|
477
477
|
if (cleaner)
|
|
478
478
|
validate.functionArgument(source, { cleaner });
|
|
479
479
|
let rows = await handleFileArgument(arg1, getColumnValues.name, [columnName]);
|
|
@@ -497,7 +497,7 @@ async function getColumnValues(arg1, columnName, cleaner, allowDuplicates = fals
|
|
|
497
497
|
*/
|
|
498
498
|
async function getIndexedColumnValues(arg1, columnName, cleaner) {
|
|
499
499
|
const source = `[reading.getIndexedColumnValues()]`;
|
|
500
|
-
validate.stringArgument(source, {
|
|
500
|
+
// validate.stringArgument(source, {columnName});
|
|
501
501
|
if (cleaner)
|
|
502
502
|
validate.functionArgument(source, { cleaner });
|
|
503
503
|
let rows = await handleFileArgument(arg1, getIndexedColumnValues.name, [columnName]);
|
package/dist/utils/object.d.ts
CHANGED
|
@@ -100,3 +100,12 @@ export declare function hasDefinedEntry<T extends object>(obj: any, key: keyof T
|
|
|
100
100
|
export declare function containsKey<T extends object, K extends (keyof T | (keyof any & {})) = any>(obj: T, ...keys: K[]): obj is {
|
|
101
101
|
[K in keyof T]: T[K];
|
|
102
102
|
};
|
|
103
|
+
/**
|
|
104
|
+
* @deprecated
|
|
105
|
+
* @param objA `Record<string, any>`
|
|
106
|
+
* @param objB `Record<string, any>`
|
|
107
|
+
* @returns **`areEquivalentObjects`** `boolean`
|
|
108
|
+
* - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
|
|
109
|
+
* - `false` `otherwise`.
|
|
110
|
+
*/
|
|
111
|
+
export declare function areEquivalentObjects(objA: Record<string, any>, objB: Record<string, any>): boolean;
|
package/dist/utils/object.js
CHANGED
|
@@ -11,7 +11,9 @@ exports.picked = picked;
|
|
|
11
11
|
exports.enforceMaxLength = enforceMaxLength;
|
|
12
12
|
exports.hasDefinedEntry = hasDefinedEntry;
|
|
13
13
|
exports.containsKey = containsKey;
|
|
14
|
+
exports.areEquivalentObjects = areEquivalentObjects;
|
|
14
15
|
const typeValidation_1 = require("./typeValidation");
|
|
16
|
+
const index_1 = require("./regex/index");
|
|
15
17
|
/**
|
|
16
18
|
* @param obj `S` - source object (e.g., Request Body)
|
|
17
19
|
* @param schema {@link TransformationSchema}`<T, S>` - map of keys to transformation functions.
|
|
@@ -177,3 +179,33 @@ function containsKey(obj, ...keys) {
|
|
|
177
179
|
}
|
|
178
180
|
return true;
|
|
179
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* @deprecated
|
|
184
|
+
* @param objA `Record<string, any>`
|
|
185
|
+
* @param objB `Record<string, any>`
|
|
186
|
+
* @returns **`areEquivalentObjects`** `boolean`
|
|
187
|
+
* - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
|
|
188
|
+
* - `false` `otherwise`.
|
|
189
|
+
*/
|
|
190
|
+
function areEquivalentObjects(objA, objB) {
|
|
191
|
+
if (!(0, typeValidation_1.isObject)(objA) || !(0, typeValidation_1.isObject)(objB))
|
|
192
|
+
return false;
|
|
193
|
+
const keysA = Object.keys(objA);
|
|
194
|
+
const keysB = Object.keys(objB);
|
|
195
|
+
if (keysA.length !== keysB.length)
|
|
196
|
+
return false;
|
|
197
|
+
return keysA.every(key => {
|
|
198
|
+
if (!containsKey(objB, key))
|
|
199
|
+
return false; // key not in both objects
|
|
200
|
+
const valA = objA[key];
|
|
201
|
+
const valB = objB[key];
|
|
202
|
+
if (Array.isArray(valA) && Array.isArray(valB)) {
|
|
203
|
+
return valA.length === valB.length
|
|
204
|
+
&& valA.every((item) => valB.includes(item));
|
|
205
|
+
}
|
|
206
|
+
else if (typeof valA === "object" && valA && typeof valB === "object" && valB) {
|
|
207
|
+
return areEquivalentObjects(valA, valB);
|
|
208
|
+
}
|
|
209
|
+
return (0, index_1.equivalentAlphanumericStrings)(valA, valB);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
@@ -1,6 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
export interface ParsedEmailAddress {
|
|
2
|
+
/** the whole email address */
|
|
3
|
+
address: string;
|
|
4
|
+
/** `localPart` the part before the @ sign */
|
|
5
|
+
local: string;
|
|
6
|
+
/** the part after the @ sign */
|
|
7
|
+
domain: string;
|
|
8
|
+
/** sender's display name if present in source string */
|
|
9
|
+
displayName?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* @param s `string`
|
|
13
|
+
* - e.g. `"{local}@{domain}"`, `"{displayName} <{local}@{domain}>"`
|
|
14
|
+
* @returns **`result`** {@link ParsedEmailAddress}` | null`
|
|
15
|
+
* @note `ParsedEmail.displayName` will be `undefined` if not present in `s`
|
|
16
|
+
* - prefix `/^no(-)?reply\s*(?=\w)/i` is removed from `displayName`
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseEmailAddress(s: string): ParsedEmailAddress | null;
|
|
19
|
+
/** @deprecated
|
|
20
|
+
* `re` = `/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/` */
|
|
2
21
|
export declare const EMAIL_REGEX: RegExp;
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated
|
|
24
|
+
* return true if matches {@link EMAIL_REGEX} and does not include pattern/string specified in `excludeSubstrings` */
|
|
25
|
+
export declare function isValidEmail(email: string, excludeSubstrings?: string | string[] | RegExp): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated
|
|
28
|
+
* @returns `RegExpMatchArray` {@link EMAIL_REGEX} */
|
|
6
29
|
export declare function extractEmail(email: string): RegExpMatchArray | null;
|
|
@@ -1,24 +1,56 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EMAIL_REGEX = void 0;
|
|
4
|
+
exports.parseEmailAddress = parseEmailAddress;
|
|
4
5
|
exports.isValidEmail = isValidEmail;
|
|
5
6
|
exports.extractEmail = extractEmail;
|
|
6
7
|
/**
|
|
7
8
|
* @file src/utils/regex/email.ts
|
|
8
9
|
*/
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const Str_1 = require("./Str");
|
|
11
|
+
// @TODO parameterize replacements in parsed displayName
|
|
12
|
+
/**
|
|
13
|
+
* @param s `string`
|
|
14
|
+
* - e.g. `"{local}@{domain}"`, `"{displayName} <{local}@{domain}>"`
|
|
15
|
+
* @returns **`result`** {@link ParsedEmailAddress}` | null`
|
|
16
|
+
* @note `ParsedEmail.displayName` will be `undefined` if not present in `s`
|
|
17
|
+
* - prefix `/^no(-)?reply\s*(?=\w)/i` is removed from `displayName`
|
|
18
|
+
*/
|
|
19
|
+
function parseEmailAddress(s) {
|
|
20
|
+
const emailRegex = /([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g;
|
|
21
|
+
const matchArrays = Array.from(s.matchAll(emailRegex));
|
|
22
|
+
if (matchArrays.length === 0)
|
|
23
|
+
return null;
|
|
24
|
+
const match = matchArrays[0];
|
|
25
|
+
const [address, local, domain] = match;
|
|
26
|
+
const displayName = (s
|
|
27
|
+
.slice(0, match.index ?? 0)
|
|
28
|
+
.trim()
|
|
29
|
+
.replace(/^no(-)?reply\s*(?=\w)/i, '')
|
|
30
|
+
.replace(/<$/, '')
|
|
31
|
+
.trim());
|
|
32
|
+
const result = { address, local, domain };
|
|
33
|
+
if (displayName)
|
|
34
|
+
result.displayName = displayName;
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
/** @deprecated
|
|
38
|
+
* `re` = `/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/` */
|
|
39
|
+
exports.EMAIL_REGEX = new RegExp(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated
|
|
42
|
+
* return true if matches {@link EMAIL_REGEX} and does not include pattern/string specified in `excludeSubstrings` */
|
|
14
43
|
function isValidEmail(email, excludeSubstrings) {
|
|
15
44
|
if (!email)
|
|
16
45
|
return false;
|
|
17
46
|
email = email.trim();
|
|
18
|
-
return
|
|
19
|
-
|
|
47
|
+
return (excludeSubstrings
|
|
48
|
+
? exports.EMAIL_REGEX.test(email) && !Str_1.Str.contains(email, excludeSubstrings)
|
|
49
|
+
: exports.EMAIL_REGEX.test(email));
|
|
20
50
|
}
|
|
21
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* @deprecated
|
|
53
|
+
* @returns `RegExpMatchArray` {@link EMAIL_REGEX} */
|
|
22
54
|
function extractEmail(email) {
|
|
23
55
|
if (!email)
|
|
24
56
|
return null;
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* `extractFileNameFromPath`
|
|
6
6
|
* essentially a wrapper for path.basename() for short-hand convenience
|
|
7
|
-
* @param
|
|
7
|
+
* @param filepath `string` e.g. pass in the node module variable `__filename`
|
|
8
8
|
* @param removeExtension `boolean` `optional, default = true` - flag indicating
|
|
9
|
-
* whether or not to remove the file extension from the
|
|
10
|
-
* @returns **`
|
|
9
|
+
* whether or not to remove the file extension from the filename
|
|
10
|
+
* @returns **`filename`** `string`
|
|
11
11
|
*/
|
|
12
|
-
export declare function extractFileName(
|
|
12
|
+
export declare function extractFileName(filepath: string, removeExtension?: boolean): string;
|
|
13
13
|
/**
|
|
14
14
|
* = `= /^[^/\\:*?"<>|]+(\.[^/\\:*?"<>|]+)$/`
|
|
15
15
|
*/
|
|
@@ -33,3 +33,17 @@ export declare const KOREA_ADDRESS_LATIN_TEXT_PATTERN: RegExp;
|
|
|
33
33
|
* @returns **`leaf`**: `string` - the extracted `leaf` or the original value if no extraction performed
|
|
34
34
|
*/
|
|
35
35
|
export declare function extractLeaf(value: string, classDelimiter: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* @param keepParentheses `boolean (optional)` `default = false`
|
|
38
|
+
* @returns **new RegExp** with same flags as `re`
|
|
39
|
+
* - returns `re` if does not have `groupName`
|
|
40
|
+
* @example
|
|
41
|
+
* const re = /(?<name>)\s*abcdefg/;
|
|
42
|
+
* let groupName = 'name';
|
|
43
|
+
* let value = 'Bob';
|
|
44
|
+
* let result1 = replaceGroupWithLiteral(re, groupName, value, false);
|
|
45
|
+
* // result1.source === 'Bob\\s*abcdefg'
|
|
46
|
+
* let result2 = replaceGroupWithLiteral(re, groupName, value, true);
|
|
47
|
+
* // result2.source === '(Bob)\\s*abcdefg'
|
|
48
|
+
*/
|
|
49
|
+
export declare function replaceGroupWithLiteral(re: RegExp, groupName: string, value: string, keepParentheses?: boolean): RegExp;
|
package/dist/utils/regex/misc.js
CHANGED
|
@@ -9,25 +9,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.KOREA_ADDRESS_LATIN_TEXT_PATTERN = exports.DATE_STRING_PATTERN = exports.FILE_NAME_WITH_EXTENSION_PATTERN = void 0;
|
|
10
10
|
exports.extractFileName = extractFileName;
|
|
11
11
|
exports.extractLeaf = extractLeaf;
|
|
12
|
+
exports.replaceGroupWithLiteral = replaceGroupWithLiteral;
|
|
12
13
|
const typeValidation_1 = require("../typeValidation");
|
|
13
14
|
const node_path_1 = __importDefault(require("node:path"));
|
|
14
15
|
/**
|
|
15
16
|
* `extractFileNameFromPath`
|
|
16
17
|
* essentially a wrapper for path.basename() for short-hand convenience
|
|
17
|
-
* @param
|
|
18
|
+
* @param filepath `string` e.g. pass in the node module variable `__filename`
|
|
18
19
|
* @param removeExtension `boolean` `optional, default = true` - flag indicating
|
|
19
|
-
* whether or not to remove the file extension from the
|
|
20
|
-
* @returns **`
|
|
20
|
+
* whether or not to remove the file extension from the filename
|
|
21
|
+
* @returns **`filename`** `string`
|
|
21
22
|
*/
|
|
22
|
-
function extractFileName(
|
|
23
|
-
if (!(0, typeValidation_1.isNonEmptyString)(
|
|
23
|
+
function extractFileName(filepath, removeExtension = true) {
|
|
24
|
+
if (!(0, typeValidation_1.isNonEmptyString)(filepath)) {
|
|
24
25
|
return 'undefined';
|
|
25
26
|
}
|
|
26
|
-
let
|
|
27
|
+
let filename = node_path_1.default.basename(filepath);
|
|
27
28
|
if (removeExtension) {
|
|
28
|
-
|
|
29
|
+
filename = filename.replace(/(?<=.+)\.[a-z0-9]{1,}$/i, '');
|
|
29
30
|
}
|
|
30
|
-
return
|
|
31
|
+
return filename;
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
33
34
|
* = `= /^[^/\\:*?"<>|]+(\.[^/\\:*?"<>|]+)$/`
|
|
@@ -59,3 +60,29 @@ function extractLeaf(value, classDelimiter) {
|
|
|
59
60
|
}
|
|
60
61
|
return result || value;
|
|
61
62
|
}
|
|
63
|
+
// @consideration rename keepParentheses to keepGroup or keepGrouping or keepGroupParentheses ?
|
|
64
|
+
/**
|
|
65
|
+
* @param keepParentheses `boolean (optional)` `default = false`
|
|
66
|
+
* @returns **new RegExp** with same flags as `re`
|
|
67
|
+
* - returns `re` if does not have `groupName`
|
|
68
|
+
* @example
|
|
69
|
+
* const re = /(?<name>)\s*abcdefg/;
|
|
70
|
+
* let groupName = 'name';
|
|
71
|
+
* let value = 'Bob';
|
|
72
|
+
* let result1 = replaceGroupWithLiteral(re, groupName, value, false);
|
|
73
|
+
* // result1.source === 'Bob\\s*abcdefg'
|
|
74
|
+
* let result2 = replaceGroupWithLiteral(re, groupName, value, true);
|
|
75
|
+
* // result2.source === '(Bob)\\s*abcdefg'
|
|
76
|
+
*/
|
|
77
|
+
function replaceGroupWithLiteral(re, groupName, value, keepParentheses = false) {
|
|
78
|
+
let pat = (keepParentheses
|
|
79
|
+
? `(?<=\\\()` + `\\\?<${groupName}>` + `(?=\\\))`
|
|
80
|
+
: `\\\(` + `\\\?<${groupName}>` + `\\\)`);
|
|
81
|
+
let groupPattern = new RegExp(pat);
|
|
82
|
+
if (!groupPattern.test(re.source)) { // re does not contain group
|
|
83
|
+
console.warn(`[regex.misc.replaceGroupWithLiteral()] re does not contain group '${groupName}'`);
|
|
84
|
+
return re;
|
|
85
|
+
}
|
|
86
|
+
let newSource = re.source.replace(groupPattern, value);
|
|
87
|
+
return new RegExp(newSource, re.flags);
|
|
88
|
+
}
|
|
@@ -40,6 +40,9 @@ export declare function stringContainsAnyOf(s: string, substrings: string | stri
|
|
|
40
40
|
* - **`false`** `otherwise`.
|
|
41
41
|
*/
|
|
42
42
|
export declare function equivalentAlphanumericStrings(s1: string, s2: string, tolerance?: number): boolean;
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated
|
|
45
|
+
* for simple regular expressions...
|
|
46
|
+
* so like not ones that have parentheses, pipes, or curly braced numbers
|
|
47
|
+
* */
|
|
45
48
|
export declare function extractSource(regex: RegExp): string;
|
|
@@ -128,7 +128,7 @@ function stringContainsAnyOf(s, substrings, ...flags) {
|
|
|
128
128
|
regex = new RegExp(substrings, flagString);
|
|
129
129
|
}
|
|
130
130
|
if (!regex) {
|
|
131
|
-
config_1.typeshiLogger.warn('containsAnyOf() Invalid substrings type. returning false.', config_1.INDENT_LOG_LINE + `Expected string, array of strings, or RegExp, but received: ${typeof substrings}, ${substrings}`);
|
|
131
|
+
config_1.typeshiLogger.warn('[containsAnyOf()] Invalid substrings type. returning false.', config_1.INDENT_LOG_LINE + `Expected string, array of strings, or RegExp, but received: ${typeof substrings}, ${substrings}`);
|
|
132
132
|
return false; // Invalid substrings type
|
|
133
133
|
}
|
|
134
134
|
return regex.test(s);
|
|
@@ -178,8 +178,11 @@ function equivalentAlphanumericStrings(s1, s2, tolerance = 0.90) {
|
|
|
178
178
|
}
|
|
179
179
|
return false;
|
|
180
180
|
}
|
|
181
|
-
/**
|
|
182
|
-
*
|
|
181
|
+
/**
|
|
182
|
+
* @deprecated
|
|
183
|
+
* for simple regular expressions...
|
|
184
|
+
* so like not ones that have parentheses, pipes, or curly braced numbers
|
|
185
|
+
* */
|
|
183
186
|
function extractSource(regex) {
|
|
184
187
|
if (!regex)
|
|
185
188
|
return '';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - **`true`** if `value` is an array and has at least one element,
|
|
8
8
|
* - **`false`** otherwise.
|
|
9
9
|
*/
|
|
10
|
-
export declare function isNonEmptyArray<T>(value:
|
|
10
|
+
export declare function isNonEmptyArray<T>(value: unknown): value is Array<T> & {
|
|
11
11
|
length: number;
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
@@ -16,7 +16,7 @@ export declare function isNonEmptyArray<T>(value: any): value is Array<T> & {
|
|
|
16
16
|
* - **`true`** if `value` is an array and has no elements,
|
|
17
17
|
* - **`false`** `otherwise`
|
|
18
18
|
*/
|
|
19
|
-
export declare function isEmptyArray<T>(value:
|
|
19
|
+
export declare function isEmptyArray<T>(value: unknown): value is Array<T> & {
|
|
20
20
|
length: 0;
|
|
21
21
|
};
|
|
22
22
|
/**
|
|
@@ -27,13 +27,12 @@ export declare function isEmptyArray<T>(value: any): value is Array<T> & {
|
|
|
27
27
|
* - `if` `false` then `value` can be empty array
|
|
28
28
|
* @returns **`isIntegerArray`** `boolean` = `value is number[] & { length: number }`
|
|
29
29
|
*/
|
|
30
|
-
export declare function isIntegerArray(value:
|
|
30
|
+
export declare function isIntegerArray(value: unknown, requireNonNegative?: boolean, requireNonEmpty?: boolean): value is number[] & {
|
|
31
31
|
length: number;
|
|
32
32
|
};
|
|
33
33
|
/**
|
|
34
|
-
* @consideration add param to allow for empty strings?
|
|
35
34
|
* @param value `any`
|
|
36
|
-
* @param requireNonEmpty `boolean` `default = true`
|
|
35
|
+
* @param requireNonEmpty `boolean` `aka "requireNonEmptyArray"` `default = true`
|
|
37
36
|
* - `if` `true` then `value` must be array with at least 1 element and every element `isNonEmptyString`
|
|
38
37
|
* - `if` `false` then `value` can be empty array
|
|
39
38
|
* @returns **`isStringArray`** `boolean` = `value is string[] & { length: number }`
|
|
@@ -41,40 +40,6 @@ export declare function isIntegerArray(value: any, requireNonNegative?: boolean,
|
|
|
41
40
|
export declare function isStringArray(value: any, requireNonEmpty?: boolean): value is string[] & {
|
|
42
41
|
length: number;
|
|
43
42
|
};
|
|
44
|
-
/**
|
|
45
|
-
* `fka hasNonTrivialKeys`
|
|
46
|
-
* @note **passing in an array will return `false`.**
|
|
47
|
-
* @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
|
|
48
|
-
* @param obj `any` The object to check.
|
|
49
|
-
* @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
|
|
50
|
-
* @returns **`hasNonTrivialEntries`** `boolean`
|
|
51
|
-
* - **`true`** `if` the `obj` has non-empty keys,
|
|
52
|
-
* - **`false`** `otherwise`
|
|
53
|
-
*/
|
|
54
|
-
export declare function hasNonTrivialEntries<T extends object>(obj: T, requireAll?: boolean): obj is T;
|
|
55
|
-
/**
|
|
56
|
-
* @note uses `key in obj` for each element of param `keys`
|
|
57
|
-
* @param obj `T extends Object` the object to check
|
|
58
|
-
* @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
|
|
59
|
-
* @param requireAll `boolean` defaults to `true`
|
|
60
|
-
* - `if` `true`, all keys must be present in the object;
|
|
61
|
-
* - `if` `false`, at least one key must be present
|
|
62
|
-
* @param restrictKeys `boolean` defaults to `false`
|
|
63
|
-
* - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
|
|
64
|
-
* - `if` `false`, the object can keys not included in the `keys` param.
|
|
65
|
-
* @returns **`hasKeys`** `boolean`
|
|
66
|
-
* - **`true`** `if` `obj` is of type 'object' and has the required key(s),
|
|
67
|
-
* - **`false`** `otherwise`
|
|
68
|
-
*/
|
|
69
|
-
export declare function hasKeys<T extends object>(obj: T, keys: Array<keyof T> | string[] | string, requireAll?: boolean, restrictKeys?: boolean): boolean;
|
|
70
|
-
/**
|
|
71
|
-
* @param objA `Record<string, any>`
|
|
72
|
-
* @param objB `Record<string, any>`
|
|
73
|
-
* @returns **`areEquivalentObjects`** `boolean`
|
|
74
|
-
* - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
|
|
75
|
-
* - `false` `otherwise`.
|
|
76
|
-
*/
|
|
77
|
-
export declare function areEquivalentObjects(objA: Record<string, any>, objB: Record<string, any>): boolean;
|
|
78
43
|
/**
|
|
79
44
|
* @param value `any`
|
|
80
45
|
* @param requireInteger `boolean` `default = false`
|
|
@@ -116,7 +81,7 @@ export declare function isInteger(value: unknown, requireNonNegative?: boolean):
|
|
|
116
81
|
* - `if` `false` then `value` is allowed to be an array
|
|
117
82
|
* @returns **`isObject`** `boolean` `value is T`
|
|
118
83
|
*/
|
|
119
|
-
export declare function isObject<T extends object = Record<
|
|
84
|
+
export declare function isObject<T extends object = Record<keyof any, any>>(value: unknown, requireNonEmpty?: boolean, requireNonArray?: boolean): value is T;
|
|
120
85
|
export declare function isPositveInteger(value: unknown): value is number;
|
|
121
86
|
export declare const isType: <T>(value: any, guard: (v: any, ...args: any[]) => v is T, ...args: any[]) => value is T;
|
|
122
87
|
/**
|
|
@@ -243,30 +208,31 @@ export declare function isNull(value: unknown): value is null;
|
|
|
243
208
|
*/
|
|
244
209
|
export declare function isUndefined(value: any): value is undefined;
|
|
245
210
|
export declare function isUndefinedOrNull(value: unknown): value is undefined | null;
|
|
246
|
-
export type NumberKeys<T, Required extends boolean = false> = {
|
|
247
|
-
[K in keyof T]: Required extends true ? (T[K] extends number ? K : never) : (T[K] extends number | undefined ? K : never);
|
|
248
|
-
}[keyof T][];
|
|
249
|
-
export type ArrayKeys<T, Required extends boolean = false> = {
|
|
250
|
-
[K in keyof T]: Required extends true ? (T[K] extends Array<any> ? K : never) : (T[K] extends Array<any> | undefined ? K : never);
|
|
251
|
-
}[keyof T][];
|
|
252
|
-
export type ArrayOfTypeKeys<T, U, Required extends boolean = false> = {
|
|
253
|
-
[K in keyof T]: Required extends true ? (T[K] extends Array<U> ? K : never) : (T[K] extends Array<U> | undefined ? K : never);
|
|
254
|
-
}[keyof T][];
|
|
255
|
-
export type StringKeys<T, Required extends boolean = false> = {
|
|
256
|
-
[K in keyof T]: Required extends true ? (T[K] extends string ? K : never) : (T[K] extends string | undefined ? K : never);
|
|
257
|
-
}[keyof T][];
|
|
258
|
-
export type PrimitiveKeys<T, Required extends boolean = false> = {
|
|
259
|
-
[K in keyof T]: Required extends true ? (T[K] extends string | number | boolean | null ? K : never) : (T[K] extends string | number | boolean | null | undefined ? K : never);
|
|
260
|
-
}[keyof T][];
|
|
261
|
-
export type Primitive = string | number | boolean | null | undefined;
|
|
262
|
-
/** Get the union of all values of `T` (like `valueof T`) */
|
|
263
|
-
export type ValueOf<T> = T[keyof T];
|
|
264
211
|
/**
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
* @
|
|
268
|
-
* @
|
|
212
|
+
* @deprecated
|
|
213
|
+
* `fka hasNonTrivialKeys`
|
|
214
|
+
* @note **passing in an array will return `false`.**
|
|
215
|
+
* @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
|
|
216
|
+
* @param obj `any` The object to check.
|
|
217
|
+
* @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
|
|
218
|
+
* @returns **`hasNonTrivialEntries`** `boolean`
|
|
219
|
+
* - **`true`** `if` the `obj` has non-empty keys,
|
|
220
|
+
* - **`false`** `otherwise`
|
|
221
|
+
*/
|
|
222
|
+
export declare function hasNonTrivialEntries<T extends object>(obj: T, requireAll?: boolean): obj is T;
|
|
223
|
+
/**
|
|
224
|
+
* @deprecated
|
|
225
|
+
* @note uses `key in obj` for each element of param `keys`
|
|
226
|
+
* @param obj `T extends Object` the object to check
|
|
227
|
+
* @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
|
|
228
|
+
* @param requireAll `boolean` defaults to `true`
|
|
229
|
+
* - `if` `true`, all keys must be present in the object;
|
|
230
|
+
* - `if` `false`, at least one key must be present
|
|
231
|
+
* @param restrictKeys `boolean` defaults to `false`
|
|
232
|
+
* - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
|
|
233
|
+
* - `if` `false`, the object can keys not included in the `keys` param.
|
|
234
|
+
* @returns **`hasKeys`** `boolean`
|
|
235
|
+
* - **`true`** `if` `obj` is of type 'object' and has the required key(s),
|
|
236
|
+
* - **`false`** `otherwise`
|
|
269
237
|
*/
|
|
270
|
-
export
|
|
271
|
-
[K in keyof T]: Required extends true ? (T[K] extends U ? K : never) : (T[K] extends U | undefined ? K : never);
|
|
272
|
-
}[keyof T][];
|
|
238
|
+
export declare function hasKeys<T extends object = any>(obj: T, keys: Array<keyof T> | string[] | string, requireAll?: boolean, restrictKeys?: boolean): boolean;
|
|
@@ -8,9 +8,6 @@ exports.isNonEmptyArray = isNonEmptyArray;
|
|
|
8
8
|
exports.isEmptyArray = isEmptyArray;
|
|
9
9
|
exports.isIntegerArray = isIntegerArray;
|
|
10
10
|
exports.isStringArray = isStringArray;
|
|
11
|
-
exports.hasNonTrivialEntries = hasNonTrivialEntries;
|
|
12
|
-
exports.hasKeys = hasKeys;
|
|
13
|
-
exports.areEquivalentObjects = areEquivalentObjects;
|
|
14
11
|
exports.isNumeric = isNumeric;
|
|
15
12
|
exports.isNonEmptyString = isNonEmptyString;
|
|
16
13
|
exports.isPrimitiveValue = isPrimitiveValue;
|
|
@@ -23,7 +20,8 @@ exports.isFunction = isFunction;
|
|
|
23
20
|
exports.isNull = isNull;
|
|
24
21
|
exports.isUndefined = isUndefined;
|
|
25
22
|
exports.isUndefinedOrNull = isUndefinedOrNull;
|
|
26
|
-
|
|
23
|
+
exports.hasNonTrivialEntries = hasNonTrivialEntries;
|
|
24
|
+
exports.hasKeys = hasKeys;
|
|
27
25
|
/**
|
|
28
26
|
* @param value
|
|
29
27
|
* @returns **`isNonEmptyArray`** `boolean` = `value is Array<T> & { length: number }`
|
|
@@ -55,10 +53,10 @@ function isIntegerArray(value, requireNonNegative = false, requireNonEmpty = tru
|
|
|
55
53
|
? isNonEmptyArray(value) && value.every(el => isInteger(el, requireNonNegative))
|
|
56
54
|
: isEmptyArray(value));
|
|
57
55
|
}
|
|
56
|
+
// * @consideration add param to allow for empty strings?
|
|
58
57
|
/**
|
|
59
|
-
* @consideration add param to allow for empty strings?
|
|
60
58
|
* @param value `any`
|
|
61
|
-
* @param requireNonEmpty `boolean` `default = true`
|
|
59
|
+
* @param requireNonEmpty `boolean` `aka "requireNonEmptyArray"` `default = true`
|
|
62
60
|
* - `if` `true` then `value` must be array with at least 1 element and every element `isNonEmptyString`
|
|
63
61
|
* - `if` `false` then `value` can be empty array
|
|
64
62
|
* @returns **`isStringArray`** `boolean` = `value is string[] & { length: number }`
|
|
@@ -68,103 +66,6 @@ function isStringArray(value, requireNonEmpty = true) {
|
|
|
68
66
|
? isNonEmptyArray(value) && value.every(el => isNonEmptyString(el))
|
|
69
67
|
: isEmptyArray(value));
|
|
70
68
|
}
|
|
71
|
-
// maybe deprecate this
|
|
72
|
-
/**
|
|
73
|
-
* `fka hasNonTrivialKeys`
|
|
74
|
-
* @note **passing in an array will return `false`.**
|
|
75
|
-
* @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
|
|
76
|
-
* @param obj `any` The object to check.
|
|
77
|
-
* @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
|
|
78
|
-
* @returns **`hasNonTrivialEntries`** `boolean`
|
|
79
|
-
* - **`true`** `if` the `obj` has non-empty keys,
|
|
80
|
-
* - **`false`** `otherwise`
|
|
81
|
-
*/
|
|
82
|
-
function hasNonTrivialEntries(obj, requireAll = false) {
|
|
83
|
-
if (!isObject(obj)) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
return (requireAll
|
|
87
|
-
? Object.values(obj).every(v => !isEmpty(v))
|
|
88
|
-
: Object.values(obj).some(v => !isEmpty(v)));
|
|
89
|
-
}
|
|
90
|
-
// @TODO add overload on param `keys` where keys = `{ required: string[], optional: string[] }`
|
|
91
|
-
// maybe deprecate this
|
|
92
|
-
/**
|
|
93
|
-
* @note uses `key in obj` for each element of param `keys`
|
|
94
|
-
* @param obj `T extends Object` the object to check
|
|
95
|
-
* @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
|
|
96
|
-
* @param requireAll `boolean` defaults to `true`
|
|
97
|
-
* - `if` `true`, all keys must be present in the object;
|
|
98
|
-
* - `if` `false`, at least one key must be present
|
|
99
|
-
* @param restrictKeys `boolean` defaults to `false`
|
|
100
|
-
* - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
|
|
101
|
-
* - `if` `false`, the object can keys not included in the `keys` param.
|
|
102
|
-
* @returns **`hasKeys`** `boolean`
|
|
103
|
-
* - **`true`** `if` `obj` is of type 'object' and has the required key(s),
|
|
104
|
-
* - **`false`** `otherwise`
|
|
105
|
-
*/
|
|
106
|
-
function hasKeys(obj, keys, requireAll = true, restrictKeys = false) {
|
|
107
|
-
if (!obj || typeof obj !== 'object') {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
if (keys === null || keys === undefined) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
if (!isNonEmptyArray(keys)) {
|
|
114
|
-
keys = [keys]; // Convert string (assumed to be single key) to array of keys
|
|
115
|
-
}
|
|
116
|
-
let numKeysFound = 0;
|
|
117
|
-
for (const key of keys) {
|
|
118
|
-
if (key in obj) {
|
|
119
|
-
numKeysFound++;
|
|
120
|
-
if (!requireAll && !restrictKeys) {
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
else if (requireAll) { // and a key is not found
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
if (restrictKeys) {
|
|
129
|
-
// If restrictKeys is true, check that no other keys are present in the object
|
|
130
|
-
const objKeys = Object.keys(obj);
|
|
131
|
-
const extraKeys = objKeys.filter(k => !keys.includes(k));
|
|
132
|
-
if (extraKeys.length > 0) {
|
|
133
|
-
return false; // Found keys not in the allowed list
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return requireAll ? numKeysFound === keys.length : numKeysFound > 0;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* @param objA `Record<string, any>`
|
|
140
|
-
* @param objB `Record<string, any>`
|
|
141
|
-
* @returns **`areEquivalentObjects`** `boolean`
|
|
142
|
-
* - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
|
|
143
|
-
* - `false` `otherwise`.
|
|
144
|
-
*/
|
|
145
|
-
function areEquivalentObjects(objA, objB) {
|
|
146
|
-
if (!objA || typeof objA !== 'object' || !objB || typeof objB !== 'object') {
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
const keysA = Object.keys(objA);
|
|
150
|
-
const keysB = Object.keys(objB);
|
|
151
|
-
if (keysA.length !== keysB.length)
|
|
152
|
-
return false;
|
|
153
|
-
return keysA.every(key => {
|
|
154
|
-
if (!hasKeys(objB, key))
|
|
155
|
-
return false; // key not in both objects
|
|
156
|
-
const valA = objA[key];
|
|
157
|
-
const valB = objB[key];
|
|
158
|
-
if (Array.isArray(valA) && Array.isArray(valB)) {
|
|
159
|
-
return valA.length === valB.length
|
|
160
|
-
&& valA.every((item) => valB.includes(item));
|
|
161
|
-
}
|
|
162
|
-
else if (typeof valA === "object" && valA && typeof valB === "object" && valB) {
|
|
163
|
-
return areEquivalentObjects(valA, valB);
|
|
164
|
-
}
|
|
165
|
-
return (0, index_1.equivalentAlphanumericStrings)(valA, valB);
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
69
|
/**
|
|
169
70
|
* @param value `any`
|
|
170
71
|
* @param requireInteger `boolean` `default = false`
|
|
@@ -209,7 +110,7 @@ function isNumeric(value, requireInteger = false, requireNonNegative = false) {
|
|
|
209
110
|
function isNonEmptyString(value, requireNonSpace = false) {
|
|
210
111
|
return (typeof value === 'string'
|
|
211
112
|
&& (requireNonSpace
|
|
212
|
-
? value.trim() !== ''
|
|
113
|
+
? value.trim() !== '' // Boolean(value.trim())
|
|
213
114
|
: value.length > 0));
|
|
214
115
|
}
|
|
215
116
|
function isPrimitiveValue(value) {
|
|
@@ -456,3 +357,69 @@ function isUndefined(value) {
|
|
|
456
357
|
function isUndefinedOrNull(value) {
|
|
457
358
|
return value === undefined || value === null;
|
|
458
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* @deprecated
|
|
362
|
+
* `fka hasNonTrivialKeys`
|
|
363
|
+
* @note **passing in an array will return `false`.**
|
|
364
|
+
* @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
|
|
365
|
+
* @param obj `any` The object to check.
|
|
366
|
+
* @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
|
|
367
|
+
* @returns **`hasNonTrivialEntries`** `boolean`
|
|
368
|
+
* - **`true`** `if` the `obj` has non-empty keys,
|
|
369
|
+
* - **`false`** `otherwise`
|
|
370
|
+
*/
|
|
371
|
+
function hasNonTrivialEntries(obj, requireAll = false) {
|
|
372
|
+
if (!isObject(obj)) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
return (requireAll
|
|
376
|
+
? Object.values(obj).every(v => !isEmpty(v))
|
|
377
|
+
: Object.values(obj).some(v => !isEmpty(v)));
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* @deprecated
|
|
381
|
+
* @note uses `key in obj` for each element of param `keys`
|
|
382
|
+
* @param obj `T extends Object` the object to check
|
|
383
|
+
* @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
|
|
384
|
+
* @param requireAll `boolean` defaults to `true`
|
|
385
|
+
* - `if` `true`, all keys must be present in the object;
|
|
386
|
+
* - `if` `false`, at least one key must be present
|
|
387
|
+
* @param restrictKeys `boolean` defaults to `false`
|
|
388
|
+
* - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
|
|
389
|
+
* - `if` `false`, the object can keys not included in the `keys` param.
|
|
390
|
+
* @returns **`hasKeys`** `boolean`
|
|
391
|
+
* - **`true`** `if` `obj` is of type 'object' and has the required key(s),
|
|
392
|
+
* - **`false`** `otherwise`
|
|
393
|
+
*/
|
|
394
|
+
function hasKeys(obj, keys, requireAll = true, restrictKeys = false) {
|
|
395
|
+
if (!obj || typeof obj !== 'object') {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
if (keys === null || keys === undefined) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
if (!isNonEmptyArray(keys)) {
|
|
402
|
+
keys = [keys]; // Convert string (assumed to be single key) to array of keys
|
|
403
|
+
}
|
|
404
|
+
let numKeysFound = 0;
|
|
405
|
+
for (const key of keys) {
|
|
406
|
+
if (key in obj) {
|
|
407
|
+
numKeysFound++;
|
|
408
|
+
if (!requireAll && !restrictKeys) {
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
else if (requireAll) { // and a key is not found
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (restrictKeys) {
|
|
417
|
+
// If restrictKeys is true, check that no other keys are present in the object
|
|
418
|
+
const objKeys = Object.keys(obj);
|
|
419
|
+
const extraKeys = objKeys.filter(k => !keys.includes(k));
|
|
420
|
+
if (extraKeys.length > 0) {
|
|
421
|
+
return false; // Found keys not in the allowed list
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return requireAll ? numKeysFound === keys.length : numKeysFound > 0;
|
|
425
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/utils/utilityTypes.ts
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @template Required - Whether the key is required
|
|
6
|
+
* (allows for `K` where `T[K]` can be `undefined` if `false`)
|
|
7
|
+
* - `default = false`
|
|
8
|
+
*/
|
|
9
|
+
export type NumberKeys<T, Required extends boolean = false> = Exclude<{
|
|
10
|
+
[K in keyof T]: Required extends true ? (T[K] extends number ? K : never) : (T[K] extends number | undefined ? K : never);
|
|
11
|
+
}[keyof T], undefined>[];
|
|
12
|
+
/**
|
|
13
|
+
* @template Required - Whether the key is required
|
|
14
|
+
* (allows for `K` where `T[K]` can be `undefined` if `false`)
|
|
15
|
+
* - `default = false`
|
|
16
|
+
*/
|
|
17
|
+
export type ArrayKeys<T, Required extends boolean = false> = Exclude<{
|
|
18
|
+
[K in keyof T]: Required extends true ? (T[K] extends Array<any> ? K : never) : (T[K] extends Array<any> | undefined ? K : never);
|
|
19
|
+
}[keyof T], undefined>[];
|
|
20
|
+
/**
|
|
21
|
+
* @template Required - Whether the key is required
|
|
22
|
+
* (allows for `K` where `T[K]` can be `undefined` if `false`)
|
|
23
|
+
* - `default = false`
|
|
24
|
+
*/
|
|
25
|
+
export type ArrayOfTypeKeys<T, U, Required extends boolean = false> = Exclude<{
|
|
26
|
+
[K in keyof T]: Required extends true ? (T[K] extends Array<U> ? K : never) : (T[K] extends Array<U> | undefined ? K : never);
|
|
27
|
+
}[keyof T], undefined>[];
|
|
28
|
+
/**
|
|
29
|
+
* @template Required - Whether the key is required
|
|
30
|
+
* (allows for `K` where `T[K]` can be `undefined` if `false`)
|
|
31
|
+
* - `default = false`
|
|
32
|
+
*/
|
|
33
|
+
export type StringKeys<T, Required extends boolean = false> = Exclude<{
|
|
34
|
+
[K in keyof T]: Required extends true ? (T[K] extends string ? K : never) : (T[K] extends string | undefined ? K : never);
|
|
35
|
+
}[keyof T], undefined>[];
|
|
36
|
+
/**
|
|
37
|
+
* @template Required - Whether the key is required
|
|
38
|
+
* (allows for `K` where `T[K]` can be `undefined` if `false`)
|
|
39
|
+
* - `default = false`
|
|
40
|
+
*/
|
|
41
|
+
export type PrimitiveKeys<T, Required extends boolean = false> = Exclude<{
|
|
42
|
+
[K in keyof T]: Required extends true ? (T[K] extends string | number | boolean | null ? K : never) : (T[K] extends string | number | boolean | null | undefined ? K : never);
|
|
43
|
+
}[keyof T], undefined>[];
|
|
44
|
+
export type Primitive = string | number | boolean | null | undefined;
|
|
45
|
+
/** Get the union of all values of `T` (like `valueof T`) */
|
|
46
|
+
export type ValueOf<T> = T extends object ? T[keyof T] : T;
|
|
47
|
+
/**
|
|
48
|
+
* Keys of `T` whose values extend a given type `U`
|
|
49
|
+
* @template T - The object type
|
|
50
|
+
* @template U - The type to check each `T[K]` against
|
|
51
|
+
* @template Required - Whether the key is required
|
|
52
|
+
* (allows for `K` where `T[K]` can be `undefined` if `false`)
|
|
53
|
+
* - `default = false`
|
|
54
|
+
* */
|
|
55
|
+
export type KeysOfType<T, U, Required extends boolean = false> = Exclude<{
|
|
56
|
+
[K in keyof T]: Required extends true ? (T[K] extends U ? K : never) : (T[K] extends U | undefined ? K : never);
|
|
57
|
+
}[keyof T], undefined>[];
|
|
58
|
+
/**
|
|
59
|
+
* use for non-strict autocomplete of enum/literal value types
|
|
60
|
+
* @example
|
|
61
|
+
* JobPlatformEnum = { GREENHOUSE: 'GREENHOUSE', WORKDAY: 'WORKDAY' } as const;
|
|
62
|
+
* type JobPlatformEnum = (typeof JobPlatformEnum)[keyof typeof JobPlatformEnum]; // 'GREENHOUSE' | 'WORKDAY'
|
|
63
|
+
* let key: NonStrict<JobPlatformEnum>; // allows any string, but will have the enum values as suggested auto-complete values
|
|
64
|
+
* key = 'hello'; // ok
|
|
65
|
+
* key = 9; // Error: Type '9' is not assignable to type 'NonStrict<JobPlatformEnum>'
|
|
66
|
+
* */
|
|
67
|
+
export type NonStrict<T extends string | number> = T | (T extends string ? (string & {}) : (number & {}));
|